Dan*_*Dan 5 java lambda for-loop java-8
鉴于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());
}
Run Code Online (Sandbox Code Playgroud)
所以问题是为什么我没有在for循环范围内有效地完成最终,这是最简单的解决方法.
TLDR:i不是final因为它i++在循环的每次迭代中都被修改()for.
为什么我没有在for循环范围内有效最终?
该for循环语法是
for (initialization; termination; increment) {
statement(s)
}
Run Code Online (Sandbox Code Playgroud)
每次迭代循环后都会调用increment表达式.在你的情况下,增量i++所以i在每次迭代后修改.
您可以通过宣布i最终确认:
for (final int i = 0; i < x.getBooks().size(); i++) {
}
Run Code Online (Sandbox Code Playgroud)
你会得到这个编译错误:
The final local variable i cannot be assigned.
It must be blank and not using a compound assignment
Run Code Online (Sandbox Code Playgroud)
这是最简单的解决方法吗?
在for循环的情况下:是的.
但你可以使用@dkatzel或a while所示的循环:foreach
int i = 0;
for (Book book: x.getBooks()) {
int i2 = i;
...
i++;
}
Run Code Online (Sandbox Code Playgroud)
正如其他答案所提到的那样,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());
});
Run Code Online (Sandbox Code Playgroud)
你必须记住,for循环实际上相当于:
int i=0;
while(i < x.getBooks().size()){
//execute your block
i++;
}
Run Code Online (Sandbox Code Playgroud)
所以你会看到它只i声明一次并更新,因此实际上不是最终的。
x.getBooks()和之间的关系有点不清楚,Book.getAuthors()但显然它们的大小相同?如果没有更好的理解,我认为我无法向您展示更好的方法。但这也可能表明你的设计很糟糕。