Java lambda - for for循环计数器不是最终的

时间:2014-07-22 17:10:01

标签: java for-loop lambda 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());
}

所以问题是为什么我没有在for循环范围内有效地进行最终决定,这是最简单的解决方法。

4 个答案:

答案 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 循环的情况下:是。

但您可以使用@dkatzelfor所示的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)

来自Java Language Specification

  

在基本for语句(第14.14.1节)的ForInit部分中声明的局部变量的范围包括以下所有内容:

     
      
  • 自己的初始化程序
  •   
  • for语句的ForInit部分右侧的任何其他声明符
  •   
  • for for statement的ExpressionForUpdate部分
  •   
  • 包含的声明
  •   

关于effectively final

  

局部变量或方法,构造函数,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()之间的关系有点不清楚,但显然它们的大小相同?如果没有更好的理解,我不认为我可以告诉你更好的方法。但这也可能表明你的设计很差。