一、什么是方法引用?
其实简单来讲,方法引用就是把已经存在的方法拿过来用,当做函数式接口中抽象方法的方法体。使用方法引用有这么四个必要条件:
- 引用处必须是函数式接口
- 被引用的方法必须已存在
- 被引用方法的形参和返回值需要根抽象方法保持一致
- 被引用方法的功能要满足当前需求
二、方法引用有什么用?
其实方法引用就是用来简化 Lambda
表达式的,虽然 Lambda 表达式在一些场景下也能起到简化的效果,但是还不够 “优雅”,方法引用便是一种简化 Lambda 表达式的跟优雅的写法。
三、方法引用使用
1、引用静态方法
- 语法格式:
类名 :: 静态方法
- 演示范例:
Integer :: parseInt
public static void main(String[] args) { List<String> lists = new ArrayList<>(); Collections.addAll(lists,"1","2","3","4","5"); // 引用静态方法示例: List<Integer> collect = lists.stream().map(Integer::parseInt).collect(Collectors.toList()); System.out.println(collect); }
2、引用成员方法
- 语法格式:
对象 :: 成员方法
具体来说,可分为三类:
- 其他类:
其他类对象 :: 方法名
- 本类:
this :: 方法名
- 父类:
super :: 方法名
其他类:
class StringUtil { public boolean judge(String s) { return s.startsWith("蔡") && s.length() == 3; } } public class OtherClassDemo { public static void main(String[] args) { // 创建集合并填入数据 ArrayList<String> manList = new ArrayList<>(); Collections.addAll(manList, "蔡坤坤", "叶厚贤,", "刘不甜", "吴倩", "蔡加", "蔡亮亮"); // 获取所有以 “蔡” 开头,并且长度为 3 的姓名 manList.stream().filter(new StringUtil()::judge).forEach(System.out::println); } }
本类:
public class ThisAndSuperDemo { private int thisDesc(Integer o1,Integer o2) { return o2 - o1; } private void sortDesc(Integer[] nums) { Arrays.sort(nums,this::thisDesc); } public static void main(String[] args) { Integer[] nums = {1,2,3,4,5}; new ThisAndSuperDemo().sortDesc(nums); System.out.println(Arrays.toString(nums)); } }
父类:
class Father { public int thisDesc(Integer o1,Integer o2) { return o2 - o1; } } public class ThisAndSuperDemo extends Father { private void sortDesc(Integer[] nums) { Arrays.sort(nums,super::thisDesc); } public static void main(String[] args) { Integer[] nums = {1,2,3,4,5}; new ThisAndSuperDemo().sortDesc(nums); System.out.println(Arrays.toString(nums)); } }
3、引用构造方法
- 语法格式:
类名 :: new
- 演示范例:
Student :: new
注:引用构造方法就是为了创建一个对象。
// ... // Actor 中的构造方法 public Actor(String str) { String[] split = str.split(","); this.name = split[0]; this.age = Integer.parseInt(split[1]); } // ... public class StructDemo { public static void main(String[] args) { //创建一个集合,存储多个字符串元素 ArrayList<String> list = new ArrayList<>(); Collections.addAll(list,"张无忌,15","周芷若,14","赵敏,13","张三丰,100","谢广坤,41"); // 将上述字符串封装成 Actor 对象返回 List<Actor> collect = list.stream().map(Actor::new).collect(Collectors.toList()); System.out.println(collect); } }
4. 类名引用成员方法
独有规则:
- 对于抽象方法中的第一个参数,表示被引用方法的调用者,决定了可以引用哪些类中的方法。假设 Stream 流中的数据是字符串,那么使用这种方式,只能引用 String 类中的方法。
- 第二个参数到最后一个参数,跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法。
- 语法格式:
类名 :: 成员方法
- 演示范例:
String :: toUpperCase
public class SpecialDemo { public static void main(String[] args) { // 准备数据 List<String> list = new ArrayList<>(); Collections.addAll(list,"aaa","bbb","ccc"); // 转换成大写并输出 list.stream().map(String::toUpperCase).forEach(System.out::println); } }
5、引用数组的构造方法
- 语法格式:
数据类型[] :: new
- 演示范例:
int[] :: new
注:引用数组的构造方法就是为了创建一个数组。
注:数组的类型需要和流中数据的类型保持一致。
public class ArrayDemo { public static void main(String[] args) { // 1.创建集合并添加元素 List<Integer> list = new ArrayList<>(); Collections.addAll(list,1,2,3,4,5); // 2.收集到数组当中 Integer[] integers = list.stream().toArray(Integer[]::new); System.out.println(Arrays.toString(integers)); } }
小结
Lambda 怎么简化?
- 首先,数据类型可以省略
- 如果形参只有一个,小括号可以省略
- 如果形参有多个,小括号就不能省略了
- 如果方法体只有一行,那么大括号可以省略,return 可以省略分号可以省略
什么是方法引用?
- 把已经存在的方法拿过来用,当做函数式接口中抽象方法的方法体
::
是什么符号?
- 方法引用符
方法引用时需要注意什么?
- 需要有函数式接口
- 被引用方法必须已经存在
- 被引用方法的形参和返回值需要跟抽象方法保持一致
- 被引用方法的功能要满足当前的需求
方法引用的类型?
- 引用静态方法
- 类名::静态方法
- 引用成员方法
- 对象::成员方法
- this::成员方法
- super::成员方法
- 引用构造方法
- 类名::new
- 使用类名引用成员方法
- 类名::成员方法
- 注:不能引用所有类中的成员方法,如果抽象方法中的第一个参数是A类型的,只能引用A类中的方法。
- 引用数组的构造方法
- 数据类型[]::new