# 方法引用
方法引用是把已经有的方法拿过来用 当做函数式接口中抽象方法的方法体
# 引用前提
- 引用处必须是函数式接口
- 被引用的方法必须存在
- 被引用方法的形参和返回值需要跟抽象方法保持一致
- 被引用方法的功能要满足当前需求
package methodReference;
import java.util.Arrays;
import java.util.Comparator;
public class Main {
public static void main(String[] args) {
//方法引用
// 需求: 创建一个数组,进行倒序排列
Integer[] arr = {1, 2, 3, 4};
//匿名内部类
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
System.out.println(Arrays.toString(arr));
//lambda表达式
//因为第二个参数Comparator是一个函数式接口 只有函数式接口才可以使用lambda表达式
Arrays.sort(arr, (o1, o2) -> o2 - o1);
System.out.println(Arrays.toString(arr));
//方法引用
// 1. 引用处必须是函数式接口
// 2. 被引用的方法必须存在
// 3. 被引用方法的形参和返回值需要跟抽象方法保持一致
// 4. 被引用方法的功能要满足当前需求
// ::是方法引用符 存在于方法引用中
Arrays.sort(arr, Main::subtration);
System.out.println(Arrays.toString(arr));
}
//可以使java已经写好的 也可以是第三方的工具类
public static int subtration(Integer o1, Integer o2) {
return o2 - o1;
}
}
# 方法引用的分类
# 引用静态方法
格式:类名::静态方法
范例:Integer::parseInt
# 引用成员方法
格式: 对象::成员方法
- 其他类 其他类对象类名::成员方法名
- 本类 this::成员方法名(引用处不能使用静态方法)
- 父类 super::成员方法名(引用处不能使用静态方法)
# 技巧
- 现在有没有一个方法符合我当前的需求
- 如果有这样的方法,那么这个方法是否满足引用的规则
- 静态: 类名::方法名
- 成员方法 分本类和其他类
- 构造方法 类名::new
package MethodReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;
public class Main {
public static void main(String[] args) {
//引用成员方法
// 需求 集合中有一些名字,按照要求过滤数据
// 数据:“张三","李四","王五","赵六","孙七","周八","吴九","郑十"
// 过滤要求:只要张开头,而且名字是三个字的
ArrayList<String> listName = new ArrayList<>();
Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
//过滤数据
listName.stream().filter(s -> s.startsWith("张") && s.length() == 3).forEach(System.out::println);
//内部类
listName.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.startsWith("张") && s.length() == 3;
}
}).forEach(System.out::println);
//方法引用
//引用其他类的方法
listName.stream().filter(new StringOperation()::filterFun).forEach(System.out::println);
//引用本类的方法
//静态方法中是没有this的 在非静态的方法中才可以使用this
//在静态方法中可以创建本类的对象进行使用
listName.stream().filter(new Main()::filterFun).forEach(System.out::println);
}
public boolean filterFun(String s) {
return s.startsWith("张") && s.length() == 3;
}
}
class StringOperation {
public boolean filterFun(String s) {
return s.startsWith("张") && s.length() == 3;
}
}
# 引用构造方法
为什么要引用构造方法:为了创建对象
package MethodReference;
import java.util.ArrayList;
import java.util.Collections;
public class Main {
public static void main(String[] args) {
ArrayList<String> listName = new ArrayList<>();
Collections.addAll(listName, "张无忌,15", "赵敏,16", "周芷若,17", "周星驰,18", "周星驰,19", "周星驰,20");
List<StringOperation.Student> collect = listName.stream().map(StringOperation.Student::new).toList();
System.out.println(collect);
}
}
class StringOperation extends Main {
public void StringOperationfilterFunStr(String s) {
ArrayList<String> listName = new ArrayList<>();
Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
//引用父类的方法
listName.stream().filter(super::filterFunStr).forEach(System.out::println);
}
static class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//方法引用参数必须一致
//在类中可创建形参不同的多个构造方法
public Student(String str) {
String[] split = str.split(",");
this.name = split[0];
this.age = Integer.parseInt(split[1]);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}
# 使用类名引用成员方法
- 格式:类名::成员方法
- 范例:String::substringkmd
该引用方法独有的特性 抽象方法形参的详解:
- 第一个参数:表示被引用方法的调用者,决定了可以引用那些类中的方法
- 在
stream流当中,第一个参数一般都表示流里面的每一个数据 - 假设流里面的数据是字符串,那么使用这种方式进行方法引用只能引用
String这个类中的方法 - 第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被引用的方法需要是无参的成员方法
# 局限性
- 不能引用所有类中的成员方法
- 它跟抽象方法中的第一个参数有关,这个参数是什么类型的,就只能引用什么类型中的方法
package MethodReference;
public class Main {
public static void main(String[] args) {
//使用类名引用成员方法
// 练习:集合里面一些字符串,要求变成大写后输出
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "abc", "b", "c");
list.stream().map(new Function<String, String>() {
//用这种方式进行方法引用只能引用`String`这个类中的方法
//如果没有第二个参数,说明被引用的方法需要是无参的成员方法
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(System.out::println);
//拿着流里面的每一个数据,去调用String类中的toUpperCase方法,方法的返回值就是转换之后的结果
list.stream().map(String::toUpperCase).forEach(System.out::println);
}
}
# 引用数组的构造方法
- 格式:数据类型[]::new
- 范例:int[]::new 必须跟流中的类型一致
package MethodReference;
public class Main {
public static void main(String[] args) {
//练习:集合中存储一些整数,收集到一个数组中
ArrayList<Integer> list1 = new ArrayList<>();
Collections.addAll(list1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer[] integers = list1.stream().toArray(new IntFunction<Integer[]>() {
@Override
public Integer[] apply(int value) {
return new Integer[value];
}
});
//打印
System.out.println(Arrays.toString(integers));
//方法引用简化写法
Integer[] array = list1.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(array));
}
}
# 方法引用练习
package MethodReference;
public class Main {
public static void main(String[] args) {
//练习1:集合中存储一些字符串数据,比如:张三,23 收集到Student类型的数组中
ArrayList<String> list2 = new ArrayList<>();
Collections.addAll(list2, "张三,23", "赵四,24", "孙五,25", "周六,26", "吴七,27", "郑八,28", "吴九,29", "郑十,30");
StringOperation.Student[] array1 = list2.stream().map(StringOperation.Student::new).toArray(StringOperation.Student[]::new);
System.out.println(Arrays.toString(array1));
//练习2:创建集合添加学生对象,对象的属性name、age 只获取姓名添加到数组当中
ArrayList<StringOperation.Student> listStudent = new ArrayList<>();
Collections.addAll(listStudent, new StringOperation.Student("张三", 23), new StringOperation.Student("赵四", 24), new StringOperation.Student("孙五", 25));
String[] array2 = listStudent.stream().map(new StringOperation.Student()::getName).toArray(String[]::new);
//使用类名引用成员方法
//在该stream流中类型是StringOperation.Student类型
//在map的抽象类中无第二个参数 说明需要无参的成员方法
//StringOperation.Student类中的getName刚好满足
String[] array4 = listStudent.stream().map(StringOperation.Student::getName).toArray(String[]::new);
System.out.println(Arrays.toString(array2));
System.out.println(Arrays.toString(array4));
//练习3:创建集合添加学生对象,学生对象属性:name、age
// 把姓名和年龄拼接成:张三-23的字符串,并放入数组中
ArrayList<StringOperation.Student> listStudent1 = new ArrayList<>();
Collections.addAll(listStudent1, new StringOperation.Student("张三", 23), new StringOperation.Student("赵四", 24), new StringOperation.Student("孙五", 25));
String[] array3 = listStudent1.stream().map(new StringOperation.Student()::getNameAgeStr).toArray(String[]::new);
System.out.println(Arrays.toString(array3));
}
}
class StringOperation extends Main {
public void StringOperationfilterFunStr(String s) {
ArrayList<String> listName = new ArrayList<>();
Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
//引用父类的方法
listName.stream().filter(super::filterFunStr).forEach(System.out::println);
}
static class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String str) {
String[] split = str.split(",");
this.name = split[0];
this.age = Integer.parseInt(split[1]);
}
public Student() {
}
public String getName() {
return name;
}
public String getName(Student student) {
return student.name;
}
public String getNameAgeStr(Student student) {
return student.name + "-" + student.age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}
# 引用本类和父类的成员方法
package MethodReference;
import java.util.ArrayList;
import java.util.Collections;
public class Main {
public boolean filterFunStr(String s) {
return s.startsWith("张") && s.length() == 3;
}
public void filterFun(String s) {
ArrayList<String> listName = new ArrayList<>();
Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
//引用本类的方法
listName.stream().filter(this::filterFunStr).forEach(System.out::println);
}
}
class StringOperation extends Main {
public void StringOperationfilterFunStr(String s) {
ArrayList<String> listName = new ArrayList<>();
Collections.addAll(listName, "张三", "张四三", "王五", "赵六", "孙七", "周八", "吴九", "郑十");
//引用父类的方法
listName.stream().filter(super::filterFunStr).forEach(System.out::println);
}
}