在java8中,如何在lambdas foreach块中设置全局值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32521972/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In java8, how to set the global value in the lambdas foreach block?
提问by MarsYoung
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.Like the code above, I want to set the value of a variable beside the foreach block, can it works?
1.像上面的代码,我想在foreach块旁边设置一个变量的值,可以吗?
2.And why?
2.为什么?
3.And the foreach iterator is in order or disorder?
3.foreach迭代器是有序还是无序?
4.I think the lamdas foreach block is cool and simple for iterator,but this is really a complicated thing to do rather than the same work in java 7 or before.
4.我认为 lamdas foreach 块对于迭代器来说既酷又简单,但这确实是一件复杂的事情,而不是在 java 7 或更早版本中进行相同的工作。
采纳答案by Lukas Eder
You could, of course, "make the outer value mutable" via a trick:
当然,您可以通过一个技巧“使外部值可变”:
public void test() {
String[] x = new String[1];
List<String> list = Arrays.asList("a", "b", "c", "d");
list.forEach(n -> {
if (n.equals("d"))
x[0] = "match the value";
});
}
Get ready for a beating by the functional purist on the team, though. Much nicer, however, is to use a more functional approach (similar to Sleiman's approach):
不过,准备好被团队中的功能纯粹主义者殴打。然而,更好的是使用更实用的方法(类似于 Sleiman 的方法):
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);
}
回答by Sleiman Jneidi
- No you can't do it. (Although you should have tried it yourself)
- Because variables used within anonymous inner classes and lambda expression have to be
effectively final
. you can achieve the same more concisely using
filter
andmap
.Optional<String> d = list.stream() .filter(c -> c.equals("d")) .findFirst() .map(c -> "match the value");
- 不,你不能这样做。(虽然你应该自己尝试过)
- 因为匿名内部类和 lambda 表达式中使用的变量必须是
effectively final
. 您可以使用
filter
and更简洁地实现相同的效果map
。Optional<String> d = list.stream() .filter(c -> c.equals("d")) .findFirst() .map(c -> "match the value");
回答by Tagir Valeev
As it's already explained, you cannot modify the local variable of the outer method from the lambda body (as well as from the anonymous class body). My advice is don't try to use lambdas when they are completely unnecessary. Your problem can be solved like this:
正如已经解释过的,您不能从 lambda 主体(以及匿名类主体)修改外部方法的局部变量。我的建议是不要在完全不必要时尝试使用 lambda。你的问题可以这样解决:
public void test(){
String x;
List<String> list = Arrays.asList("a","b","c","d");
if(list.contains("d"))
x = "match the value";
}
In general lambdas are friends with functional programming where you rarely have mutable variables (every variable is assigned only once). If you use lambdas, but continue thinking in imperative style you will always have such problems.
一般来说,lambda 是函数式编程的朋友,在那里你很少有可变变量(每个变量只分配一次)。如果您使用 lambdas,但继续以命令式风格思考,您将始终遇到此类问题。
回答by Andrii Rubtsov
In addition to already provided idiomatic examples, another hack would be to use AtomicReference, but I would only recommend it if you do need 'forEach' and prefer something more readable than true-functional variant:
除了已经提供的惯用示例之外,另一个技巧是使用 AtomicReference,但我只会在您确实需要 'forEach' 并且更喜欢比真正功能变体更具可读性的情况下推荐它:
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");
});
}