当前位置 : 主页 > 编程语言 > java >

深入理解lambda的奥秘

来源:互联网 收集:自由互联 发布时间:2022-09-02
大家好,我是李哥。 JDK1.6和JDK1.8是主流的两个大版本,目前市场上用的最多最多的依然是JDK1.8。所以,我们有必要聊一聊Java8的一些新特性。 深入理解lambda的奥秘 深入理解Stream之原理

大家好,我是李哥。

JDK1.6和JDK1.8是主流的两个大版本,目前市场上用的最多最多的依然是JDK1.8。所以,我们有必要聊一聊Java8的一些新特性。

  • 深入理解lambda的奥秘
  • 深入理解Stream之原理剖析
  • 深入理解Stream之foreach源码解析
  • 深入浅出NPE神器Optional
  • 谈谈接口默认方法与静态方法
  • 深入浅出重复注解与类型注解
  • 深入浅出JVM元空间metaspace
  • 今天我们先来聊聊深入理解lambda的奥秘。

    深入理解lambda的奥秘_java


    为什么会出现函数式编程

    在数学中,函数是有输入量、输出量的一套计算方案。相对而言,面向对象过分强调“必须通过对象的形式来做事情”,而函数式思想则尽量忽略面向对象的复杂语法——强调做什么,而不是以什么形式做。

    面向对象编程是对数据进行抽象;而函数式编程是对行为进行抽象。


    lambda表达式是什么

    lambda表达式也可称为闭包,是一个匿名函数,是对匿名函数的简写形式,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递),可以写出更简洁、更灵活的代码。

    作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。


    lambda表达式目标定位

    lambda表达式的目标定位:预定义使用了 @FunctionalInterface 注释的函数式接口,自带一个未实现的函数的方法,或者SAM(Single Abstract Method 单个抽象方法)类型。

    例如,若一个方法接收Runnable、Comparator或者 Callable 接口,都有单个抽象方法,可以传入lambda表达式。

    类似的,如果一个方法接受声明于 java.util.function 包内的接口,里面的每一个接口都标明类注解@FunctionalInterface,并且只有一个未实现的函数。例如常见的 Predicate、Function、Consumer 或 Supplier,那么可以向其传lambda表达式。


    lambda表达式写法组成

  • 形参列表:形参列表允许省略类型,如果形参列表中只有一个参数,形参列表的圆括号也可以省略;
  • 箭头(->):通过英文画线和大于符号组成;
  • 代码块:如果代码块只有一条语句,花括号可以省略。Lambda 代码块只有一条 return 语句,可以省略 return 关键字,Lambda 表达式会自动返回这条语句的值作为返回值。
  • 说到这里,相信大家已经比较明确lambda表达式了。接下来我们看看如何运用它吧。


    lambda的常见使用

    深入理解lambda的奥秘_javaee_02


    更深入的理解

    先来看几个case

    深入理解lambda的奥秘_Stream_03

    在编译器内部,会将lambda表达式翻译成私有方法,执行invokedynamic指令。我们可以使用javap -c -v查看字节码文件,当然也可以使用Idea的插件来查看字节码。

    jclasslib plugin:

    深入理解lambda的奥秘_代码块_04

    javap -c -v:(代码块较长,不想关注细节可直接跳过此模块)

    Classfile /Users/lige/IdeaProjects/javahomeProject/out/production/javahomeProject/com/ligejishu/lambda/LambdaDemo02.class
    Last modified 2022-8-7; size 2654 bytes
    MD5 checksum c76a7d3ce0088c93f0dc265b8eee28de
    Compiled from "LambdaDemo02.java"
    public class com.ligejishu.lambda.LambdaDemo02
    minor version: 0
    major version: 52
    flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
    #1 = Methodref #30.#54 // java/lang/Object."<init>":()V
    #2 = Class #55 // java/lang/Thread
    #3 = InvokeDynamic #0:#60 // #0:run:()Ljava/lang/Runnable;
    #4 = Methodref #2.#61 // java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
    #5 = Methodref #2.#62 // java/lang/Thread.start:()V
    #6 = Class #63 // java/util/ArrayList
    #7 = Methodref #6.#54 // java/util/ArrayList."<init>":()V
    #8 = String #64 // a
    #9 = InterfaceMethodref #17.#65 // java/util/List.add:(Ljava/lang/Object;)Z
    #10 = String #66 // c
    #11 = String #67 // b
    #12 = InterfaceMethodref #17.#68 // java/util/List.stream:()Ljava/util/stream/Stream;
    #13 = InvokeDynamic #1:#72 // #1:test:(Ljava/lang/String;)Ljava/util/function/Predicate;
    #14 = InterfaceMethodref #73.#74 // java/util/stream/Stream.filter:(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;
    #15 = Methodref #75.#76 // java/util/stream/Collectors.toList:()Ljava/util/stream/Collector;
    #16 = InterfaceMethodref #73.#77 // java/util/stream/Stream.collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
    #17 = Class #78 // java/util/List
    #18 = InvokeDynamic #2:#82 // #2:compare:()Ljava/util/Comparator;
    #19 = InterfaceMethodref #17.#83 // java/util/List.sort:(Ljava/util/Comparator;)V
    #20 = InvokeDynamic #3:#87 // #3:accept:()Ljava/util/function/Consumer;
    #21 = InterfaceMethodref #17.#88 // java/util/List.forEach:(Ljava/util/function/Consumer;)V
    #22 = Fieldref #89.#90 // java/lang/System.out:Ljava/io/PrintStream;
    #23 = String #91 // 123,
    #24 = Methodref #92.#93 // java/io/PrintStream.print:(Ljava/lang/String;)V
    #25 = String #94 // ,
    #26 = Methodref #92.#95 // java/io/PrintStream.println:()V
    #27 = String #96 // test print.
    #28 = Methodref #92.#97 // java/io/PrintStream.println:(Ljava/lang/String;)V
    #29 = Class #98 // com/ligejishu/lambda/LambdaDemo02
    #30 = Class #99 // java/lang/Object
    #31 = Utf8 <init>
    #32 = Utf8 ()V
    #33 = Utf8 Code
    #34 = Utf8 LineNumberTable
    #35 = Utf8 LocalVariableTable
    #36 = Utf8 this
    #37 = Utf8 Lcom/ligejishu/lambda/LambdaDemo02;
    #38 = Utf8 main
    #39 = Utf8 ([Ljava/lang/String;)V
    #40 = Utf8 args
    #41 = Utf8 [Ljava/lang/String;
    #42 = Utf8 list
    #43 = Utf8 Ljava/util/List;
    #44 = Utf8 filterList
    #45 = Utf8 LocalVariableTypeTable
    #46 = Utf8 Ljava/util/List<Ljava/lang/String;>;
    #47 = Utf8 lambda$main$1
    #48 = Utf8 (Ljava/lang/String;)V
    #49 = Utf8 it
    #50 = Utf8 Ljava/lang/String;
    #51 = Utf8 lambda$main$0
    #52 = Utf8 SourceFile
    #53 = Utf8 LambdaDemo02.java
    #54 = NameAndType #31:#32 // "<init>":()V
    #55 = Utf8 java/lang/Thread
    #56 = Utf8 BootstrapMethods
    #57 = MethodHandle #6:#100 // 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;
    #58 = MethodType #32 // ()V
    #59 = MethodHandle #6:#101 // invokestatic com/ligejishu/lambda/LambdaDemo02.lambda$main$0:()V
    #60 = NameAndType #102:#103 // run:()Ljava/lang/Runnable;
    #61 = NameAndType #31:#104 // "<init>":(Ljava/lang/Runnable;)V
    #62 = NameAndType #105:#32 // start:()V
    #63 = Utf8 java/util/ArrayList
    #64 = Utf8 a
    #65 = NameAndType #106:#107 // add:(Ljava/lang/Object;)Z
    #66 = Utf8 c
    #67 = Utf8 b
    #68 = NameAndType #108:#109 // stream:()Ljava/util/stream/Stream;
    #69 = MethodType #107 // (Ljava/lang/Object;)Z
    #70 = MethodHandle #5:#110 // invokevirtual java/lang/String.equals:(Ljava/lang/Object;)Z
    #71 = MethodType #111 // (Ljava/lang/String;)Z
    #72 = NameAndType #112:#113 // test:(Ljava/lang/String;)Ljava/util/function/Predicate;
    #73 = Class #114 // java/util/stream/Stream
    #74 = NameAndType #115:#116 // filter:(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;
    #75 = Class #117 // java/util/stream/Collectors
    #76 = NameAndType #118:#119 // toList:()Ljava/util/stream/Collector;
    #77 = NameAndType #120:#121 // collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
    #78 = Utf8 java/util/List
    #79 = MethodType #122 // (Ljava/lang/Object;Ljava/lang/Object;)I
    #80 = MethodHandle #5:#123 // invokevirtual java/lang/String.compareTo:(Ljava/lang/String;)I
    #81 = MethodType #124 // (Ljava/lang/String;Ljava/lang/String;)I
    #82 = NameAndType #125:#126 // compare:()Ljava/util/Comparator;
    #83 = NameAndType #127:#128 // sort:(Ljava/util/Comparator;)V
    #84 = MethodType #129 // (Ljava/lang/Object;)V
    #85 = MethodHandle #6:#130 // invokestatic com/ligejishu/lambda/LambdaDemo02.lambda$main$1:(Ljava/lang/String;)V
    #86 = MethodType #48 // (Ljava/lang/String;)V
    #87 = NameAndType #131:#132 // accept:()Ljava/util/function/Consumer;
    #88 = NameAndType #133:#134 // forEach:(Ljava/util/function/Consumer;)V
    #89 = Class #135 // java/lang/System
    #90 = NameAndType #136:#137 // out:Ljava/io/PrintStream;
    #91 = Utf8 123,
    #92 = Class #138 // java/io/PrintStream
    #93 = NameAndType #139:#48 // print:(Ljava/lang/String;)V
    #94 = Utf8 ,
    #95 = NameAndType #140:#32 // println:()V
    #96 = Utf8 test print.
    #97 = NameAndType #140:#48 // println:(Ljava/lang/String;)V
    #98 = Utf8 com/ligejishu/lambda/LambdaDemo02
    #99 = Utf8 java/lang/Object
    #100 = Methodref #141.#142 // 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;
    #101 = Methodref #29.#143 // com/ligejishu/lambda/LambdaDemo02.lambda$main$0:()V
    #102 = Utf8 run
    #103 = Utf8 ()Ljava/lang/Runnable;
    #104 = Utf8 (Ljava/lang/Runnable;)V
    #105 = Utf8 start
    #106 = Utf8 add
    #107 = Utf8 (Ljava/lang/Object;)Z
    #108 = Utf8 stream
    #109 = Utf8 ()Ljava/util/stream/Stream;
    #110 = Methodref #144.#145 // java/lang/String.equals:(Ljava/lang/Object;)Z
    #111 = Utf8 (Ljava/lang/String;)Z
    #112 = Utf8 test
    #113 = Utf8 (Ljava/lang/String;)Ljava/util/function/Predicate;
    #114 = Utf8 java/util/stream/Stream
    #115 = Utf8 filter
    #116 = Utf8 (Ljava/util/function/Predicate;)Ljava/util/stream/Stream;
    #117 = Utf8 java/util/stream/Collectors
    #118 = Utf8 toList
    #119 = Utf8 ()Ljava/util/stream/Collector;
    #120 = Utf8 collect
    #121 = Utf8 (Ljava/util/stream/Collector;)Ljava/lang/Object;
    #122 = Utf8 (Ljava/lang/Object;Ljava/lang/Object;)I
    #123 = Methodref #144.#146 // java/lang/String.compareTo:(Ljava/lang/String;)I
    #124 = Utf8 (Ljava/lang/String;Ljava/lang/String;)I
    #125 = Utf8 compare
    #126 = Utf8 ()Ljava/util/Comparator;
    #127 = Utf8 sort
    #128 = Utf8 (Ljava/util/Comparator;)V
    #129 = Utf8 (Ljava/lang/Object;)V
    #130 = Methodref #29.#147 // com/ligejishu/lambda/LambdaDemo02.lambda$main$1:(Ljava/lang/String;)V
    #131 = Utf8 accept
    #132 = Utf8 ()Ljava/util/function/Consumer;
    #133 = Utf8 forEach
    #134 = Utf8 (Ljava/util/function/Consumer;)V
    #135 = Utf8 java/lang/System
    #136 = Utf8 out
    #137 = Utf8 Ljava/io/PrintStream;
    #138 = Utf8 java/io/PrintStream
    #139 = Utf8 print
    #140 = Utf8 println
    #141 = Class #148 // java/lang/invoke/LambdaMetafactory
    #142 = NameAndType #149:#153 // 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;
    #143 = NameAndType #51:#32 // lambda$main$0:()V
    #144 = Class #154 // java/lang/String
    #145 = NameAndType #155:#107 // equals:(Ljava/lang/Object;)Z
    #146 = NameAndType #156:#157 // compareTo:(Ljava/lang/String;)I
    #147 = NameAndType #47:#48 // lambda$main$1:(Ljava/lang/String;)V
    #148 = Utf8 java/lang/invoke/LambdaMetafactory
    #149 = Utf8 metafactory
    #150 = Class #159 // java/lang/invoke/MethodHandles$Lookup
    #151 = Utf8 Lookup
    #152 = Utf8 InnerClasses
    #153 = 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;
    #154 = Utf8 java/lang/String
    #155 = Utf8 equals
    #156 = Utf8 compareTo
    #157 = Utf8 (Ljava/lang/String;)I
    #158 = Class #160 // java/lang/invoke/MethodHandles
    #159 = Utf8 java/lang/invoke/MethodHandles$Lookup
    #160 = Utf8 java/lang/invoke/MethodHandles
    {
    public com.ligejishu.lambda.LambdaDemo02();
    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 13: 0
    LocalVariableTable:
    Start Length Slot Name Signature
    0 5 0 this Lcom/ligejishu/lambda/LambdaDemo02;

    public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
    stack=3, locals=3, args_size=1
    0: new #2 // class java/lang/Thread
    3: dup
    4: invokedynamic #3, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
    9: invokespecial #4 // Method java/lang/Thread."<init>":(Ljava/lang/Runnable;)V
    12: invokevirtual #5 // Method java/lang/Thread.start:()V
    15: new #6 // class java/util/ArrayList
    18: dup
    19: invokespecial #7 // Method java/util/ArrayList."<init>":()V
    22: astore_1
    23: aload_1
    24: ldc #8 // String a
    26: invokeinterface #9, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
    31: pop
    32: aload_1
    33: ldc #10 // String c
    35: invokeinterface #9, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
    40: pop
    41: aload_1
    42: ldc #11 // String b
    44: invokeinterface #9, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
    49: pop
    50: aload_1
    51: invokeinterface #12, 1 // InterfaceMethod java/util/List.stream:()Ljava/util/stream/Stream;
    56: ldc #8 // String a
    58: invokedynamic #13, 0 // InvokeDynamic #1:test:(Ljava/lang/String;)Ljava/util/function/Predicate;
    63: invokeinterface #14, 2 // InterfaceMethod java/util/stream/Stream.filter:(Ljava/util/function/Predicate;)Ljava/util/stream/Stream;
    68: invokestatic #15 // Method java/util/stream/Collectors.toList:()Ljava/util/stream/Collector;
    71: invokeinterface #16, 2 // InterfaceMethod java/util/stream/Stream.collect:(Ljava/util/stream/Collector;)Ljava/lang/Object;
    76: checkcast #17 // class java/util/List
    79: astore_2
    80: aload_1
    81: invokedynamic #18, 0 // InvokeDynamic #2:compare:()Ljava/util/Comparator;
    86: invokeinterface #19, 2 // InterfaceMethod java/util/List.sort:(Ljava/util/Comparator;)V
    91: aload_1
    92: invokedynamic #20, 0 // InvokeDynamic #3:accept:()Ljava/util/function/Consumer;
    97: invokeinterface #21, 2 // InterfaceMethod java/util/List.forEach:(Ljava/util/function/Consumer;)V
    102: return
    LineNumberTable:
    line 16: 0
    line 19: 15
    line 20: 23
    line 21: 32
    line 22: 41
    line 23: 50
    line 26: 80
    line 27: 91
    line 34: 102
    LocalVariableTable:
    Start Length Slot Name Signature
    0 103 0 args [Ljava/lang/String;
    23 80 1 list Ljava/util/List;
    80 23 2 filterList Ljava/util/List;
    LocalVariableTypeTable:
    Start Length Slot Name Signature
    23 80 1 list Ljava/util/List<Ljava/lang/String;>;
    80 23 2 filterList Ljava/util/List<Ljava/lang/String;>;
    }
    SourceFile: "LambdaDemo02.java"
    InnerClasses:
    public static final #151= #150 of #158; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
    BootstrapMethods:
    0: #57 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:
    #58 ()V
    #59 invokestatic com/ligejishu/lambda/LambdaDemo02.lambda$main$0:()V
    #58 ()V
    1: #57 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:
    #69 (Ljava/lang/Object;)Z
    #70 invokevirtual java/lang/String.equals:(Ljava/lang/Object;)Z
    #71 (Ljava/lang/String;)Z
    2: #57 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:
    #79 (Ljava/lang/Object;Ljava/lang/Object;)I
    #80 invokevirtual java/lang/String.compareTo:(Ljava/lang/String;)I
    #81 (Ljava/lang/String;Ljava/lang/String;)I
    3: #57 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:
    #84 (Ljava/lang/Object;)V
    #85 invokestatic com/ligejishu/lambda/LambdaDemo02.lambda$main$1:(Ljava/lang/String;)V
    #86 (Ljava/lang/String;)V

    由此可见,如果使用lambda表达式使用方法引用,则编译器不会生成私有方法;如果lambda表达式没有使用方法引用,而是自定义函数实现,则编译器会生成一个内部私有方法。

    在这个示例代码块上,能够发现case1模块与case3的foreach模块,都是自定义了函数实现,所以编译器生成了两个私有方法,名称分别为:<lambda$mainmain$1>



    总结

  • lambda表达式强调具体实现,而不是用什么形式做
  • lambda表达式使得代码更简洁、灵活
  • lambda表达式也称之为闭包、匿名函数
  • 一般情况下可使用lambda表达式的接口都会标明类注解@FunctionalInterface,当然,不标明也没问题
  • 一般情况下如果使用lambda表达式,使用 java.util.function 包下的接口大多数都能满足要求
  • 使用lambda表达式,如果是自定义函数编译器在编译阶段会生成内部私有方法,如果是使用方法引用则不会生成内部私有方法
  • lambda表达式有个限制,那就是只能引用 final 或 final 局部变量,这就是说不能在lambda内部修改定义在域外的变量。
  • 谈到lambda表达式,我们对于Stream需要单独拎出来聊一聊:

    ​​深入理解Stream之原理剖析​​

    ​​深入理解Stream之foreach源码解析​​

    深入理解lambda的奥秘_Stream_06

    上一篇:Selenium基础知识
    下一篇:没有了
    网友评论