方法调用11——Lambda表达式

可参考前面的文章:
匿名内部类
lambda机制
方法引用method reference
lambda、方法引用与匿名内部类比较

public class Lambda {
    public static void main(String[] args) {
        System.setProperty("jdk.internal.lambda.dumpProxyClasses","/root/work");
        int x = 2;
        IntStream stream = IntStream.of(1, 2, 3).map(i -> i * 2).map(i -> i * x);
        System.out.println(Arrays.toString(stream.toArray()));
    }
}

1.解语法糖desugar

Javac对Lambda表达式进行解语法糖,生成一个方法来保存Lambda表达式的内容。
该方法还会包含它所捕获的变量。、
方法引用不会额外生成方法。

i -> i * 2对应如下:

  private static int lambda$main$0(int);
    descriptor: (I)I
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=1, args_size=1
         0: iload_0
         1: iconst_2
         2: imul
         3: ireturn
      LineNumberTable:
        line 8: 0

i -> i * x 对应如下:

  private static int lambda$main$1(int, int);
    descriptor: (II)I
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_1
         1: iload_0
         2: imul
         3: ireturn
      LineNumberTable:
        line 8: 0

2.生成函数接口实现类

IntStream map(IntUnaryOperator mapper);
@FunctionalInterface
public interface IntUnaryOperator {
    int applyAsInt(int operand);
    ...
}

根据Lambda表达式是否捕获变量,生成的适配器类以及所链接的MethodHandle均不同。

若未捕获变量,可以认为是上下文无关。启动方法将新建一个适配器类实例,生成一个特殊的方法句柄,始终返回该实例。

final class Lambda$$Lambda$1 implements java.util.function.IntUnaryOperator
  minor version: 0
  major version: 52
  flags: ACC_FINAL, ACC_SUPER, ACC_SYNTHETIC
Constant pool:
   #1 = Utf8               Lambda$$Lambda$1
   #2 = Class              #1             // Lambda$$Lambda$1
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               java/util/function/IntUnaryOperator
   #6 = Class              #5             // java/util/function/IntUnaryOperator
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = NameAndType        #7:#8          // "<init>":()V
  #10 = Methodref          #4.#9          // java/lang/Object."<init>":()V
  #11 = Utf8               applyAsInt
  #12 = Utf8               (I)I
  #13 = Utf8               Ljava/lang/invoke/LambdaForm$Hidden;
  #14 = Utf8               Lambda
  #15 = Class              #14            // Lambda
  #16 = Utf8               lambda$main$0
  #17 = NameAndType        #16:#12        // lambda$main$0:(I)I
  #18 = Methodref          #15.#17        // Lambda.lambda$main$0:(I)I
  #19 = Utf8               Code
  #20 = Utf8               RuntimeVisibleAnnotations
{
  private Lambda$$Lambda$1();
    descriptor: ()V
    flags: ACC_PRIVATE
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #10                 // Method java/lang/Object."<init>":()V
         4: return

  public int applyAsInt(int);
    descriptor: (I)I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=2
         0: iload_1
         1: invokestatic  #18                 // Method Lambda.lambda$main$0:(I)I
         4: ireturn
    RuntimeVisibleAnnotations:
      0: #13()
}

如果捕获了变量,每次调用是都需更新捕获的变量。此时无法共享同一个适配器类的实例,每次调用都需新建一个适配器类实例。因此该适配器类包含一个额外的静态方法private static java.util.function.IntUnaryOperator get$Lambda(int),该方法每次新建一个适配器类实例,并将捕获的参数作为实例的域。

final class Lambda$$Lambda$2 implements java.util.function.IntUnaryOperator
  minor version: 0
  major version: 52
  flags: ACC_FINAL, ACC_SUPER, ACC_SYNTHETIC
Constant pool:
   #1 = Utf8               Lambda$$Lambda$2
   #2 = Class              #1             // Lambda$$Lambda$2
   #3 = Utf8               java/lang/Object
   #4 = Class              #3             // java/lang/Object
   #5 = Utf8               java/util/function/IntUnaryOperator
   #6 = Class              #5             // java/util/function/IntUnaryOperator
   #7 = Utf8               arg$1
   #8 = Utf8               I
   #9 = Utf8               <init>
  #10 = Utf8               (I)V
  #11 = Utf8               ()V
  #12 = NameAndType        #9:#11         // "<init>":()V
  #13 = Methodref          #4.#12         // java/lang/Object."<init>":()V
  #14 = NameAndType        #7:#8          // arg$1:I
  #15 = Fieldref           #2.#14         // Lambda$$Lambda$2.arg$1:I
  #16 = Utf8               get$Lambda
  #17 = Utf8               (I)Ljava/util/function/IntUnaryOperator;
  #18 = NameAndType        #9:#10         // "<init>":(I)V
  #19 = Methodref          #2.#18         // Lambda$$Lambda$2."<init>":(I)V
  #20 = Utf8               applyAsInt
  #21 = Utf8               (I)I
  #22 = Utf8               Ljava/lang/invoke/LambdaForm$Hidden;
  #23 = Utf8               Lambda
  #24 = Class              #23            // Lambda
  #25 = Utf8               lambda$main$1
  #26 = Utf8               (II)I
  #27 = NameAndType        #25:#26        // lambda$main$1:(II)I
  #28 = Methodref          #24.#27        // Lambda.lambda$main$1:(II)I
  #29 = Utf8               Code
  #30 = Utf8               RuntimeVisibleAnnotations
{
  private final int arg$1;
    descriptor: I
    flags: ACC_PRIVATE, ACC_FINAL

  private Lambda$$Lambda$2(int);
    descriptor: (I)V
    flags: ACC_PRIVATE
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: invokespecial #13                 // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iload_1
         6: putfield      #15                 // Field arg$1:I
         9: return

  private static java.util.function.IntUnaryOperator get$Lambda(int);
    descriptor: (I)Ljava/util/function/IntUnaryOperator;
    flags: ACC_PRIVATE, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=1
         0: new           #2                  // class Lambda$$Lambda$2
         3: dup
         4: iload_0
         5: invokespecial #19                 // Method "<init>":(I)V
         8: areturn

  public int applyAsInt(int);
    descriptor: (I)I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: getfield      #15                 // Field arg$1:I
         4: iload_1
         5: invokestatic  #28                 // Method Lambda.lambda$main$1:(II)I
         8: ireturn
    RuntimeVisibleAnnotations:
      0: #22()
}

附录——字节码

-private or -p
Shows all classes and members.

javap -c -v -p Lambda.class

public class Lambda
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #14.#27        // java/lang/Object."<init>":()V
   #2 = String             #28            // jdk.internal.lambda.dumpProxyClasses
   #3 = String             #29            // /root/work
   #4 = Methodref          #30.#31        // java/lang/System.setProperty:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
   #5 = InterfaceMethodref #32.#33        // java/util/stream/IntStream.of:([I)Ljava/util/stream/IntStream;
   #6 = InvokeDynamic      #0:#38         // #0:applyAsInt:()Ljava/util/function/IntUnaryOperator;
   #7 = InterfaceMethodref #32.#39        // java/util/stream/IntStream.map:(Ljava/util/function/IntUnaryOperator;)Ljava/util/stream/IntStream;
   #8 = InvokeDynamic      #1:#41         // #1:applyAsInt:(I)Ljava/util/function/IntUnaryOperator;
   #9 = Fieldref           #30.#42        // java/lang/System.out:Ljava/io/PrintStream;
  #10 = InterfaceMethodref #32.#43        // java/util/stream/IntStream.toArray:()[I
  #11 = Methodref          #44.#45        // java/util/Arrays.toString:([I)Ljava/lang/String;
  #12 = Methodref          #46.#47        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #13 = Class              #48            // Lambda
  #14 = Class              #49            // java/lang/Object
  #15 = Utf8               <init>
  #16 = Utf8               ()V
  #17 = Utf8               Code
  #18 = Utf8               LineNumberTable
  #19 = Utf8               main
  #20 = Utf8               ([Ljava/lang/String;)V
  #21 = Utf8               lambda$main$1
  #22 = Utf8               (II)I
  #23 = Utf8               lambda$main$0
  #24 = Utf8               (I)I
  #25 = Utf8               SourceFile
  #26 = Utf8               Lambda.java
  #27 = NameAndType        #15:#16        // "<init>":()V
  #28 = Utf8               jdk.internal.lambda.dumpProxyClasses
  #29 = Utf8               /root/work
  #30 = Class              #50            // java/lang/System
  #31 = NameAndType        #51:#52        // setProperty:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
  #32 = Class              #53            // java/util/stream/IntStream
  #33 = NameAndType        #54:#55        // of:([I)Ljava/util/stream/IntStream;
  #34 = Utf8               BootstrapMethods
  #35 = MethodHandle       #6:#56         // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #36 = MethodType         #24            //  (I)I
  #37 = MethodHandle       #6:#57         // invokestatic Lambda.lambda$main$0:(I)I
  #38 = NameAndType        #58:#59        // applyAsInt:()Ljava/util/function/IntUnaryOperator;
  #39 = NameAndType        #60:#61        // map:(Ljava/util/function/IntUnaryOperator;)Ljava/util/stream/IntStream;
  #40 = MethodHandle       #6:#62         // invokestatic Lambda.lambda$main$1:(II)I
  #41 = NameAndType        #58:#63        // applyAsInt:(I)Ljava/util/function/IntUnaryOperator;
  #42 = NameAndType        #64:#65        // out:Ljava/io/PrintStream;
  #43 = NameAndType        #66:#67        // toArray:()[I
  #44 = Class              #68            // java/util/Arrays
  #45 = NameAndType        #69:#70        // toString:([I)Ljava/lang/String;
  #46 = Class              #71            // java/io/PrintStream
  #47 = NameAndType        #72:#73        // println:(Ljava/lang/String;)V
  #48 = Utf8               Lambda
  #49 = Utf8               java/lang/Object
  #50 = Utf8               java/lang/System
  #51 = Utf8               setProperty
  #52 = Utf8               (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
  #53 = Utf8               java/util/stream/IntStream
  #54 = Utf8               of
  #55 = Utf8               ([I)Ljava/util/stream/IntStream;
  #56 = Methodref          #74.#75        // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #57 = Methodref          #13.#76        // Lambda.lambda$main$0:(I)I
  #58 = Utf8               applyAsInt
  #59 = Utf8               ()Ljava/util/function/IntUnaryOperator;
  #60 = Utf8               map
  #61 = Utf8               (Ljava/util/function/IntUnaryOperator;)Ljava/util/stream/IntStream;
  #62 = Methodref          #13.#77        // Lambda.lambda$main$1:(II)I
  #63 = Utf8               (I)Ljava/util/function/IntUnaryOperator;
  #64 = Utf8               out
  #65 = Utf8               Ljava/io/PrintStream;
  #66 = Utf8               toArray
  #67 = Utf8               ()[I
  #68 = Utf8               java/util/Arrays
  #69 = Utf8               toString
  #70 = Utf8               ([I)Ljava/lang/String;
  #71 = Utf8               java/io/PrintStream
  #72 = Utf8               println
  #73 = Utf8               (Ljava/lang/String;)V
  #74 = Class              #78            // java/lang/invoke/LambdaMetafactory
  #75 = NameAndType        #79:#83        // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #76 = NameAndType        #23:#24        // lambda$main$0:(I)I
  #77 = NameAndType        #21:#22        // lambda$main$1:(II)I
  #78 = Utf8               java/lang/invoke/LambdaMetafactory
  #79 = Utf8               metafactory
  #80 = Class              #85            // java/lang/invoke/MethodHandles$Lookup
  #81 = Utf8               Lookup
  #82 = Utf8               InnerClasses
  #83 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #84 = Class              #86            // java/lang/invoke/MethodHandles
  #85 = Utf8               java/lang/invoke/MethodHandles$Lookup
  #86 = Utf8               java/lang/invoke/MethodHandles
{
  public Lambda();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 4: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=3, args_size=1
         0: ldc           #2                  // String jdk.internal.lambda.dumpProxyClasses
         2: ldc           #3                  // String /root/work
         4: invokestatic  #4                  // Method java/lang/System.setProperty:(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
         7: pop
         8: iconst_2
         9: istore_1
        10: iconst_3
        11: newarray       int
        13: dup
        14: iconst_0
        15: iconst_1
        16: iastore
        17: dup
        18: iconst_1
        19: iconst_2
        20: iastore
        21: dup
        22: iconst_2
        23: iconst_3
        24: iastore
        25: invokestatic  #5                  // InterfaceMethod java/util/stream/IntStream.of:([I)Ljava/util/stream/IntStream;
        28: invokedynamic #6,  0              // InvokeDynamic #0:applyAsInt:()Ljava/util/function/IntUnaryOperator;
        33: invokeinterface #7,  2            // InterfaceMethod java/util/stream/IntStream.map:(Ljava/util/function/IntUnaryOperator;)Ljava/util/stream/IntStream;
        38: iload_1
        39: invokedynamic #8,  0              // InvokeDynamic #1:applyAsInt:(I)Ljava/util/function/IntUnaryOperator;
        44: invokeinterface #7,  2            // InterfaceMethod java/util/stream/IntStream.map:(Ljava/util/function/IntUnaryOperator;)Ljava/util/stream/IntStream;
        49: astore_2
        50: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
        53: aload_2
        54: invokeinterface #10,  1           // InterfaceMethod java/util/stream/IntStream.toArray:()[I
        59: invokestatic  #11                 // Method java/util/Arrays.toString:([I)Ljava/lang/String;
        62: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        65: return
      LineNumberTable:
        line 6: 0
        line 7: 8
        line 8: 10
        line 9: 50
        line 10: 65

  private static int lambda$main$1(int, int);
    descriptor: (II)I
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_1
         1: iload_0
         2: imul
         3: ireturn
      LineNumberTable:
        line 8: 0

  private static int lambda$main$0(int);
    descriptor: (I)I
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=1, args_size=1
         0: iload_0
         1: iconst_2
         2: imul
         3: ireturn
      LineNumberTable:
        line 8: 0
}
SourceFile: "Lambda.java"
InnerClasses:
     public static final #81= #80 of #84; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
  0: #35 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #36 (I)I
      #37 invokestatic Lambda.lambda$main$0:(I)I
      #36 (I)I
  1: #35 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #36 (I)I
      #40 invokestatic Lambda.lambda$main$1:(II)I
      #36 (I)I
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容