我有以下课程:
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);
答案 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}}