Java8 Stream编译器消息 - 局部变量必须是最终的或有效的最终

时间:2016-01-13 21:17:41

标签: java eclipse java-stream

我有点问题。当我写这个for循环时,f.getAnswerScore()。get(i)....中的变量i带有错误消息的下划线: - 我在封闭范围内定义的局部变量必须是最终的或      有效地最后。这与流有关吗?也许流不能用于循环?

for (int i = 0; i < 10; i++) {
    correct = active.stream()
        .filter(f -> f.getAnswerScore().get(i).getStatus().equals(AnswerStatus.ANSWERED_CORRECT))
        .count();
}

2 个答案:

答案 0 :(得分:6)

与匿名内部类一样,lambda表达式只能访问局部变量final或“有效最终”(Java 8或更高版本;不是final,但一旦分配就不会更改)。

这由the JLS, Section 15.27.2

涵盖
  

使用但未在lambda表达式中声明的任何局部变量,形式参数或异常参数必须声明为final或者实际上是最终的(§4.12.4),否则会发生编译时错误尝试使用。

     

在lambda体中使用但未在lambda体中声明的任何局部变量必须明确赋值(§16(Definite Assignment)),否则会发生编译时错误。

     

关于变量使用的类似规则适用于内部类的主体(第8.1.3节)。对有效最终变量的限制禁止访问动态变化的局部变量,其捕获可能会引入并发问题。与最终限制相比,它减少了程序员的文书负担。

声明final变量等于i并使用它。

for(int i = 0; i< 10; i++){
     final int j = i;
     correct = active
         .stream()
         .filter(f-> f.getAnswerScore().get(j).getStatus().equals(AnswerStatus.ANSWERED_CORRECT))
         .count();
}

答案 1 :(得分:2)

rgettman的答案是一种解决方法。你永远不会在循环中使用correct,那么为什么还要为它分配10次而不是仅使用i = 9运行一次呢?

答案是你可能正在做一些你没有向我们展示的correct的其他内容,而对这个问题的彻底回答可能需要我们知道那是什么。因为你编写的C风格的循环实际上是你试图解决的问题的最佳/最优雅的解决方案。

一种可能性是收集另一个流中的所有correct值:

IntStream.range(0, 10).map(i ->
  active
  .stream()
  .filter(f ->
     f.getAnswerScore()
      .get(i)
      .getStatus()
      .equals(AnswerStatus.ANSWERED_CORRECT)
  )
  .count()
)

当然,您可能想完全做其他事情,我们无法知道。