在forEach
中修改局部变量会导致编译错误:
典型的
int ordinal = 0;
for (Example s : list) {
s.setOrdinal(ordinal);
ordinal++;
}
和Lambda
int ordinal = 0;
list.forEach(s -> {
s.setOrdinal(ordinal);
ordinal++;
});
你知道怎么解决这个问题吗?
如果您只需要将值从外部传递到lambda,而不需要将其传递出去,您可以使用常规的匿名类来代替lambda:
list.forEach(new Consumer<Example>() {
int ordinal = 0;
public void accept(Example s) {
s.setOrdinal(ordinal);
ordinal++;
}
});
这相当接近于XY问题。也就是说,被问到的问题本质上是如何从lambda突变捕获的局部变量。但是手头的实际任务是如何给列表中的元素编号。
根据我的经验,80%以上的情况下,有一个问题是如何从lambda中变异捕获的局部,有更好的方法继续。通常这涉及到减少,但在这种情况下,在列表索引上运行流的技术非常适用:
IntStream.range(0, list.size())
.forEach(i -> list.get(i).setOrdinal(i));
任何包装都是好的。
对于Java10,使用此构造,因为它非常容易设置:
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]++);
});
注意:如果使用并行流,请非常小心。您可能不会得到预期的结果。像斯图尔特这样的其他解决方案可能更适合这些情况。
当然,这对于int
以外的类型仍然有效。
例如,对于Java 10:
var wrapper = new Object(){ String value = ""; };
list.forEach(s->{
wrapper.value += "blah";
});
或者,如果您一直使用Java8或Java9,请使用与上面相同的构造,但是使用原子引用
。。。
AtomicReference<String> value = new AtomicReference<>("");
list.forEach(s -> {
value.set(value.get() + s);
});
... 或数组:
String[] value = { "" };
list.forEach(s-> {
value[0] += s;
});
问题内容: 修改中的局部变量会产生编译错误: 正常 与Lambda 任何想法如何解决这个问题? 问题答案: 任何一种包装纸都是好的。 对于 Java 8+ ,请使用: …或数组: 使用 Java 10+ : 注意: 如果使用并行流, 请 非常小心。您可能无法获得预期的结果。诸如Stuart的其他解决方案可能更适合这些情况。 对于除 当然,这对于之外的其他类型仍然有效。您只需要将包装类型更改为或该类
假设我有一个和一个。我想将每个变压器应用于列表中的每个字符串。 使用Java8 lambdas,我可以这样做: 但我想做更像这样的事情,但这会导致编译时错误: 我刚刚开始玩lambdas,所以也许我只是没有正确的语法。
问题内容: 为什么我需要声明一个方法,好像我在方法中定义的需要使用它一样? 范例: } 为什么String 需要是最终常量?它如何影响? 问题答案: 答案是两者在不同的范围内。因此该变量可以在内部类访问它之前更改。将其最终确定可以防止这种情况。
为什么<code>test
但是,如果我在内部类中声明了一个同名的variabe呢?有什么方法可以显式引用外部变量吗? 顺便说一句,这和这个问题不同,因为它考虑的是局部堆栈变量。