Java
方法引用
- 方法: 以前的方法
- 引用: 把以前的方法拿过来用, 当作函数式接口中抽象方法的方法体
java
//因为方法引用的格式阅读性不强, 所以会先使用匿名内部类和Lambda表达式, 比较着来看作用
import java.util.Arrays;
import java.util.Comparator;
public class Demo1 {
public static void main(String[] args) {
Integer[] arr = {21, 56, 12, 34};
//匿名内部类
Arrays.sort(arr, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
//lambda表达式
Arrays.sort(arr, (o1, o2) -> o2 - o1);
// Arrays.sort(arr, 比较规则)
//在以前调用静态方法使用的是类型.方法名, 而方法引用形式也差不多
// 1. 引用处必须是函数式接口
Arrays.sort(arr, Demo1::subtraction);
}
// 2. 被引用的方法已经存在
// 3. 引用的抽象方法参数类型和返回值类型, 与引用处参数类型和返回值类型一致
// 4. 被引用方法的功能要满足当前需求
public static int subtraction(int n1, int n2) {
return n2 - n1;
}
}提示
::表示方法引用符
引用条件:
- 引用处必须是函数式接口
- 被引用的方法已经存在
- 引用的抽象方法参数类型和返回值类型, 与引用处参数类型和返回值类型一致
- 被引用方法的功能要满足当前需求
静态方法引用
- 格式:
类名::方法名 - 范式:
Integer::parseInt
需求: 将集合中的元素转换为int类型
java
import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Function;
public class Demo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "1", "2", "3", "4", "5");
//对元素进行处理, 首先想到的是流; 然后我们需要将String转换为int类型, 那么想到的是map()
list.stream().map(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
}).forEach(integer -> System.out.println(integer));
//使用lambda表达式
list.stream().map(s -> Integer.parseInt(s)).forEach(integer -> System.out.println(integer));
//使用方法引用
List<Integer> newList = list.stream()
//需要实现的功能与parseInt一致, 并且返回值和参数类型也一致, 所以可以使用方法引用
.map(Integer::parseInt)
.collect(Collectors.toList());
System.out.println(newList);// [1, 2, 3, 4, 5]
}
}成员方法引用
- 格式:
对象::成员方法- 其他类: 其他类对象:
其他类对象::方法名 - 本类:
this::方法名 - 父类:
super::方法名
- 其他类: 其他类对象:
引用其他类的方法
java
public class Demo3 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1, "张三丰", "张无忌", "张翠山", "王二麻子", "张良", "谢广坤");
//需求: 找到list集合中姓为张, 姓名长度为3的人
list1.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() == 3 && s.startsWith("张");
}
}).forEach(s -> System.out.println(s));
//方法引用 引用其他类的方法"对象::成员方法"
list1.stream()
.filter(new StringOperation()::stringJudge)
.forEach(s -> System.out.println(s));
}
}java
public class StringOperation {
//注: 引用的抽象方法参数类型和返回值类型, 与引用处参数类型和返回值类型一致
public boolean stringJudge(String str) {
return str.length() == 3 && str.startsWith("张");
}
}引用本类的成员方法
- 在静态方法中调用本类方法
java
public class Demo3 {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1, "张三丰", "张无忌", "张翠山", "王二麻子", "张良", "谢广坤");
//需求: 找到list集合中姓为张, 姓名长度为3的人
list1.stream().filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() == 3 && s.startsWith("张");
}
}).forEach(s -> System.out.println(s));
//因为static方法中, 不能使用this, 所以在静态方法中想要使用本类方法引用, 需要创建对象然后在引用
list1.stream().filter(this::stringJudge).forEach(s -> System.out.println(s));
//引用本类方法
list1.stream().filter(new Demo3()::stringJudge).forEach(s -> System.out.println(s));
}
public boolean stringJudge(String str) {
return str.length() == 3 && str.startsWith("张");
}
}- 在非静态方法中调用本类方法
java
@FunctionalInterface
public interface MyString {
String mySubString(String s,int x,int y);
}
public class StringOperation {
public StringOperation() {
// useMyString((s,x,y) -> s.substring(x,y));
useMyString(this::mySubstring);
}
private void useMyString(MyString my) {
String s = my.mySubString("HelloWorld", 2, 5);
System.out.println(s);
}
public String mySubstring(String s,int x,int y) {
return s.substring(x, y);
}
}引用父类的成员方法
java
public class Fu {
public String mySubstring(String s,int x,int y) {
return s.substring(x, y);
}
}
public class StringOperation extends Fu {
public StringOperation() {
useMyString(super::mySubstring);
}
private void useMyString(MyString my) {
String s = my.mySubString("HelloWorld", 2, 5);
System.out.println(s);
}
}构造方法引用
- 格式:
类名::new - 目的: 创建这个类的对象
java
//Student构造方法, 若想要引用构造方法, 则对应的参数类型需要对应
public Student(String s) {
String[] info = s.split("-");
//为成员变量赋值, 就相当于new Student(name, age)
this.name = info[0];
this.age = Integer.parseInt(info[1]);
//构造方法没有返回值, 但构造方法运行完后, 对象就已经有了, 所以返回值不需要管
//只需要保证构造方法结束后, 生成的对象和抽象方法(比如当前的apply)返回值保持一致就行
}
public class Demo5 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("汪加年-19");
list.add("小小汪-21");
list.add("励志汪-20");
//将list里面的数据转换为Student类型
//以前的做法
List<Student> studentList = list.stream().map(new Function<String, Student>() {
@Override
public Student apply(String s) {
String[] info = s.split("-");
String name = info[0];
int age = Integer.parseInt(info[1]);
return new Student(name, age);
}
}).collect(Collectors.toList());
//使用构造方法因哟女
list.stream().map(Student::new).collect(Collectors.toList());
}
}类名引用成员方法
- 格式:
类名::成员方法 - 范式:
String::substring
独属于类名引用成员方法的引用规则:
第三条规则与之前不同
- 引用处必须是函数式接口
- 被引用的方法已经存在
- 被引用的形参, 需要跟抽象方法的第二个形参到最后一个形参保持一致, 返回值需要保持一致
- 被引用方法的功能要满足当前需求
java
public class Demo6 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "aaa", "bbb", "ccc", "ddd", "eee");
list.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
return s.toUpperCase();
}
}).forEach(System.out::println);
System.out.println("----------------------");
//类名引用成员方法
//拿着流中的每一个数据, 去调用String类中的方法toUpperCase, 返回值就是转换之后的结果
list.stream().map(String::toUpperCase).forEach(System.out::println);
}
}类名引用成员方法与接口中抽象方法的匹配规则
- 第一个参数 ==> 表示引用方法的调用者, 决定了可以引用哪些类中的方法. 例如: 流当中, 第一个参数一般表示流中的每一个数据, 假设流中的数据是字符串, 那么只能引用
String类中的方法 - 第二个参数到最后一个参数, 抽象方法需要与引用方法保持一致, 如果抽象方法没有第二个参数, 说明被引用的方法需要的是无参的成员方法
局限性: 不能引用所有的成员方法
引用数组的构造方法
格式: 数据类型[]::new
java
public class Demo7 {
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) {
return new Integer[value];
}
});
System.out.println(Arrays.toString(arr));
//引用数组的构造方法就是创建一个数组
Integer[] arr1 = list.stream().toArray(Integer[]::new);
System.out.println(Arrays.toString(arr1));
}
}提示
list.stream().toArray(Integer[]::new);流中的数据是什么类型, 那么就创建什么类型的数组
总结
- 引用静态方法
类名::静态方法名
- 引用成员方法
- 静态中引用
对象::成员方法名
- 非静态中引用
this::成员方法名super::成员方法名
- 静态中引用
- 引用构造方法
类名::new
- 使用类名引用成员方法
类名::成员方法名
- 引用数组的构造方法
类名[]::new