JAVA8学习4-方法引用(Method reference)

4. 方法引用(Method reference)

方法引用其实就是 Lambda 表达式的语法糖

​ 方法引用本质上就是一个【函数指针】function pointer

注意: 方法调用和方法引用没有半毛钱关系,如果学过 JavaScript 就类似于使用函数变量地址值的传递。

方法引用分4类:

​ 我们先建个类,用于对象排序。

package cn.zxhysy.jdk8.methodreference;

import java.util.List;

public class Student {

    private String name;

    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    /** 排序方法 */
    public static int compareStudentByScore(Student student1, Student student2){
        return student1.score - student2.score;
    }
    /** 根据名字字符比较 */
    public static int compareStudentByName(Student student1, Student student2){
        return student1.getName().compareToIgnoreCase(student2.getName());
    }
}

4.1 类名::静态方法名

​ 类名::静态方法名 替换 Lambda 表达式,要求要类中有一个方法体跟 Lamdba 表达式是客观等价的,就可以被引用。也就是参数列表一致(参数值,参数类型,返回值一致)。

package cn.zxhysy.jdk8.methodreference;

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class MethodReferenceTest {

    public static void main(String[] args) {
        Student student1 = new Student("zhangsan",10);
        Student student2 = new Student("lisi",90);
        Student student3 = new Student("wangwu",60);
        Student student4 = new Student("zhaoliu",30);

        List<Student> students = Arrays.asList(student1,student2,student3, student4);

        // 调用写好的静态排序
        students.sort((s1, s2) -> Student.compareStudentByScore(s1,s2));
        students.sort(Student::compareStudentByScore);
        students.forEach(student -> System.out.println(student.getName()));

        System.out.println("----------------");

        // 将调用的静态排序改成方法引用
        students = Arrays.asList(student1,student2,student3, student4);
        students.sort(Student::compareStudentByScore);
        students.forEach(student -> System.out.println(student.getName()));
    }

}

4.2 引用名(对象名):: 实例方法名(非静态方法)

​ 引用名::实例方法名 替换 Lambda 表达式,要求要实例中有一个方法体跟 Lamdba 表达式是客观等价的,就可以被引用。也就是参数列表一致(参数值,参数类型,返回值一致)。与 类::静态方法名 一样。

这里我们需要先建一个补助类,用来放排序的方法,非静态

package cn.zxhysy.jdk8.methodreference;

import java.util.Arrays;
import java.util.List;

public class StudentComparator {

    /** 排序方法 */
    public int compareStudentByScore(Student student1, Student student2){
        return student1.getScore() - student2.getScore();
    }
    /** 根据名字字符比较 */
    public int compareStudentByName(Student student1, Student student2){
        return student1.getName().compareToIgnoreCase(student2.getName());
    }

}

进行测试:

package cn.zxhysy.jdk8.methodreference;

import java.util.Arrays;
import java.util.List;

public class MethodReferenceTest2 {

    public static void main(String[] args) {
        Student student1 = new Student("zhangsan",10);
        Student student2 = new Student("lisi",90);
        Student student3 = new Student("wangwu",60);
        Student student4 = new Student("zhaoliu",30);

        List<Student> students = Arrays.asList(student1,student2,student3, student4);

        StudentComparator studentComparator = new StudentComparator();
        // 使用 Lambda 表达式实现
        students.sort((s1 , s2) -> studentComparator.compareStudentByName(s1, s2));
        students.forEach(student -> System.out.println(student.getName()));

        System.out.println("----------------");
        // 使用 对象名::实例方法名 引用
        students = Arrays.asList(student1,student2,student3, student4);
        students.sort(studentComparator::compareStudentByName);
        students.forEach(student -> System.out.println(student.getName()));
    }
}

4.3 类名::实例方法名(非静态方法)*****

​ ·这个比较核心。先说下,我们在Student类中定义的两个静态方法,其实从设计上看,是很有问题的,对象本身就有数据了,还要再接受两个数据给他来比较。应该这样设计,设计一个实例方法,传递一个对象进来,与自己本身对象的属性进行比较后返回值。

​ 根据上面设计,在Student类中添加下面一段代码:

public int compareByScope(Student student){
    return this.getScore() - student.getScore();
}

public int compareByName(Student student){
    return this.getName().compareToIgnoreCase(student.getName());
}

测试:

package cn.zxhysy.jdk8.methodreference;

import java.util.Arrays;
import java.util.List;

public class MethodReferenceTest3 {

    public static void main(String[] args) {
        Student student1 = new Student("zhangsan",10);
        Student student2 = new Student("lisi",90);
        Student student3 = new Student("wangwu",60);
        Student student4 = new Student("zhaoliu",30);
        List<Student> students = Arrays.asList(student1,student2,student3, student4);

        // 使用 Lambda 表达式进行比较
        students.sort((s1, s2) -> s1.compareByName(s2));
        students.forEach(student -> System.out.println(student.getName()));

        System.out.println("----------------");
        // 使用 类名::实例方法名 引用
        students = Arrays.asList(student1,student2,student3, student4);
        students.sort(Student::compareByName);
        students.forEach(student -> System.out.println(student.getName()));

    }

}

​ 看到这里,大家应该有疑惑 compareByName()方法只接受一个参数,那sort() 需要的是两个参数,根本对不上。我们就需要理清楚到底是谁调用了compareByName 方法,类名肯定调用不了。我们知道,实例方法是由对象调用的,那么有可能的就是 sort 方法里面的参数调用了该方法,与另一个参数对比。

​ 事实上,compareByName 是由 sort 方法的第一个参数进行调用,之后 sort 方法的所有参数,作为 compareByName 方法参数。

​ 类::实例方法引用,原理上就是 引用处的第一个参数作为对象调用实例方法,其他参数,则作为实例方法的参数。

4.4 类名::new 构造方法引用

​ 构造方法本身是可以重载的,但编译工具在引用时自己会识别的。

package cn.zxhysy.jdk8.methodreference;

import java.util.function.Function;
import java.util.function.Supplier;

public class MethodRefernceTest4 {

    public String getString(Supplier<String> supplier){
        return supplier.get() + "test";
    }

    public String getString(String str, Function<String, String> function){
        return function.apply(str);
    }

    public static void main(String[] args) {

        MethodRefernceTest4 methodRefernceTest4 = new MethodRefernceTest4();
        System.out.println(methodRefernceTest4.getString(String :: new));
        // 带参数
 System.out.println(methodRefernceTest4.getString("hello", String::new));
    }

}

这里,推荐使用 idea 编程工具,在对 lambda 表达式的支持上相当给力,可以给你的代码提供优化的选择方案,让你的代码更为漂亮。

你可能感兴趣的:(java)