Java 8 Lambda变量范围

cod*_*erz 6 java lambda java-8

我有2个代码示例:

int[] idx = { 0 };
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("def");
list.add("ghi");
list.stream().forEach(item -> {
    System.out.println(idx[0] + ": " + item);
    idx[0]++;
});
Run Code Online (Sandbox Code Playgroud)

好好工作.

虽然此代码有编译错误:

int idx = 0;
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("def");
list.add("ghi");
list.stream().forEach(item -> {
    System.out.println(idx + ": " + item);
    idx++;
});
Run Code Online (Sandbox Code Playgroud)

他说:

Local variable idx defined in an enclosing scope must be final or effectively final.
Run Code Online (Sandbox Code Playgroud)

唯一的区别是idxint或int数组.

根本原因是什么?

das*_*ght 7

根本原因是JVM缺少构造对局部变量的引用的机制,这是idx++idx一个int或一些不可变类型(例如String)时需要执行的操作.既然你试图改变idx,只是捕捉它的价值是不够的; Java需要捕获引用,然后通过它修改值.

使用数组时Java没有此问题,因为数组是引用对象.Java可以捕获永不改变的数组引用,并使用该不变的引用来改变对象.数组本身提供了必要的间接级别,因为Java数组是可变的.

我试过make idxstatic并将它移到main方法之外,工作正常.但为什么?

因为在这种情况下,lambda不需要捕获对基本类型的局部变量的引用.对静态变量的引用很容易获得,因此捕获它没有问题.

类似地,如果您创建idx成员变量,代码将起作用,并在实例方法中使用lambda.这将使lambda idx通过this对象修改字段,可以自由捕获.

  • Java 通常缺少指向局部变量的指针。不管变量的类型是不是原始类型,局部变量都不能改变。这是一件好事,因为局部变量有固定的生命周期,并且有一个可以持续更长时间的指向它们的指针,这正是 Java 所防止的。 (2认同)