为什么lambda强迫我使用单个元素数组而不是最终对象?

我有以下课程:

public class Item{ private String name; //setter getter } 

和物品的集合。 我想得到Collection中最后一项的名字。 要做到这一点,我只需迭代所有集合并使用最后。 问题是我不知道为什么它迫使我使用一个元素String数组。

为什么我必须使用:

 String[] lastName = {""}; items.forEach(item -> lastName[0] = item.getName()); System.out.println(lastname[0]); 

代替:

 final String lastName; items.forEach(item -> lastName = item.getName()); System.out.println(lastname); 

你不能将lastName String ,因为在lambda(或匿名内部类)中使用的局部变量必须(有效)为final ( 参见此处 ),即你不能在.forEach中每次执行lambda时覆盖它循环。 使用数组(或其他一些包装器对象)时,不要为该变量赋值,而只是更改它的某些方面,因此它可以是最终的。

或者,您可以使用reduce跳到最后一项:

 String lastName = items.stream().reduce((a, b) -> b).get().getName(); 

或者,如评论中所述, skipn-1个元素并在此之后取第一个元素:

 String last = items.stream().skip(items.size() - 1).findFirst().get().getName(); 

final实际上意味着你必须分配一次(并且只有一次,由编译时分析保证)。 例如,以下代码无效:

 final String lastName; List items = new ArrayList(); items.add(new Item("only one element")); for (Item item:items) lastName = item.getName(); 

在您的第二个lambda表达式中,使用者分配给lastName ,该lastName已声明为final

 final String lastName; items.forEach(item -> lastName = item.getName()); 

因为lambda表达式中引用的变量必须是有效的final (即final关键字可以添加到其定义中),所以删除lastName声明中的final关键字没有帮助:这里lastName实际上是final,并且消费者指定到一个有效的最终变量。

 String lastName; items.forEach(item -> lastName = item.getName()); 

另一方面,在你的第一个表达式中, 有效的final变量是lastName ,它是一个数组。 然后你可以这样做:

  String[] lastName = {""}; items.forEach(item -> lastName[0] = item.getName()); 

因为在这里你没有分配有效的最终变量,只是修改它的元素(记住什么是常量是引用,而不是它的值),因为在下面的例子中也是如此:

  final String[] lastName = new String[1]; lastName[0]="foo";