lambda表达式之方法的调用

前提一:在函数式接口(FI)的作用域内

前提二:lambda表达式函数体必须是表达式(函数体只有一行)。

前提三:那个表达式的格式是:符合java语法标准的,方法的调用

另外,记住3种情况就可以:

一. 静态方法的调用

类名::静态方法名

示例
公用类:

    public class Student {
    
        private Integer id;
    
        private String name;
    
        public Student(Integer id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public String getStudentInfo() {
            return "Student:name:" + name + ",id:" + id;
        }
    
        public void printStudentInfo() {
            Log.d("CCC", getStudentInfo());
        }
    
        public void printStudentInfo2(String addedNote) {
            Log.d("CCC", "addedNote:" + addedNote + " " + getStudentInfo());
        }
    
    }
    public class StudentUtils {
        public static String getStudentInfo(Student student) {
            return student.getStudentInfo();
        }
    }
    public class GetStudentInfoUseCase {
        public String getStudentInfo(Student student){
            return student.getStudentInfo();
        }
    }

数据源:

    private List getData() {
        List list = new ArrayList<>();

        for (int i = 0; i < 100; i++) {
            Integer id = i + 1;
            list.add(new Student(id, "N" + id));
        }

        return list;
    }

静态方法的调用:

    private void testStaticRef() {
        getData().forEach(StudentUtils::getStudentInfo);
    }

就是这么简单,但是我们要看下演化的流程。下面是原版:

    getData().forEach(new java.util.function.Consumer() {
        @Override
        public void accept(Student student) {
            StudentUtils.getStudentInfo(student);
        }
    });

将 FI 转为lambda:

    getData().forEach(student -> StudentUtils.getStudentInfo(student));

可以看到:

  • GetCardInfoUseCase.getCardInfo的参数列表 与 FI 方法【accept(Student student) 】的参数列表是一致的

  • 向GetCardInfoUseCase.getCardInfo传的值正好就是FI方法的实参

正因为静态方法与FI方法两者的参数列表一致,且由FI方法传递给静态方法,也就是说无论FI的方法是什么,静态方法都要保持一致并接收。
所以可以直接省略参数列表,直接显示是什么类的什么方法。

也就是:

    getData().forEach(StudentUtils::getStudentInfo);
二. 实例上的实例方法调用

实例对象::实例方法名

示例

    private void testInstInstRef() {
        GetStudentInfoUseCase useCase = new GetStudentInfoUseCase();

        getData().forEach(useCase::getStudentInfo);
    }

演化的流程,下面原版:

    getData().forEach(new java.util.function.Consumer() {
        @Override
        public void accept(Student student) {
            useCase.getStudentInfo(student);
        }
    });

FI 转为lambda:

    getData().forEach(student -> useCase.getStudentInfo(student));

最后:

    getData().forEach(useCase::getStudentInfo);

同理:lambda实例方法的参数列表必须同FI方法的参数列表保持一致

三. 类型上的实例方法调用

类名::实例方法名

可以看出:它的调用方式同第一种“静态方法的调用”

示例

    private void testClsInstRef() {
        getData().forEach(Student::printStudentInfo);
    }

演化流程,下面是原版:

    getData().forEach(new java.util.function.Consumer() {
        @Override
        public void accept(Student student) {
            student.printStudentInfo();
        }
    });

将FI 转为lambda:

    getData().forEach(student -> student.printStudentInfo());

最后:

    getData().forEach(Student::printStudentInfo);
来来来,划重点:

前两种方式是将FI的实参,作为lambda方法的实参来使用
而第三种,FI的实参,是作为lambda方法的调用者来使用

这就是第三种可以使用类型::实例方法名来调用的原因。

有利必有弊,第三种默认是将lambda方法的第一个实参作为该实例方法的调用者(本文FI方法【accept(Student student) 】只是恰巧只有一个,其他FI方法可以有多个)。但这种调用的局限性非常明显,那就是对于被调用的方法而言不能有参数

    getData().forEach(Student::printStudentInfo2);

printStudentInfo2(String addedNote)方法有一个参数,编译时报如下错:

image.png

可以看出:编译器直接将printStudentInfo2方法识别为静态方法

以上就是三种方法的快速使用总结。其他方法的调用还有:超类上的实例方法调用,构造方法的调用,数组构造方法调用等这些不常用的就不赘述了,用到再自己查阅资料。

你可能感兴趣的:(lambda表达式之方法的调用)