【问题标题】:Is it possible to access outer variables inside JAVA8 stream filter?是否可以访问 JAVA8 流过滤器中的外部变量?
【发布时间】:2018-02-21 05:42:00
【问题描述】:

我被困在一个场景中,我想根据条件过滤字符串 ArrayList 中 20% 的元素。我搜索了 Stream.filter 并且有一些东西阻止我使用它。 我有一个数组列表包含字符串“一、二、三、四”和一个匹配变量 String match = “e”;假设我已经将列表作为 myList,我想做类似的事情,

public List<String> filterArrayList(List<String> myList, String match){
    List<String> filtered_result=myList.stream().filter(elem -> {
    if(elem.indexOf(match)!=-1){
      return true;
    }
    return false;
  }).collect(Collectors.toList());
  return filtered_result; 
}
filterArrayList(somelist,"e");

但这似乎不起作用,因为我无法访问过滤器内的匹配变量。它只是将列表返回为“e”,这是变量匹配的值。 过滤结果 = ["e"]

我也试过这样做,

List<String> filtered_result=myList.stream().filter(elem -> elem.contains(match)).collect(Collectors.toList());

这也返回相同的结果。有什么办法可以在这里解决吗?

PS:我不想仅仅为此目的创建一个 POJO 类,我也不能创建一个 final 变量,因为列表是这个方法的一个参数,这是我跨类的许多方法。

编辑:映射到方法的匹配变量可能因方法而异,并且不能保持不变。

【问题讨论】:

  • 我不明白你的编辑,但最终参数...public List&lt;String&gt; filterArrayList(final List&lt;String&gt; myList, final String match),不影响对象的外部值。
  • 只需将String match 参数标记为final
  • 您的问题描述毫无意义。首先,您说“我无法访问过滤器内的匹配变量”,然后您说“它只是将列表返回为“e”,这是变量匹配的值”。这两个陈述之间的联系在哪里?除此之外,您将结果存储在一个名为 filtered_result 的变量中,但指的是一个名为 filtered_list 的变量,它不会出现在您显示的代码中的其他任何地方。也许,这就是整个问题,谁知道呢。
  • @cricket_007 原始版本甚至没有围绕代码的方法/函数声明,仍然不一致地引用filtered_resultfiltered_list,更重要的是,包含这些关于根本无法进行操作,并且会得到意想不到的“结果”。
  • @MikeRoss 不要因为你无法提出一个可以理解的问题而责备他人。您接受了一个答案,其中包含与您在问题中发布的完全相同的代码,仅包含细微差别(除了没有错字),那么您的问题是什么?您的自相矛盾的问题描述,“无法访问过滤器内的匹配变量”或“它只是将列表返回为“e””,都不适用于您的代码。错字只是一个额外的矛盾。正如前面的 cmets 中明确指出的那样,not 以错字为中心。

标签: java lambda collections filter java-stream


【解决方案1】:

为了展示这种方法的工作原理,这里是那个方法

public static List<String> matchFilter(List<String> list, final String match) {
    return list.stream()
        .filter(e -> e.indexOf(match) != -1)
        .collect(Collectors.toList());
}

public static void main(String[] args) {
    String match = "e";
    List<String> myList = Arrays.asList("one", "two", "three", "four");
    System.out.println(matchFilter(myList, match)); // [one, three]
}

您应该在应用流过滤之前尝试打印出myList 的内容

关于额外的 cmets。

我不想仅仅为此目的创建一个 POJO 类

您不需要,但这是一个实用方法,因此它可以在某个随机类中作为static 方法关闭,以便在任何地方使用。

我也不能创建最终变量,因为列表是作为此方法的参数出现的,这是我跨类的许多方法

如这段代码所示,final String match 是一个有效参数。它不需要是最终的,但我表明它不会影响任何事情。该列表也可能是最终的,但这里没有理由。将任何变量设为最终变量仅意味着您不能重新分配它。 您仍然可以向final List 添加和删除值

注意:这是过滤 50%,而不是 20%(这在 4 个元素的列表中是不可能的)

【讨论】:

  • “列表也可以是最终的,但这里没有理由”——这同样适用于match 参数;在该参数变量中存在 final 修饰符对 OP 所做的没有任何影响。实际的主要区别在于您既不是指filtered_result 也不是filtered_list,避免了这种不一致。最后,没有人知道OP的实际问题是什么(尤其是神秘的filtered_list = ["e"]“结果”)......
【解决方案2】:

要在 lambda 中使用变量 match,它必须实际上是 final(它在此处和您的示例中)。您的第一个示例在这里有效,但不优雅;问题一定在于你如何获得myList - 而不是if 只是return elem.indexOf(match) != -1; - 可以在这个mcve中进一步细化,

public static void main(String[] args) {
    String match = "e";
    List<String> myList = Arrays.asList("one", "two", "three", "four");
    List<String> filtered_result = myList.stream() //
            .filter(e -> e.indexOf(match) != -1) //
            .collect(Collectors.toList());
    System.out.println(filtered_result);
}

哪些输出

[one, three]

【讨论】:

  • 感谢您的解释,但很抱歉我忘了提及,匹配字符串也作为此方法的参数。我正在寻找一种使用动态条件进行动态过滤的解决方案。
  • @MikeRoss match 的范围应该无关紧要,无论是参数、局部变量还是字段。
  • @cricket_007 match 的值从方法更改,而不是固定值。该值存储在 db 中,并且基于 db 中存储的任何值,需要调用它。
  • @MikeRoss 所以?如果您认为这是一个问题,请在问题中将其作为一个完整的示例来展示。见minimal reproducible example
【解决方案3】:

您是否要根据列表中的“匹配”变量值进行过滤?如果是,那么下面的代码应该可以帮助您

        List<String> lines = Arrays.asList("one", "two", "three");
    String match = "e";
    List<String> result = lines.stream()               
            .filter(line -> !match.equals(line))    
            .collect(Collectors.toList());             
    result.forEach(System.out::println); 

【讨论】:

    猜你喜欢
    • 2020-01-13
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-21
    • 1970-01-01
    • 2018-11-18
    相关资源
    最近更新 更多