欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

Java8新特性:方法引用

时间:2023-07-04

一、什么是方法引用?

当我们在写代码的时候,发现方法的入参是一个函数接口,比如我们在对数组进行排序,需要使用Arrays.sort(T[] a, Comparator<? super T> c)方法,此时Comparator是一个函数接口,在没有lambda的情况下,我们需要提供一个匿名内部类来实现Comparator接口,在Java 8中可以通过lambda表达式来实现,如果我们的代码中已经有一个类实现了Comparator接口,那么是否可以直接使用该类实现的compare方法呢?答案是可以的,这就是方法引用存在的意义,方法引用是用来直接访问类或者实例已经存在的方法或者构造方法,如果某个方法签名和接口恰好一致,就可以直接传入方法引用,恰好一致要求除了方法名外,方法参数一致且返回类型相同。计算时,方法引用会创建函数式接口的一个实例。

二、使用方法引用的好处?

1、方法引用的唯一用途是支持Lambda的简写。

2、方法引用提高了代码的可读性,也使逻辑更加清晰。

三、语法:

1、使用::操作符将方法名和类或者实例的名字分隔开

四、分类:

1、类名::静态方法名

2、对象::实例方法名

3、类名::实例方法名

4、类名::new

五、举例:

定义一个Student类:

import java.util.Arrays;import java.util.List;public class Student { private String name; private int score; public Student(){ } 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.getScore() - student2.getScore(); }}

现在有一批学生,需要我们按着分数由小到大排列并输出

1、首先我们使用lambda表达式的方式处理:

public static void main(String[] args) { Student student1 = new Student("zhangsan",60); Student student2 = new Student("lisi",70); Student student3 = new Student("wangwu",80); Student student4 = new Student("zhaoliu",90); List students = Arrays.asList(student1,student2,student3,student4); students.sort((o1, o2) -> o1.getScore() - o2.getScore()); students.forEach(student -> System.out.println(student.getScore())); }

2、【类名::静态方法名】此时我们发现Student类的compareStudentByScore方法与compare方法签名是一致的, 所有我们可以使用方法引用来改写:

public static void main(String[] args) { Student student1 = new Student("zhangsan",60); Student student2 = new Student("lisi",70); Student student3 = new Student("wangwu",80); Student student4 = new Student("zhaoliu",90); List students = Arrays.asList(student1,student2,student3,student4); students.sort((o1, o2) -> o1.getScore() - o2.getScore()); students.forEach(student -> System.out.println(student.getScore())); students.sort(Student::compareStudentByScore); students.forEach(student -> System.out.println(student.getScore())); }

3、【对象::实例方法名】我们在Student里面增加一个实例方法,与静态方法一样:

public int compareStudent(Student student1,Student student2){ return student1.getScore() - student2.getScore(); }

然后我们代码可以这样写,这里用的是student1,其实用这四个中的任何一个都是可以的:

public static void main(String[] args) { Student student1 = new Student("zhangsan",60); Student student2 = new Student("lisi",70); Student student3 = new Student("wangwu",80); Student student4 = new Student("zhaoliu",90); List students = Arrays.asList(student1,student2,student3,student4); students.sort((o1, o2) -> o1.getScore() - o2.getScore()); students.forEach(student -> System.out.println(student.getScore())); students.sort(Student::compareStudentByScore); students.forEach(student -> System.out.println(student.getScore())); students.sort(student1::compareStudent); students.forEach(student -> System.out.println(student.getScore())); }

4、【类名::实例方法名】我们从上面看,其实这个实例方法里面调用的时候,实例是知道自己的分数的,那是不是可以不用在定义方法的时候,只定义一个入参,而不是两个,也就是:

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

那要实现排序的需求,代码应该怎么写呢?

public static void main(String[] args) { Student student1 = new Student("zhangsan",60); Student student2 = new Student("lisi",70); Student student3 = new Student("wangwu",80); Student student4 = new Student("zhaoliu",90); List students = Arrays.asList(student1,student2,student3,student4); students.sort((o1, o2) -> o1.getScore() - o2.getScore()); students.forEach(student -> System.out.println(student.getScore())); students.sort(Student::compareStudentByScore); students.forEach(student -> System.out.println(student.getScore())); students.sort(student1::compareStudent); students.forEach(student -> System.out.println(student.getScore())); students.sort(Student::compareByScore); students.forEach(student -> System.out.println(student.getScore())); }

现在我就有点困惑了,sort方法接收的lambda表达式不应该是两个参数么,为什么和int Comparator.compare(Student, Student)能匹配呢?因为实例方法有一个隐含的this参数,在方法实际调用的时候,第一个隐含参数总是传入this,相当于静态方法:public static int compareTo(this, Student o);

5、【类名::new】我们来讲最后一个类型的用法,看下面这个问题,如果要把一个List转换为List,应该怎么办?

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

传统的做法是先定义一个ArrayList,然后用for循环填充这个List:

public static void main(String[] args) { List names = Arrays.asList("zhangsan", "lisi", "wangwu"); List studentList = new ArrayList<>(); for (String name : names) { studentList.add(new Student(name)); } }

要更简单地实现String到Student的转换,我们可以引用Student的构造方法:

public static void main(String[] args) { List names = Arrays.asList("zhangsan", "lisi", "wangwu"); List studentList = new ArrayList<>(); for (String name : names) { studentList.add(new Student(name)); } System.out.println(studentList.size()); List studentList1 = names.stream().map(Student::new).collect(Collectors.toList()); System.out.println(studentList1.size()); }

是不是有点奇怪,现在我们来看一下map()方法的入参FunctionalInterface的定义:

@FunctionalInterfacepublic interface Function { R apply(T t);}

把泛型进行替换以后就是方法签名Student apply(String),即传入参数String,返回类型Student。而Student类的构造方法恰好满足这个条件,因为构造方法的参数是String,虽然构造方法虽然没有return语句,但它会隐式地返回this实例,类型就是Student,因此,此处可以引用构造方法。

六、总结:

1、方法引用是为了简化lambda表达式而出现的

2、类名::实例方法名 比较特殊,需要注意一下,会隐式的传入对象本身

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。