Pat*_*tan 86 java lambda java-8
修改局部变量forEach会产生编译错误:
正常
    int ordinal = 0;
    for (Example s : list) {
        s.setOrdinal(ordinal);
        ordinal++;
    }
随着Lambda
    int ordinal = 0;
    list.forEach(s -> {
        s.setOrdinal(ordinal);
        ordinal++;
    });
知道如何解决这个问题吗?
Oli*_*ire 135
使用Java 8+:
AtomicInteger ordinal = new AtomicInteger(0);
list.forEach(s -> {
  s.setOrdinal(ordinal.getAndIncrement());
});
使用Java 10+:
int[] ordinal = { 0 };
list.forEach(s -> {
  s.setOrdinal(ordinal[0]++);
});
Stu*_*rks 12
这非常接近XY问题.也就是说,被问到的问题本质上是如何从lambda变异捕获的局部变量.但是手头的实际任务是如何对列表的元素进行编号.
根据我的经验,在80%的时间内存在如何从lambda内变异捕获的局部的问题,有更好的方法可以继续.通常这涉及到减少,但在这种情况下,在列表索引上运行流的技术很适用:
IntStream.range(0, list.size())
         .forEach(i -> list.get(i).setOrdinal(i));
new*_*cct 11
如果你只需要将值从外部传递给lambda,而不是将它取出,你可以使用常规的匿名类而不是lambda来实现:
list.forEach(new Consumer<Example>() {
    int ordinal = 0;
    public void accept(Example s) {
        s.setOrdinal(ordinal);
        ordinal++;
    }
});
由于来自lamda外部的已使用变量必须(隐式)最终,您必须使用类似的东西AtomicInteger或编写自己的数据结构.
请参阅 https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#accessing-local-variables.
另一种方法AtomicInteger是使用数组(或任何其他能够存储值的对象):
final int ordinal[] = new int[] { 0 };
list.forEach ( s -> s.setOrdinal ( ordinal[ 0 ]++ ) );
但是请参阅Stuart 的回答:可能有更好的方法来处理您的案例。