方法引用也是Java8新增加的一个概念。它能够使代码更加的简洁。
那么什么是方法引用呢?
其实,方法引用就是Lambda表达式,就是函数式接口的一个实例,可以认为是Lambda表达式的一个语法糖。但是,并不是所有的Lambda表达式都可以使用方法引用来表示,需要满足一定的条件(抽象接口的实现需满足一定的条件),才能使用方法引用表示。
我们可以把方法引用理解为方法的指针,指向的是另外一个方法。也就是说,如果抽象方法的实现恰好可以使用调用另外一个方法来实现,就有可能可以使用方法引用。注意是有可能。下面就对方法引用来进行介绍。
方法引用总共分为4类:
1. 类名::静态方法名
如果函数式接口的抽象方法的实现刚好可以通过调用一个静态方法来实现,那么就可以使用该类型的方法引用。例如,一个Integer类型集合,现在需要把它转换成对应的String类型的集合,就可以使用下面的代码:
List<Integer> list = Arrays.asList(1, 2, 3, 4);
List<String> strList = list.stream()
.map(String::valueOf)
.collect(Collectors.toList());
上面的map方法参数是Function类型的,把Integer类型转换成对应的String类型,Java中已经有现成的静态方法String.valueOf(int i)可以实现了,因此可以使用方法引用。更加的简洁。
2. 对象名::实例方法名
如果函数式接口的抽象方法的实现刚好可以通过调用一个实例的实例方法来实现,那么就可以使用该类型的方法引用。下面给出一个例子:
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 int compareByScore(Student student1, Student student2) {
return student1.getScore() - student2.getScore();
}
public int compareByName(Student student1, Student student2) {
return student1.getName()
.compareToIgnoreCase(student2.getName());
}
}
然后定义一个Student集合,让集合按照学生名字进行排序:
Student student1 = new Student("zhangsan", 10);
Student student2 = new Student("lisi", 90);
Student student3 = new Student("wangwu", 50);
Student student4 = new Student("zhaoliu", 40);
List<Student> students = Arrays.asList(student1, student2, student3, student4);
students.sort(student1::compareByName);
3. 类名::实例方法名
1、引用处是函数式接口(也是可以写成lambda表达式的一个条件 )
2、被引用的方法必须是已经存在的,不存在的话还要自己写
3、被引用的方法的形参和返回值需要和抽象方法的保持一致
4、被引用的方法要满足当前的需求
5、抽象方法形参的详解
- 第一个参数表示是引用方法的调用者,决定了可以引用那些方法,在stream流中第一个参数一般表示的是流里面的每一个数据。假设流里面的数据是字符串,那么使用这种方式的方法引用,只能引用String这个类中的方法。
- 第二个参数到最后一个参数:是跟引用放法的形参保持一致,如果没有第二个参数,说明被引用的方法是需要无参数的成员方法。
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 int compareByScore(Student student) {
return this.getScore() - student.getScore();
}
public int compareByName(Student student) {
return this.getName()
.compareToIgnoreCase(student.getName());
}
然后定义一个Student集合,让集合按照学生名字进行排序:
//案例一:按名字排序
Student student1 = new Student("zhangsan", 10);
Student student2 = new Student("lisi", 90);
Student student3 = new Student("wangwu", 50);
Student student4 = new Student("zhaoliu", 40);
List<Student> students = Arrays.asList(student1, student2, student3, student4);
students.sort(Student::compareByName);
//案例二:转换成大小
//创建集合
ArrayList<String> list =new ArrayList<>();
Collections.addAll(list,"aaa","bbb","ccc","ddd","eee","fff");
//数据流
list.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(s -> System.out.println(s));
//相当于流里面的每一个数据都去调用同UpperCase这方法,然后方法的返回值就是String类型的
list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));
其实就是调用了compare方法的第一个参数Student实例的compareByName方法,第二个参数作为compareByName方法的参数,来当做compare方法的实现逻辑。
4. 构造方法引用: 类名::new
如果函数式接口的抽象方法的实现刚好可以通过调用一个类的构造方法来实现,那么就可以使用该类型的方法引用。
注意:数组的类型要和流里面的数据类型一致!
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.function.IntFunction;
public class 引用数组的构造方法 {
public static void main(String[] args) {
//创建集合
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7);
//存入数组
Integer[] array = list.stream().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});
//方法引用
Object[] array1 = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(array1));
}
}