在开始之前,让我们高喊我们的口号:
键盘敲烂,年薪百万!
我听说关注我的人未来都会暴富哦!
目录
方法引用概述
方法引用是什么?
把已经有的方法拿过来用,当做函数式接口中抽象方法的方法体。
::是什么符号
方法引用符号
方法引用的时候要注意什么?
- 需要有函数式接口:函数式接口是指仅包含一个抽象方法的接口。抽象方法是指只有方法声明而没有方法体的方法。不过,函数式接口可以包含默认方法(有方法体的实例方法)、静态方法和
Object
类的公共方法。 - 被引用方法必须已经存在
- 被引用方法的形参和返回值需要跟抽象方法保持一致
- 被引用方法的功能要满足当前的需求
引用静态方法
分类
- 引用静态方法:引用其他类、本类、父类的成员方法
- 引用成员方法:引用其他类、本类、父类的成员方法
- 引用构造方法:引用其他类、本类、父类的成员方法
- 其他调用方法:使用类名引用成员方法;引用数组的构造方法
两个小练习:
练习一:
public class FunctionDemo1 {
public static void main(String[] args) {
//需求:创建一个数组进行倒序排列(不是1,3,2变成2,3,1。而是1,3,2变成3,2,1)
//1.新建一个数组,为什么要用Integer类型的数组?因为Arrays.sort()方法,如果传入的是基本数据类型则只能升序排列。要自定义排序则要传入comparator的数组对象到sort()方法里面。因此这里要自定义排序,所以用Integer
//2.准备一些数放进数组、
//3.倒序排列
//方法一:
// 3.1调用Arrays.sort()传入数组和比较器(comparator)。比较器用匿名内部类完成。
// 3.2简化为lambda表达式
// 3.3输出打印sout(Arrays.toString(arr)
//这个方法只是实现了倒过来,132->231
//方法二:
// 3.1主方法之外,类之内去写一个和重写的
Integer[] arr = {3,5,4,1,6,2};
//Comparator接口的作用:核心作用是通过实现compare(T o1, T o2)方法,
// 为对象提供独立于其自然顺序的比较规则。注意不要把o写成0
// Arrays.sort(arr, new Comparator<Integer>() {
// @Override
// public int compare(Integer o1, Integer o2) {
// return 02 - 01;
// }
// });
//优化
//Arrays.sort(arr, (o1, o2) ->o2 - o1);
//方法引用
//1.引用处需要是函数式接口
//2.被引用的方法需要已经存在
//3.被引用方法的形参和返回值需要跟抽象方法的形参和返回值保持一致
//4.被引用方法的功能需要满足当前的要求
//表示引用FunctionDemo1类里面的subtraction方法
//把这个方法当做抽象方法的方法体
Arrays.sort(arr,FunctionDemo1::subtraction);
System.out.println(Arrays.toString(arr));
}
//可以是Java已经写好的,也可以是一些第三方的工具类
//当你使用静态方法引用时,Java 会把静态方法的参数和返回值类型与Comparator接口里的compare方法进行匹配。
public static int subtraction(int num1,int num2){
return num2 - num1;
}
}
练习二:
public class FunctionDemo2 {
public static void main(String[] args) {
/*
方法引用(引用静态方法)
格式
类::方法名
需求:
集合中有以下数字,要求把他们都变成int类型
"1","2","3","4","5"
*/
//思路:
//1.创建一个集合
//2.把字符类型的元素放进集合当中
//3.转换成int类型并输出
ArrayList<String> list = new ArrayList<>();
// list.add("1");
// list.add("2");
// list.add("3");
// list.add("4");
// list.add("5");
Collections.addAll(list, "1", "2", "3", "4", "5");
// 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));
//优化
//因为本身有parseInt这个,所以不必自己再重新写个方法
//这里为什么要写s->是因为parseInt底层就是传的s
//进入parseInt方法:
// public static int parseInt(String s) throws NumberFormatException {
// return parseInt(s,10);
// }
list.stream()
.map(Integer::parseInt)
.forEach(s -> System.out.println(s));
}
}
引用成员方法
格式:对象::成员方法
- 其他类:其他类对象 :: 方法名
- 本类:this :: 方法名,引用处不能是静态方法
- 父类:super :: 方法名,引用处不能是静态方法
一个小练习:
public class FunctonDemo3 {
public static void main(String[] args) {
/*
方法引用(引用成员方法)
格式
其他类:其他类对象::方法名
本类:this::方法名(引用处不能是静态方法)
父类:super::方法名(引用处不能是静态方法)
需求:
集合中有一些名字,按照要求过滤数据
数据:"张无忌","周芷若","赵敏","张强","张三丰"
要求:只要以张开头,而且名字是3个字的
*/
//思路:
//1.创建一个集合
//2.把这些名字存放进集合当中
//3.filter过滤保留张开头,且长度为3的名字。打印
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");
/*方法一:list.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张") && s.length() == 3;
}
}).forEach(s-> System.out.println(s));
*/
/*
方法二:
1.创建一个StringOperation的类
2.在StringOperation类当中写一个方法:
public boolean stringJudge(String s){
return s.startsWith("张") && s.length() == 3;
}
3.new一个StringOperation对象
4.用 类名::方法 调用然后打印
StringOperation so = new StringOperation();
list.stream()
.filter(so::stringJudge)
.forEach(s-> System.out.println(s));
}
*/
/*
方法三:
在本类当中写一个方法调用
*/
list.stream()
.filter(new FunctonDemo3()::stringJudge)
.forEach(s-> System.out.println(s));
}
public boolean stringJudge(String s) {
return s.startsWith("张") && s.length() == 3;
}
}
引用构造方法:
格式:类名 :: new
范例:Student :: new
一个小练习:
public class FunctionDemo4 {
public static void main(String[] args) {
/*
方法引用(引用构造方法)
格式
类名::new
目的:
创建这个类的对象
需求:
集合里面存储姓名和年龄,要求封装成Student对象并收集到List集合中
方法引用的规则:
1.需要有函数式接口
2.被引用的方法必须已经存在
3.被引用方法的形参和返回值,需要跟抽象方法的形参返回值保持一致
4.被引用方法的功能需要满足当前的需求
*/
/*
思路:
1.创建一个集合
3.封装成Student对象并收集到List集合中。String-->Student
4.打印输出
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "张无忌,15", "周芷若,14", "赵敏,13", "张强,20", "张三丰,100", "张翠山,40", "张良,35", "王二麻子,37", "谢广坤,41");
// 方法一:
// List<Student> newList = list.stream().map(new Function<String, Student>() {
// @Override
// public Student apply(String s) {
// String[] arr = s.split(",");
// String name = arr[0];
// int age = Integer.parseInt(arr[1]);
// return new Student(name, age);
// }
// }).collect(Collectors.toList());
// System.out.println(newList);
//注意:这里new会报错,因为Student类当中没有对应的构造方法,所以要到Student类当中去写对应的构造方法。
List<Student> newList2 =list.stream().map(Student::new).collect(Collectors.toList());
System.out.println(newList2);
}
}
使用类名引用成员方法
格式:类名 :: 成员方法
范例:String :: substring
public class FunctionDemo5 {
public static void main (String[] args) {
/*
方法引用(类名引用成员方法)
格式
类名::成员方法
需求:
集合里面一些字符串,要求变成大写后进行输出
方法引用的规则:
1.需要有函数式接口
2.被引用的方法必须已经存在
3.被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致。
4.被引用方法的功能需要满足当前的需求
抽象方法形参的详解:
第一个参数:表示被引用方法的调用者,决定了可以引用哪些类中的方法
在Stream流当中,第一个参数一般都表示流里面的每一个数据。
假设流里面的数据是字符串,那么使用这种方式进行方法引用,只能引用String这个类中的方法
第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法
局限性:
不能引用所有类中的成员方法。
是跟抽象方法的第一个参数有关,这个参数是什么类型的,那么就只能引用这个类中的方法。
*/
/*思路:
1.创建一个集合
2.把字符串放进集合当中去
3.把字符串变成大写后输出
*/
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"aaa","bbb","ccc");
// list.stream().map(new Function<String, String>() {
// @Override
// public String apply(String string) {
// return string.toUpperCase();
// }
// }).forEach(s-> System.out.println(s));
//优化
list.stream().map(String :: toUpperCase).forEach(s-> System.out.println(s));
}
}
引用数组的构造方法
格式:数据类型[] :: new
范例:int[] :: new
public class FunctionDemo6 {
public static void main(String[] args) {
/*
方法引用(数组的构造方法)
格式
数据类型[]::new
目的:
创建一个指定类型的数组
需求:
集合中存储一些整数,收集到数组当中
细节:
数组的类型,需要跟流中数据的类型保持一致。
*/
/*
思路:
1.创建一个集合
2.存一些整数到集合当中
3.收集到数组当中
4.打印
*/
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) {
// return new Integer[value];
// }
// });
//优化
Integer[] arr2 = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(arr2));
}
}
总结
- 引用静态方法。类名 :: 静态方法
- 引用成员方法。对象 :: 成员方法;this :: 成员方法;super :: 成员方法
- 引用构造方法。类名 :: new
- 使用类名引用成员方法。类名 :: 成员方法。注意:不能引用所有类中的成员方法,如果抽象方法的第一个参数是A类型的,只能引用A类中的方法。
- 引用数组的构造方法。 数据类型[] :: new
补充知识:Lambda表达式的写法
public class LambdaDemo4 {
public static void main(String[] args) {
/*
定义数组并存储一些字符串,利用Arrays中的sort方法进行排序
要求:
按照字符串的长度进行排序,短的在前,长的在后
(暂时不比较字符串里面的内容)
*/
String[] arr = {"a","aaaa","aaa","aa"};
//如果以后我们要把数组中的数据按照指定的方式进行排列,而且要指定排序的规则
/*Arrays.sort(arr, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});*/
//lambda完整格式
// Arrays.sort(arr,(String o1, String o2) -> {
// return o1.length() - o2.length();
// }
// );
//lambda的简写格式
//小括号:数据类型可以省略,如果参数只有一个,小括号还可以省略。
//大括号:如果方法体只有一行,return,分号,大括号都可以省略
Arrays.sort(arr,(o1, o2) -> o1.length() - o2.length());
//打印数组
System.out.println(Arrays.toString(arr));
}
}
好啦,今天的分享就到这里,欢迎在评论区评交流,一起进步一起学习
如果你能关注我,那就是对我创作的最大鼓励啦!