目录
方法引用(method reference):
实际上是 lambda 表达式的一种语法糖。可以将方法引用看作为一个 函数指针(function pointer),对于方法引用来说,所使用的 lambda 表达式的实现恰好有一个完成相同功能的对应的方法。方法引用分为左右两个部分,通过两个连在一起的冒号(::) 进行分割, 而方法引用分为以下四种类型:
- 类名::静态方法名
- 引用名(实例对象的引用名字)::实例方法名
- 类名::实例方法名
- 类名::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(流)。