编译后的 Java 8 Lambda 表达式是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21858482/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 11:05:59  来源:igfitidea点击:

What is a Java 8 Lambda Expression Compiled to?

javalambdajava-8

提问by ams

Consider the following Java 8 snippet.

考虑以下 Java 8 代码段。

public static void main(String[] args) {            
   List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);

   Consumer<Integer>  consumer = x -> System.out.print(x);  

   integers.forEach(consumer);
}

What is Consumer<Integer> consumer = x -> System.out.print(x)getting compiled to?

什么是Consumer<Integer> consumer = x -> System.out.print(x)越来越编译?

I understand that Lambdas are not implemented as anonymous inner classes. However Consumer<Integer>is an interface therefore x -> System.out.print(x)must be producing an object of some kind but it is not clear what kind of object is being produced.

我知道 Lambda 不是作为匿名内部类实现的。然而Consumer<Integer>,接口因此x -> System.out.print(x)必须产生某种对象,但不清楚正在产生什么样的对象。

Is there some new type of object in Java 8 to represent a lambda expression?

Java 8 中是否有一些新类型的对象来表示 lambda 表达式?

UpdateHere is the decompiled program the program was complied with the eclipse java 8 complier and the output below is from eclipse when you open a class file.

更新这是反编译的程序,该程序是用 eclipse java 8 编译器编译的,下面的输出来自 eclipse 打开类文件时。

It looks like that the lambda expression is getting turned into a static method on the class that contains the lambda expression private static synthetic void lambda$0(java.lang.Integer x);

看起来 lambda 表达式正在变成包含 lambda 表达式的类上的静态方法 private static synthetic void lambda$0(java.lang.Integer x);

// Compiled from Example.java (version 1.8 : 52.0, super bit)
public class Example {

  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public Example();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 7]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: Example

  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 4, Locals: 3
  public static void main(java.lang.String[] args);
     0  iconst_5
     1  anewarray java.lang.Integer [16]
     4  dup
     5  iconst_0
     6  iconst_1
     7  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    10  aastore
    11  dup
    12  iconst_1
    13  iconst_2
    14  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    17  aastore
    18  dup
    19  iconst_2
    20  iconst_3
    21  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    24  aastore
    25  dup
    26  iconst_3
    27  iconst_4
    28  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    31  aastore
    32  dup
    33  iconst_4
    34  iconst_5
    35  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    38  aastore
    39  invokestatic java.util.Arrays.asList(java.lang.Object[]) : java.util.List [22]
    42  astore_1 [integers]
    43  invokedynamic 0 accept() : java.util.function.Consumer [31]
    48  astore_2 [consumer]
    49  getstatic java.lang.System.out : java.io.PrintStream [32]
    52  aload_2 [consumer]
    53  invokevirtual java.lang.Object.getClass() : java.lang.Class [38]
    56  invokevirtual java.lang.Class.getCanonicalName() : java.lang.String [42]
    59  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
    62  getstatic java.lang.System.out : java.io.PrintStream [32]
    65  aload_2 [consumer]
    66  invokevirtual java.lang.Object.getClass() : java.lang.Class [38]
    69  invokevirtual java.lang.Class.getTypeName() : java.lang.String [54]
    72  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
    75  aload_1 [integers]
    76  aload_2 [consumer]
    77  invokeinterface java.util.List.forEach(java.util.function.Consumer) : void [57] [nargs: 2]
    82  return
      Line numbers:
        [pc: 0, line: 10]
        [pc: 43, line: 12]
        [pc: 49, line: 14]
        [pc: 62, line: 15]
        [pc: 75, line: 17]
        [pc: 82, line: 18]
      Local variable table:
        [pc: 0, pc: 83] local: args index: 0 type: java.lang.String[]
        [pc: 43, pc: 83] local: integers index: 1 type: java.util.List
        [pc: 49, pc: 83] local: consumer index: 2 type: java.util.function.Consumer
      Local variable type table:
        [pc: 43, pc: 83] local: integers index: 1 type: java.util.List<java.lang.Integer>
        [pc: 49, pc: 83] local: consumer index: 2 type: java.util.function.Consumer<java.lang.Integer>

  // Method descriptor #73 (Ljava/lang/Integer;)V
  // Stack: 2, Locals: 1
  private static synthetic void lambda
x -> System.out.print(x);  
(java.lang.Integer x); 0 getstatic java.lang.System.out : java.io.PrintStream [32] 3 aload_0 [x] 4 invokevirtual java.io.PrintStream.print(java.lang.Object) : void [74] 7 return Line numbers: [pc: 0, line: 12] Local variable table: [pc: 0, pc: 8] local: x index: 0 type: java.lang.Integer Inner classes: [inner class info: #96 java/lang/invoke/MethodHandles$Lookup, outer class info: #98 java/lang/invoke/MethodHandles inner name: #100 Lookup, accessflags: 25 public static final] Bootstrap methods: 0 : # 89 arguments: {#90,#93,#94} }

采纳答案by Sotirios Delimanolis

The current draft of the Java 8 Language Specificationstates (chapter 15.27.4)

Java 8 语言规范当前草案状态(第 15.27.4 章)

The value of a lambda expression is a reference to an instance of a class with the following properties:

  • The class implements the targeted functional interface and, if the target type is an intersection type, every other interface element of the intersection.
  • The class declares a method that overrides the functional interface supertype's abstract methods (and, potentially, some other methods of its superinterfaces).
  • The method's parameter types, return type, and thrown types are given by the interface's function type.
  • The method's body has the effect of evaluating the lambda body, if it is an expression, or of executing the lambda body, if it is a block; if a result is expected, it is returned from the method.
  • The class overrides no other methods of the interface or interfaces mentioned above, except that it may override methods of the Objectclass.

lambda 表达式的值是对具有以下属性的类实例的引用:

  • 该类实现目标功能接口,如果目标类型是交集类型,则实现交集的所有其他接口元素。
  • 该类声明了一个方法,该方法覆盖功能接口超类型的抽象方法(以及可能覆盖其超接口的一些其他方法)。
  • 方法的参数类型、返回类型和抛出类型由接口的函数类型给出。
  • 该方法的主体具有评估 lambda 主体(如果它是一个表达式)或执行 lambda 主体(如果它是一个块)的效果;如果需要结果,则从该方法返回。
  • 该类不覆盖上面提到的一个或多个接口的其他方法,除了它可以覆盖Object该类的方法。

Note that the JLS doesn't say anything about how the code should be compiled except that the byte code should support the specification above.

请注意,除了字节码应支持上述规范之外,JLS 没有说明应如何编译代码。

As such, the object returned by the lambda expression

因此,由 lambda 表达式返回的对象

consumer.getClass()

will be an instance of a class that follows the above rules.

将是遵循上述规则的类的实例。

Given your comment that

鉴于你的评论

Example$$Lambda/1072591677

returns the following class

返回以下类

##代码##

it seems that it is generating a proxy-like class specific for lambda expressions.

似乎它正在生成一个特定于 lambda 表达式的类似代理的类。

See here:

看这里: