在forEach
中修改局部变量会出现编译错误:
正常
int ordinal = 0;
for (Example s : list) {
s.setOrdinal(ordinal);
ordinal++;
}
采用Lambda的
int ordinal = 0;
list.forEach(s -> {
s.setOrdinal(ordinal);
ordinal++;
});
你知道怎么解决这个问题吗?
发布于 2015-05-04 17:37:03
使用包装器
任何类型的包装器都是好的。
对于Java 10+,使用这个结构是因为它很容易设置:
var wrapper = new Object(){ int ordinal = 0; };
list.forEach(s -> {
s.setOrdinal(wrapper.ordinal++);
});
对于Java 8+,请使用AtomicInteger
AtomicInteger ordinal = new AtomicInteger(0);
list.forEach(s -> {
s.setOrdinal(ordinal.getAndIncrement());
});
..。或数组:
int[] ordinal = { 0 };
list.forEach(s -> {
s.setOrdinal(ordinal[0]++);
});
注意:如果您使用并行流,要非常小心。您可能最终得不到预期的结果。像Stuart's这样的其他解决方案可能更适合这些情况。
用于int
以外的类型
当然,这对于int
以外的类型仍然有效。
例如,使用Java 10+
var wrapper = new Object(){ String value = ""; };
list.forEach(s->{
wrapper.value += "blah";
});
或者,如果您坚持使用Java8或9,可以使用与上面相同的结构,但使用的是AtomicReference
...
AtomicReference<String> value = new AtomicReference<>("");
list.forEach(s -> {
value.set(value.get() + s);
});
..。或数组:
String[] value = { "" };
list.forEach(s-> {
value[0] += s;
});
发布于 2015-05-05 04:18:37
这相当接近于XY problem。也就是说,所问的问题本质上是如何从lambda中变异捕获的局部变量。但手头的实际任务是如何对列表中的元素进行编号。
根据我的经验,超过80%的时间都存在如何从lambda中变异捕获的本地对象的问题,有一种更好的方法来处理。通常这涉及到缩减,但在这种情况下,在列表索引上运行流的技术适用得很好:
IntStream.range(0, list.size())
.forEach(i -> list.get(i).setOrdinal(i));
发布于 2015-05-05 04:29:17
如果您只需要将值从外部传入lambda,而不是将其取出,则可以使用常规匿名类而不是lambda来完成此操作:
list.forEach(new Consumer<Example>() {
int ordinal = 0;
public void accept(Example s) {
s.setOrdinal(ordinal);
ordinal++;
}
});
https://stackoverflow.com/questions/30026824
复制相似问题