• Java8中实现函数式接口的Lambda表达式与方法引用详解


    函数式接口的实现既可以使用Lambda表达式也可以使用方法引用的方式,那么它们之间有何区别呢?

    也就是说: 函数式接口的实例既可以是Lambda表达式也可以是方法引用

    //方式1: Lambda
    Function<String, String> lambda = (a) -> a.toUpperCase();
    
    //方式2: 方法引用
    Function<String, String> lambda = String::toUpperCase;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    废话少说,咱来通过实验一步一步来解开其中的奥秘!

    测试源代码TestClassInstanceMethodRefrence:

    package wjw.test.java8.invokedynamic;
    
    import java.util.Arrays;
    
    public class TestClassInstanceMethodRefrence {
      static {
        //加上这个参数后,运行时会将生成的函数式接口代理类的class代码码输出到一个文件中
        System.setProperty("jdk.internal.lambda.dumpProxyClasses", "./lambda_dumpProxyClasses");
      }
    
      public static void main(String[] args) {
      (new TestClassInstanceMethodRefrence()).testA();
      (new TestClassInstanceMethodRefrence()).testB();
      }
      
      public TestClassInstanceMethodRefrence() {
      }
    
      public void testA() {
        String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
        Arrays.sort(stringArray, (T1, T2) -> T1.compareToIgnoreCase(T2));    
      }
      
      public void testB() {
        String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
        Arrays.sort(stringArray, String::compareToIgnoreCase);
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    Arrays.sort()方法里需要一个函数式接口参数Comparator, 方法testA是使用Lambda表达式方式,方法testB是使用方法引用方式.

    来看看编译后的代码:

    测试类: TestClassInstanceMethodRefrence

    package wjw.test.java8.invokedynamic;
    
    import java.util.*;
    
    public class TestClassInstanceMethodRefrence
    {
        static {
            System.setProperty("jdk.internal.lambda.dumpProxyClasses", "./lambda_dumpProxyClasses");
        }
        
        public static void main(final String[] args) {
            new TestClassInstanceMethodRefrence().testA();
            new TestClassInstanceMethodRefrence().testB();
        }
        
        public TestClassInstanceMethodRefrence() {
            super();
        }
        
        public void testA() {
            final String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
            Arrays.sort(stringArray, (T1, T2) -> T1.compareToIgnoreCase(T2));
        }
        
        public void testB() {
            final String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
            Arrays.sort(stringArray, String::compareToIgnoreCase);
        }
        
        private static /* synthetic */ int lambda$0(final String T1, final String T2) {
            return T1.compareToIgnoreCase(T2);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    可以看到里面多出来一个lambda$0方法,这个方法就是编译器自动添加的让lambda表达式来调用

    lambda方式对应的源码: TestClassInstanceMethodRefrence$$Lambda$1.class

    package wjw.test.java8.invokedynamic;
    
    import java.util.*;
    import java.lang.invoke.*;
    
    final synthetic class TestClassInstanceMethodRefrence$$Lambda$1 implements Comparator
    {
        private TestClassInstanceMethodRefrence$$Lambda$1() {
            super();
        }
        
        @LambdaForm.Hidden
        @Override
        public int compare(final Object o, final Object o2) {
            return TestClassInstanceMethodRefrence.lambda$0((String)o, (String)o2);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    含有Lambda的类在程序运行的时的流程:

    1. 在含有Lambda的类中新增一个private static的方法,这个方法的方法体就是Lambda表达式中的代码
    2. 还会生成一个匿名内部类,实现Lambda表达式代表的函数式接口,重写抽象方法
    3. 在重写方法中会调用含有Lambda的类中新生成的private static的那个方法.

    方法引用方式对应的源码: TestClassInstanceMethodRefrence$$Lambda$2.class

    package wjw.test.java8.invokedynamic;
    
    import java.util.*;
    import java.lang.invoke.*;
    
    final synthetic class TestClassInstanceMethodRefrence$$Lambda$2 implements Comparator
    {
        private TestClassInstanceMethodRefrence$$Lambda$2() {
            super();
        }
        
        @LambdaForm.Hidden
        @Override
        public int compare(final Object o, final Object o2) {
            return ((String)o).compareToIgnoreCase((String)o2);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    含有方法引用的类在程序运行的时的流程:

    1. 生成一个匿名内部类,实现方法引用代表的函数式接口,重写抽象方法
    2. 在重写方法中会调用方法引用指向的的那个方法.

    可以看出方法引用实际上是Lambda表达式的更简洁高效的写法.不会像Lambda表达式那让在包含Lambda表达式的类里生成一个静态私有方法.

    最后给出一个2种方式的调用实例图:
    在这里插入图片描述

    <<<<<< [完] >>>>>>

  • 相关阅读:
    python学习第四天之分支结构
    学生个人网页设计作品 HTML+CSS+JavaScript仿小米商城(8页) 学生个人网页模板 简单个人主页成品 个人网页制作 HTML学生个人网站作业设计
    fatal: protocol ‘“https‘ is not supported
    vscode的git提交提示commit-msg hook failed (add --no-verify to bypass)
    替换printf中的标志
    C++实现高性能内存池(二)
    IDEA插件开发
    java 时间类型和 mysql 时间类型对应关系
    【小型网站测试】使用python脚本来控制docker容器的编排
    15 | Linux系统上安装python
  • 原文地址:https://blog.csdn.net/wjw465150/article/details/126853660