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

时间:2015-03-10 10:41:39

标签: java lambda java-8

我有以下课程:

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);

2 个答案:

答案 0 :(得分:13)

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

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

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

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

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

答案 1 :(得分:4)

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

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

在您的第二个lambda表达式中,消费者分配给lastName,该final已声明为final String lastName; items.forEach(item -> lastName = item.getName());

final

由于lambda表达式中引用的变量必须为effectively final(即可以将final关键字添加到其定义中),因此删除lastName声明中的lastName关键字1}}没有帮助:这里String lastName; items.forEach(item -> lastName = item.getName()); 实际上是最终的,消费者分配给一个有效的最终变量。

lastName

另一方面,在您的第一个表达式中,有效的最终变量是 String[] lastName = {""}; items.forEach(item -> lastName[0] = item.getName()); ,这是一个数组。然后你可以这样做:

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

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

{{1}}