四:java-lambda 之方法引用

目录

 

方法引用(method reference):

类名::静态方法名

引用名(实例对象的引用名字)::实例方法名

类名::实例方法名

类名::new(构造方法引用)


方法引用(method reference):

实际上是 lambda 表达式的一种语法糖。可以将方法引用看作为一个 函数指针(function pointer),对于方法引用来说,所使用的 lambda 表达式的实现恰好有一个完成相同功能的对应的方法。方法引用分为左右两个部分,通过两个连在一起的冒号(::) 进行分割, 而方法引用分为以下四种类型:

  1. 类名::静态方法名
  2. 引用名(实例对象的引用名字)::实例方法名
  3. 类名::实例方法名
  4. 类名::new(构造方法引用)

类名::静态方法名

该类型的方法引用适用于通过一个类的类名去调用该类中静态方法的情景

public class Test {
    public static void main(String[] args) {
        List<Student> list = Arrays.asList(
                new Student("zs", 18),
                new Student("ls", 25),
                new Student("ww", 22),
                new Student("zl", 19));

        // 创建一个比较器
        Comparator<Student> s = new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.age - o2.age;
            }
        };

        // Comparator 是一个函数式接口, 所以可以将其转变为以下形式进行书写
        s = (o1, o2) -> o1.age - o2.age;

        // Comparator 的函数式方法是接收两个参数, 并返回一个 int 值,
        // 可以看到该比较器内部代码与 Student.staticSortByAge 方法功能一致
        s = Student::staticSortByAge;
        list.sort(s);
        // 这也是一种方法引用
        list.forEach(System.out::println);
    }
}

class Student {
    String name;

    int age;

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

    public static int staticSortByAge(Student student1, Student student2) {
        return student1.age - student2.age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

引用名(实例对象的引用名字)::实例方法名

与 (类名::静态方法名)的使用方式类似,区别有两点,一个是方法是否为静态的,还有一个是区别是以类的实例名字去调用,而非是用类名去调用

public class Test {
    public static void main(String[] args) {
        List<Student> list = Arrays.asList(
                new Student("zs", 18),
                new Student("ls", 25),
                new Student("ww", 22),
                new Student("zl", 19));

        Student student = new Student();
        // 需要注意的是这里是以实例名的方式调用的
        list.sort(student::sortByAge);

        // 这种书写方式也是可以的, 实际使用任意一种即可
        list.sort(list.get(0)::sortByAge);
        list.forEach(System.out::println);
    }
}

class Student {
    private String name;

    private int age;

    public Student() {
    }

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

    // 注意这里的方法是非 static 的, 还有不用在意这个方法是否应该放在这里, 这里只是做演示
    public int sortByAge(Student student, Student student2) {
        return student.age - student2.age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

类名::实例方法名

这种方式是比较难以理解的,第一个参数为调用者的实例来进行填充,第二个参数才是真正需要传入的值(以后的所有参数都是需要传入的)。

public class Test {
    public static void main(String[] args) {
        List<Student> list = Arrays.asList(
                new Student("zs", 18),
                new Student("ls", 25),
                new Student("ww", 22),
                new Student("zl", 19));

        // 首先通过 lambda 表达式的方式来创建一个比较器.
        Comparator<Student> comparator = (o1, o2) -> o1.age - o2.age;

        // 但是这种书写方式也是可以的, 但是函数式接口是需要两个参数的, 而实例的
        // sortByAge 方法只有一个参数, 那是因为第一个参数就是方法的调用者. 也就是 this.
        list.sort(Student::sortByAge);
        list.forEach(System.out::println);
    }
}

class Student {
    String name;

    int age;

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

    public int sortByAge(Student student) {
        return this.age - student.age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

如果还是觉得难以理解,那么将代码改造一下,即:

public class Test {
    public static void main(String[] args) {

        Student student = new Student("zs", 18);
        System.out.println(student);

        // 通过 lambda 来构建函数式接口 TestInterface 的实例
        TestInterface testInterface = (Student d, String name, int age) -> {
            d.updateInfo(name, age);
        };

        // 可以简写成为
        testInterface = (d, name, age) -> d.updateInfo(name, age);

        // 而通过方法引用的方式可以修改成为如下形式
        testInterface = Student::updateInfo;

        // 现在调用函数式接口
        testInterface.set(student, "ls", 80);
        System.out.println(student);
    }
}

interface TestInterface {
    // 新创建一个函数式接口, 需要传递三个参数, 需要修改属性的对象, 以及需要修改的具体内容值
    void set(Student d, String name, int age);
}

class Student {
    private String name;

    private int age;

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

    public void updateInfo(String name, int age) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

 

类名::new(构造方法引用)

该方法引用是一种极其简单的引用。其实就是调用的类的构造器去创建的,至于参数编译器会自动进行匹配,如果能匹配成功则编译通过,否则编译报错。参数不同返回的函数式接口实例也就不一样

public class Test {
    public static void main(String[] args) {

        // lambda 的书写形式为
        Supplier<Student> student = () -> new Student();

        // 方法引用的书写形式为
        student = Student::new;

        //  当有一个参数的时候 lambda 的书写形式为
        Function<String, Student> stringFunction = str -> new Student(str);

        // 方法引用的书写形式为
        stringFunction = Student::new;
        
    }
}

class Student {
    public Student() {
    }

    public Student(String s1) {
    }
}

通过方法引用的学习,作者认为,方法引用虽然可以简化代码的书写的数量,但是却让程序变得更加难以理解,它并没有 lambda 那么直观明了,所以我们不必要刻意去使用方法引用。

lambda 表达式到目前为止已经全部完毕了,接下来就是 stream(流)。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值