在java8中,如何在lambdas foreach块中设置全局值?

时间:2015-09-11 11:06:23

标签: java foreach lambda java-8

    public void test(){
       String x;
       List<String> list=Arrays.asList("a","b","c","d");

       list.forEach(n->{
          if(n.equals("d"))
            x="match the value";
       });
    }

1.像上面的代码一样,我想在foreach块旁边设置一个变量的值,它可以工作吗?

2.为什么?

3.而foreach迭代器是有序的还是无序的?

4.我认为lamdas foreach块对于迭代器来说很酷且很简单,但这实际上是一件很复杂的事情,而不是java 7或之前的相同工作。

4 个答案:

答案 0 :(得分:21)

当然,你可以通过一个技巧“使外部价值变得可变”:

public void test() {
    List<String> list = Arrays.asList("a", "b", "c", "d");
    String x = list.stream()
                   .filter("d"::equals)
                   .findAny()
                   .map(v -> "match the value")
                   .orElse(null);
}

准备好让团队中的功能性纯粹主义者挨打。然而,更好的是使用更具功能性的方法(similar to Sleiman's approach):

{{1}}

答案 1 :(得分:8)

  1. 不,你不能这样做。 (虽然你应该亲自试过)
  2. 因为匿名内部类和lambda表达式中使用的变量必须是effectively final
  3. 您可以使用filtermap更简洁地实现相同目标。

    Optional<String> d = list.stream()
                             .filter(c -> c.equals("d"))
                             .findFirst()
                             .map(c -> "match the value");
    

答案 2 :(得分:8)

除了已经提供的惯用示例之外,另一个黑客将是使用AtomicReference,但我只推荐它,如果你确实需要&#39; forEach&#39;并且更喜欢比真实功能变体更具可读性的东西:

public void test(){
    AtomicReference<String> x = new AtomicReference<>();
    List<String> list= Arrays.asList("a", "b", "c", "d");

    list.forEach(n->{
        if(n.equals("d"))
            x.set("match the value");
    });
}

答案 3 :(得分:6)

正如已经解释的那样,你不能从lambda体(以及匿名类体)修改外部方法的局部变量。我的建议是,在完全没必要的情况下,不要尝试使用lambdas。你的问题可以这样解决:

public void test(){
   String x;
   List<String> list = Arrays.asList("a","b","c","d");
   if(list.contains("d"))
       x = "match the value";
}

一般情况下,lambdas是功能编程的朋友,你很少有可变变量(每个变量只分配一次)。如果你使用lambdas,但继续以命令式的方式思考,你总会遇到这样的问题。