鉴于lambda在for循环中的这种情况,我希望计数器i能够最终成为最终的。
编译器抱怨说我不是最终的,所以我不得不使用i2。
for (int i = 0; i < x.getBooks().size(); i++){
//The compiler needs i to be effectively final.
int i2 = i;
List<Book> books = bookstore.stream()
.filter(c -> c.getAuthors().get(i2).equals("xxx"))
.collect(Collectors.toList());
}
所以问题是为什么我没有在for循环范围内有效地进行最终决定,这是最简单的解决方法。
答案 0 :(得分:6)
TLDR:i
不是final
,因为它在i++
循环的每次迭代时被修改(for
)。
为什么我没有在for循环范围内有效最终?
for
循环语法是
for (initialization; termination; increment) {
statement(s)
}
每次迭代循环后都会调用increment表达式。在您的情况下,增量为{{1}},因此在每次迭代后都会修改i++
。
您可以通过声明i
final:
i
您将收到此编译错误:
for (final int i = 0; i < x.getBooks().size(); i++) {
}
这是最简单的解决方法吗?
在The final local variable i cannot be assigned.
It must be blank and not using a compound assignment
循环的情况下:是。
但您可以使用@dkatzel或for
所示的while
循环:
foreach
答案 1 :(得分:5)
正如其他答案所提到的,effectively final
意味着,变量只能分配一次而不会被重新分配。在for循环中不是这种情况。 effectively final
存在,因为否则开发人员必须将变量显式标记为final
才能在lambda中使用它。
但是,我回答的原因是一个解决方案,编写代码而不重复i
:
IntStream.range (0, x.getBooks().size()).forEach (i -> {
List<Book> books = bookstore.stream()
.filter(c -> c.getAuthors().get(i).equals("xxx"))
.collect(Collectors.toList());
});
答案 2 :(得分:1)
在基本for语句(第14.14.1节)的
ForInit
部分中声明的局部变量的范围包括以下所有内容:
- 自己的初始化程序
- for语句的
ForInit
部分右侧的任何其他声明符- for for statement的
Expression
和ForUpdate
部分- 包含的声明
局部变量或方法,构造函数,lambda或异常 参数实际上是最终的如果它没有被声明为final,那么它就是 永远不会作为赋值运算符的左手操作数出现 (§15.26)或作为前缀或后缀增量或的操作数 递减运算符
您的i
变量作为后缀增量运算符
i++
因此,它不是最终的,并且不能被lambda捕获。
答案 3 :(得分:0)
你必须记住for
循环实际上相当于:
int i=0;
while(i < x.getBooks().size()){
//execute your block
i++;
}
因此,您看到i
仅被声明一次并因此更新,因此无法最终确定。
x.getBooks()
和Book.getAuthors()
之间的关系有点不清楚,但显然它们的大小相同?如果没有更好的理解,我不认为我可以告诉你更好的方法。但这也可能表明你的设计很差。