当我将lambda表达式作为参数传递它可以访问此范围内的其他变量时,怎么可能?

Doz*_*Doz 3 java arrays lambda interface functional-interface

public class ArraysDemo {

    public static void main(String[] args) {

          int[] a = {0, 2, 4, 6, 8};
          int[] b = {10, 12, 14, 16, 18};
          Arrays.setAll(a, i -> b[i]+1);
          System.out.println(Arrays.toString(a));
    }  
}
Run Code Online (Sandbox Code Playgroud)

输出: [11, 13, 15, 17, 19]

setAll()使用的函数的来源如下:

public static void setAll(int[] array, IntUnaryOperator generator) {
        Objects.requireNonNull(generator);
        for (int i = 0; i < array.length; i++)
            array[i] = generator.applyAsInt(i);
}
Run Code Online (Sandbox Code Playgroud)

IntUnaryOperator 是一个功能界面,这是其来源的一部分:

public interface IntUnaryOperator {
    int applyAsInt(int operand);
    // rest methods are omitted
}
Run Code Online (Sandbox Code Playgroud)

如果我错了,请纠正我,但我对Java中lambda表达式的理解是,当我将lambda表达式作为参数传递给setAll()方法时,IntUnaryOperator创建并调用实现接口的匿名类的对象generator.lambda表达式本质上是该applyAsInt()方法的一个实现,所以我相信它会转化为:

int applyAsInt(int operand){
    return b[operand]+1;
}
Run Code Online (Sandbox Code Playgroud)

我有意义的是它可以访问,operand因为它作为参数传递array[i] = generator.applyAsInt(i);但是,我不知道它可以如何操作b- 它不作为参数传递,所以如何可以引用它?我错过了什么?

And*_*res 5

原因是它b实际上是最终的.

可以在lambda的主体中使用和更改实例和静态变量而不受限制.然而,局部变量的使用受到更多限制:除非它们实际上是最终的,否则不允许捕获局部变量,这是Java 8中引入的概念.非正式地,如果局部变量的初始值从未改变(包括内部变量),则局部变量实际上是最终的. lambda表达式的主体) - 换句话说,声明最终不会导致编译失败.有效终结的概念并没有向Java引入任何新的语义; 它只是一种稍微简单的定义最终变量的方式.

来自http://www.lambdafaq.org/can-lambda-expressions-use-variables-from-their-environment/