作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
上期文章:JAVASE进阶:一文精通Stream流+函数式编程
订阅专栏:JAVASE进阶
希望文章对你们有所帮助
相信大家都会用mybatis-plus,但可能只会用其中的一些简单增删改查,想要将mybatis-plus学深入,需要学会方法引用,这是一个很重要的内容。
方法引用:把已经存在的方法拿过来用,当作函数式接口中抽象方法的方法体
对于数组排序,可以使用匿名内部类,也可以利用lambda表达式来简化,同时还可以使用方法引用Arrays.sort(arr, 比较规则)
,需要满足以下要求:
1、引用出处必须是函数式接口
2、被引用的方法必须存在
3、被引用方法的形参和返回值需要跟抽象方法一致
4、被引用的方法的功能要满足当前需求,这个方法应该要与匿名内部类一致(形参类型、返回值)
这里直接贴一个例子:
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;
}
}
其中,::
表示方法引用符
格式为类名::静态方法
,例如Integer::parseInt
做一个小demo,把List中的"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);
}
}
可以看到,Integer::parseInt
在这里比lambda表达式的s->Integer.parseInt(s)
还要便捷,但需要保证Integer类中的parseInt确实是传入String转化为int类型的,即可直接使用。
引用成员方法的基本格式为对象::成员方法
,这个对象的来源不同,方法的格式具体写法也会有一些区别:
1、其他类:其他类对象::方法名
2、本类:this::方法名
3、父类: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关键字也是可以的,但是必须保证引用出不能是静态方法
!因为在静态方法中,是不可能有this和super的。
引用本类:this::方法名
引用父类:super::方法名
引用构造方法就是为了创建这个类的对象,其格式为类型::new
,比如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);
}
}
而如果要使用方法引用,必须要满足那4点要求,然而在这里却不满足被引用方法的形参和返回值,需要跟抽象方法的形参返回值保持一致
的要求,这里的形参是String,返回值为Student类型,所以Student中需要专门有一个形参为String类型的构造方法,这种构造方式和一般的方式还是有点不一样的:
这样子,使用引用方法就不会再报错:
List<Student> newList = list.stream().map(Student::new).collect(Collectors.toList());
格式为类名::成员方法
,例如String::substring
,如下例中对集合中的一些字符串变成大写并输出:
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
,例如int[]::new
,做一个练习:集合中存储一些整数,收集到数组中去。
在这里肯定是只能使用toArray方法了,这种方法感觉用的还是有点少的,但是也肯定要掌握以下。
首先编写一下匿名内部类,这一块要是基础不是特别扎实的话也还是要捣鼓一会的:
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));
}