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

public void test(){ String x; List 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或之前的工作中确实是一件很复杂的事情。

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

 public void test() { String[] x = new String[1]; List list = Arrays.asList("a", "b", "c", "d"); list.forEach(n -> { if (n.equals("d")) x[0] = "match the value"; }); } 

但是,准备好让团队中的function性纯粹主义者挨打。 然而,更好的是使用更具function性的方法( 类似于Sleiman的方法 ):

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

除了已经提供的惯用示例之外,另一个hack将是使用AtomicReference,但我只推荐它,如果你确实需要’forEach’并且更喜欢比真正function变体更可读的东西:

 public void test(){ AtomicReference x = new AtomicReference<>(); List list= Arrays.asList("a", "b", "c", "d"); list.forEach(n->{ if(n.equals("d")) x.set("match the value"); }); } 
  1. 不,你做不到。 (虽然你应该自己尝试过)
  2. 因为匿名内部类和lambda表达式中使用的变量必须是effectively final
  3. 你可以使用filtermap更简洁地实现同样的目的。

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

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

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

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