十五、方法引用
方法引用概述
方法引用:把已经有的方法拿过来使用,当作函数式接口中抽象方法的方法体。
//引用处必须是函数式接口
Arrays.sort(arr,比较规则);
//已经存在的方法
//被引用的方法必须已经存在
//被引用的方法的形参和返回值需要跟抽象方法保持一致
//被引用的方法的功能需要满足当前要求
public int substraction(int n1, int n2) {
return n2 - n1;
}
//需求:创建一个数组,进行倒序排序
Integer[] arr = {3,4,5,1,6,23}
//匿名内部类
Arrays.sort(arr, new Comparator<Integer>() {
@Override
pubilc int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
//Lambda表达式
Arrays.sort(arr, (Integer o1, Integer o2) -> {
return o2 - o1;
});
//Lambda表达式简化形式
Arrays.sort(arr, (o1, o2) -> o2 - o1);
//方法引用
Arrays.sort(arr,类名::substraction);
//可以是java写好的代码,也可以是一些第三方工具
public static int substraction(int n1, int n2) {
return n2 - n1;
}
方法引用的分类
- 引用静态方法
- 引用成员方法
- 引用其他类的成员方法
- 引用本类的成员方法
- 引用父类的成员方法
- 引用构造方法
- 其他调用方式
- 使用类名引用成员方法
- 引用数组的构造方法
引用静态方法
格式:类名::静态方法
示例:Integer::parseInt
/*
*需求:把集合中的数据变成int类型。
**/
//1.创建集合并添加元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(arr,"1", "2", "3", "4", "5");
//2.变成int类型
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
int i = Integer.parseInt(s)
return i;
}
}).forEach(s -> System.out.println(s));
list.stream().map(Integer::parseInt).forEach(s -> System.out.println(s));
引用成员方法
格式:对象::成员方法
- 其他类:其他类对象::方法名
- 本类:this::方法名
- 父类:super::方法名
/*
*需求:按一定的要求过滤数据
**/
//1.创建集合并添加元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(arr,"张三三", "张四", "李四", "张五", "李六");
//2.lambda
list.stream()
.filter(s -> s.startwith("张")).filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));
//匿名内部类
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startwith("张") && s.length() == 3;
}
});
//引用成员方法
list.stream().filter(new StringOpreation()::stringJudge);
public class StringOperation {
public boolean stringJudge(String s) {
return s.startwith("张") && s.length() == 3;
}
}
引用构造方法
格式:类名::new
返利:Student::new
/*
*需求:集合存储姓名和年龄,要求封装成Student对象并收集到List集合中
**/
//1.创建集合并添加元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(arr,"张三三,23", "张四,25", "李四,26", "张五,27", "李六,28");
//2.封装成Student对象并收集到List集合中
List<Student> list = list.stream().map(new Function<String, Student>() {//此处Student类已经提前定义好
@Override
public Student apply(String s) {
String name = s.split(",")[0];
int age = Integer.parseInt(s.split(",")[1]);
return new Student(name, age);
}
}).collect(Collections.toList());
list.stream(),map(Student::new);//此时要在student类中完善构造方法
使用类名引用成员方法
格式:类名::成员方法
范例:String::substring
方法引用的规则(独有):
- 需要有函数式接口
- 被引用的方法必须已经存在
- 被引用方法的形参需要和抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致
- 被引用方法的功能需要满足当前的需求
抽象方法形参详解:
- 第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法。在stream流中,第一个参数一般都表示流里面每一个元素。假设流里面的数据都是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法。
- 第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法。
局限性:不能引用所有类中的成员方法,跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法。
/*
*需求:将集合中的元素转成大写后输出
**/
//1.创建集合并添加元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(arr,"aaa", "bbb", "ccc", "ddd");
//2.变成大写后输出
list.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(s -> System.out.println(s));
//3.改写成方法引用
//拿着流里面的每一数组调用toUpperCase方法,方法的返回值就是转换之后的结果。
list,stream().map(String::toUpperCase).forEach(s -> System.out.println(s));
引用数组的构造方法
格式:数据类型[]::new
范例:int[]::new
/*
*需求:集合中存储一些整数,收集到数组当中
**/
//1.创建集合并添加元素
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(arr,1, 2, 3, 4, 5);
//2.收集到数组当中
Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});
//3.改写成方法引用
//数组的类型要和流中数据的类型保持一致。
Integer[] arr = list.stream().toArray(Integer[]::new);