方法引用
简而言之,就是把已经有的方法当作函数式接口中抽象方法的方法体,从而进一步简化代码
一、需要满足的要求:
1、引用的地方必须是函数式接口
2、被引用的方法已经存在
3、被引用的方法形参和返回值必须和抽象方法一致
4、被引用的方法必须要满足当前需求
举个栗子:
//一般重写方法是这样的:
public class A02_Test {
public static void main(String[] args) {
Integer[] arr = {1, 2, 3, 4, 5, 6};
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println(Arrays.toString(arr));//[6, 5, 4, 3, 2, 1]
}
}
//使用lambda表达式简化可以写成:
public class A02_Test {
public static void main(String[] args) {
Integer[] arr = {1, 2, 3, 4, 5, 6};
Arrays.sort(arr, (o1, o2) -> o2 - o1);
System.out.println(Arrays.toString(arr));
}
}
//使用引用方法的写法:
public class A02_Test {
public static void main(String[] args) {
Integer[] arr = {1, 2, 3, 4, 5, 6};
Arrays.sort(arr, A02_Test::subtraction);//满足了四个要求,所以可以使用引用方法,方法引用符号::
System.out.println(Arrays.toString(arr));
}
public static int subtraction(int num1, int num2) {
return num2 - num1;
}
}
二、引用方法的分类
1、引用静态方法
类名::方法名
举个例子:
public class A03_Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3", "4", "5", "6");
list.stream().map(Integer::parseInt).forEach(s -> System.out.println(s));
}
}
2、引用成员方法
① 引用其他类的成员方法
创建这个类的对象,然后用对象::方法名
举个例子:
public class A04_Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
list.stream()
.filter(new StringOperation()::stringJudge)
.forEach(s -> System.out.println(s));
}
}
class StringOperation {
public boolean stringJudge(String s) {
return s.startsWith("张") && s.length() == 3;
}
}
② 引用本类的成员方法
this::方法名(注意此时的方法不能为静态的方法,静态方法需要使用静态的引用方式,即类名::方法名)
懒得举例子
③ 引用父类的成员方法
super::方法名(注意此时的方法不能为静态的方法,静态方法需要使用静态的引用方式,即类名::方法名)
懒得举例子
3、引用构造方法
类名::new
注意需要重载构造方法,stream中的抽象方法的参数为一个字符串,为了满足引用规则,必须重载构造方法满足四个条件之一的“形参一致”条件
而虽然构造方法没有返回值,但是构造方法的本质就是创建一个对象,所以是可以看作一致的
public class A05_Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌,15", "周芷若,14", "赵敏,13", "张强,20", "张三丰,100", "张翠山,40", "张良,35", "王二麻子,37");
List<Student> students = list.stream().map(Student::new).collect(Collectors.toList());
System.out.println(students);
}
}
class Student {
private String name;
private int age;
public Student() {
}
public Student(String s) {
this.name = s.split(",")[0];
this.age = Integer.parseInt(s.split(",")[1]);
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
4、其他调用方式
① 使用类名引用成员方法
类名::成员方法
这是一种特殊的情况,当stream流中数据类型和类名一致的时候,可以使用这种方法,此时的引用方法只需要和除去第一个形参后的抽象方法形参一致即可。如果抽象方法只有一个形参,那么引用方法必须是无参。
举个例子:
public class A06_Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "aaa", "bbb", "ccc", "ddd");
list.stream().map(String::toUpperCase).forEach(s -> System.out.println(s));
}
}
② 引用数组的构造方法
数据类型[]::方法名
public class A07_Test {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5);
Integer[] arr = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(arr));
}
}