内部lambda参考外部lambda变量

时间:2017-04-13 15:48:30

标签: java lambda reference functional-programming java-8

有一个外部lambda包含内部lambda whis试图引用外部lambda中的var,它怎么可能? 我试着理解这个表达式在编译时会是什么样子。

public static void main(String[] args) {
    ExecutorService service = Executors.newScheduledThreadPool(10);
    DoubleStream.of(3.14159, 2.71828)
            .forEach(c -> service.submit(
                    () -> System.out.println(c)));

我猜是会编译成这样的东西:

new Consumer<Double>() {
    @Override
    public void accept(Double aDouble) {
        new Runnable() {
            @Override
            public void run() {
                System.out.println(aDouble);
            }
        };
    }
};

我是对的吗?

2 个答案:

答案 0 :(得分:3)

编译后的代码更接近

class MyClass {
    public static void main(String[] args) {
        ExecutorService service = Executors.newScheduledThreadPool(10);
        DoubleStream.of(3.14159, 2.71828)
            .forEach(new DoubleConsumer() {
            @Override public void accept(double value) {
                lambda1(service, value);
            }
        });
    }
    private static void lambda1(ExecutorService service, double c) {
        service.submit(new Runnable() {
            @Override public void run() {
                lambda2(c);
            }
        });
    }
    private static void lambda2(double c) {
        System.out.println(c);
    }
}

不再有任何筑巢。实际上,编译后的代码不包含匿名内部类。将会生成运行时的类来完成接口DoubleConsumerRunnable,这将调用这些合成方法来保存lambda表达式的主体。

但是这个草图已经足以证明“外部lambda”和“内部lambda”之间没有真正的技术差异。嵌套存在于源代码级别,允许您简明扼要地表达您的意图。

另请参阅“How will Java lambda functions be compiled?

答案 1 :(得分:2)

最里面的lambda可以从其封闭的lambda访问c,因为ceffectively final,因为没有任何东西可以分配给它。来自规范的链接部分:

  
      
  • 处理方法,构造函数,lambda或异常参数(§8.4.1,§8.8.1,§9.4,§15.27.1,§14.20),以确定它是否真正是最终的,如声明符具有初始值设定项的局部变量。
  •   

然后上面

  
      
  • 如果满足以下所有条件,则声明符具有初始值设定项(第14.4.2节)的局部变量实际上是最终的:

         
        
    • 未宣布为最终版。

    •   
    • 它永远不会出现在赋值表达式(第15.26节)的左侧。 (请注意,包含初始值设定项的局部变量声明符不是赋值表达式。)

    •   
    • 它永远不会作为前缀或后缀增量或减量运算符的操作数出现(§15.14,§15.15)。

    •   
  •   

即使c未明确final,它仍然有效final

  

我猜是会编译成这样的东西:

     

...

     

我是对的吗?

我认为这是有效的;编译器实际上并没有这样做,lambdas是他们自己的事情。如果我们想要强调c实际上是final这一事实,我们可能会在其参数声明中添加final