2017-05-06 73 views
4

正如我所知的内部和外部类的外部变量范围存储在生成的字节码(例如OuterClass $ 1.class)中。 我想知道下一个例子,其中存储的变量:超出范围的变量存储在lambda表达式中

public Function<Integer, Integer> curring(Integer elem) { 
    return x -> x * elem; 
} 

Arrays.asList(1, 2, 3, 4, 5).stream().map(curring(2)).map(curring(5)).forEach(System.out::println); 

LAMBDA被翻译的方法,而不是类。这是否意味着这2个调用会产生2个独立的方法?

+2

已经找到关于此主题的有趣阅读:[lambda的翻译(http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation。html) – Ving

+2

这不是一个有趣的*阅读,那就是*阅读关于lambda翻译... – Eugene

回答

7

这种表达x -> x * elem;将被取消加糖的静态方法,看起来像这样:

private static Integer lambda$curring$0(int x, int y){ 
     return x*y; 
    } 

因为你是capturingelem变量拉姆达,拉姆达被认为是stateful lambda

在另一方面,你map操作需要的java.util.Function的实际情况 - 这是在运行时将那种看起来是这样产生的

final class Test2$$Lambda$1 implements java.util.function.Function { 
     private final Integer arg$1; 

     private Test2$$Lambda$1(Integer arg$1){ 
      this.arg$1 = arg$1; 
     } 

     // static factory method 
     private static java.util.function.Function get$Lambda(Integer i){ 
      return new Test2$$Lambda$1(i); // instance of self 
     } 

     public Integer apply(Integer x) { 
      return YourClass.lambda$curring$0(this.arg$1, x);  
     } 
} 

之前Function.apply(你的地图操作中)被称为新实例Test2$$Lambda$1是通过静态工厂方法get$Lambda生成的。这是需要“携带”elem变量。

因为那个每次调用地图时都会创建一个新实例

由于您的Stream包含五个初始元素,因此将会创建10个实例 - 用于两个map操作。

但是一般这是一个实现细节,可能很容易改变一天 - 所以不要依赖它。此外,这个短期实例的创建和收集(垃圾收集器)非常便宜,几乎不会影响您的应用程序。

+0

有些挑剔:当你实现原始的'Function'时,你需要一个'Object apply(Object x)方法和类型转换。这是生成的代码中实际发生的事情。此外,'this.i'必须是'this.arg $ 1'。捕获的值是第一个参数,函数参数('x')是第二个是正确的。在生成的'lambda $ curring $ 0'方法中,使用'elem'和'x'作为这些参数的名称,而不是'x'和'y',会更容易混淆...... – Holger

+0

@Holger,这是迄今为止没有挑剔的在我的世界里。这个答案实际上是几个小时的阅读*你的*(这是这个评论中的主要关键字)其他答案和很多调试以及很多字节码... thx的建议。 – Eugene

3

每次调用curring(..)方法时,都会创建一个新对象。所以是的,你会有2个对象。

这是因为你的lambda不是无状态的,也就是说它不能独立工作。它需要捕获一个外部变量,elem

如果您拉姆达使用像2一个固定的号码,而不是elem

public Function<Integer, Integer> curring() { 
    return x -> x * 2; 
} 

你拉姆达是无状态的。它不会捕获任何外部变量。在这种情况下,你的lambda将是一个多次调用的单例。

请注意,这种行为是依赖于JVM的,而上述内容来自HotSpot JVM。

此处了解详情:Does a lambda expression create an object on the heap every time it's executed?