概述
方法引用:把已经存在的方法拿过来用,当作函数式接口中抽象方法的方法体
方法引用符: ::
注意:
1、引用出处必须是函数式接口
2、被引用的方法必须存在
3、被引用方法的形参和返回值需要跟抽象方法一致
4、被引用的方法的功能要满足当前需求,这个方法应该要与匿名内部类一致(形参类型、返回值)
eg:
public class ArrayTest {
public static void main(String[] args) {
Integer[] arr = {3, 5, 4, 1, 6, 2};
Arrays.sort(arr, ArrayTest::subtraction);
System.out.println(Arrays.toString(arr));
}
public static int subtraction(int num1, int num2){
return num2 - num1;
}
}
引用静态方法
格式:类名::静态方法
eg:Integer::parseInt
练习:把集合中的"1",“2”,“3”,“4”,"5"变为int类型:
public class ArrayTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(list, "1","2","3","4","5");
List<Integer> list1 = list.stream().map(Integer::parseInt).collect(Collectors.toList());
System.out.println(list1);
}
}
引用成员方法
格式:对象::成员方法
- 其他类:
其他类对象::方法名
- 本类:
this::方法名
- 父类:
super::方法名
引用其他类的成员方法
格式:其他类对象::方法名
练习:将集合中的的名字进行过滤,留下以"张"开头的,并且名字是3个字的。
可以先写匿名内部类:
list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length()==3&&s.startsWith("张");
}
}).forEach(s-> System.out.println(s));
观察这个匿名内部类重写方法中的形参为String类型,返回值为boolean类型的,但是java并没专门提供这样的方法,所以不能直接使用,因此我们可以新建一个类:
public class StringOperation {
public boolean stringJudge(String s){
return s.startsWith("张")&&s.length()==3;
}
}
现在就可以引用这个成员方法了,但是需要注意,这里的方法不是静态方法,所以需要用对象调用成员方法,不是直接用类来调用的,需要创建这个对象出来:
list.stream().filter(new StringOperation()::stringJudge).forEach(s-> System.out.println(s));
引用本类和父类成员方法
注意:引用处不能是静态方法,因为在静态方法中,没有this和super
。
引用本类:this::方法名
引用父类:super::方法名
引用构造方法
格式:类型::new
eg:Student::new
练习:在集合中存储姓名和年龄,将数据封装为Student对象并收集到List集合中。
先试用匿名内部类编写代码:
public class demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌,15", "吗喽,13", "张三丰,100", "张良,35");
List<Student> newList = list.stream().map(new Function<String, Student>() {
@Override
public Student apply(String s) {
return new Student(s.split(",")[0], Integer.parseInt(s.split(",")[1]));
}
}).collect(Collectors.toList());
System.out.println(newList);
}
}
形参是String,返回值为Student类型,所以Student中需要专门有一个形参为String类型的构造方法,这种构造方式和一般的方式还是有点不一样的:
public student(string s){
this.name = s.split( regex:",")[0];
this.age = Integer.parseInt(s.split( regex:",")[1]);
}
List<Student> newList = list.stream().map(Student::new).collect(Collectors.toList());
其他调用方式
使用类名引用成员方法
格式:类名::成员方法
,
eg:String::substring
,
抽象方法形参的详解:
第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法
在 Stream 流当中,第一个参数一般都表示流里面的每一个数据。
假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用 String 这个类中的方法
第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法
局限性:
不能引用所有类中的成员方法。
是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法。
练习:对集合中的一些字符串变成大写并输出:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "aaa", "bbb", "ccc");
List<String> newList = list.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println(newList);
}
引用数组的构造方法
格式:数据类型[]::new
eg:int[]::new
练习:集合中存储一些整数,收集到数组中去。
细节:
数组的类型,需要跟流中数据的类型保持一致。
首先编写一下匿名内部类:
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5);
Integer[] arr = list.stream().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
//System.out.println(value);
return new Integer[value];
}
});
System.out.println(Arrays.toString(arr));
}
注意,IntFunction中的泛型装的是要处理的数据类型,这里放了一堆的整数可以当作是Integer[],注意不能写int不然会报错。
apply中的value不是指元素值,而是这个数组的长度,因此需要返回Integer[value]。
因此转换为方法引用的代码如下所示,由于上面的形参必须是Integer[]类型的,所以这边也不能用int[]
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));
}
练习
1.集合中存储一些字符串的数据,比如:张三,23。
收集到 Student 类型的数组当中
public Student(String s){
this.name=s.split(",")[0];
this.age=Integer.parseInt(s.split(",")[1]);
}
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
Collections.addAll(list,"张无忌,15","周芷若,14","赵,13","张强,20","张三丰,100","张翠山,40","张良,35","王二麻子,37");
Student[] array = list.stream()
.map(Student::new)
.toArray(Student[]::new);
System.out.println(Arrays.toString(array));
}
2.需求:
创建集合添加学生对象
学生对象属性:name,age
要求:
获取姓名并放到数组当中
使用方法引用完成
技巧:
- 现在有没有一个方法符合我当前的需求
- 如果有这样的方法,这个方法是否满足引用的规则
静态方法:类名::方法名
成员方法:对象::方法名
类名::方法名
构造方法:类名::new
数据类型::new
public static void main(String[] args) {
ArrayList<Student> list=new ArrayList<>();
list.add(new Student("zhangsan",23));
list.add(new Student("lisi",24));
String[] array = list.stream()
.map(Student::getName)
.toArray(String[]::new);
System.out.println(Arrays.toString(array));
}