Java 方法引用
本质上是Lambda的语法糖。
1 引用静态方法
lambda原表达语句:
Function<String, Integer> lambda = (String s) -> Integer.parseInt(s);
用方法改写:
Function<String, Integer> methodRef = Integer::parseInt;
- 接口是函数式接口:即接口中只有一个抽象方法(比如
Function
、Consumer
、Supplier
等)。 - 方法签名匹配:引用的方法的 “参数列表” 和 “返回值类型”,必须与函数式接口抽象方法的参数列表、返回值类型完全一致(无返回值时需都无返回值)。
Function<String, Integer> 的泛型参数与引用的方法有严格的对应关系,第一个类型参数:方法的输入参数类型,第二个类型参数:方法的返回值类型。
2 引用类(实例对象)的成员方法
引用其他类的成员方法
比如我们有一个String
对象str
,要获取它的长度(length()
是String
的成员方法):
String str = "hello,world!";
Supplier<Integer> getLength = str::length;
System.out.println(getLength.get());
引用本类或父类的成员方法
本类:
public class UserService {
private boolean isUserNameEmpty(String name) {
return name == null || name.trim().isEmpty();
}
public void register(String userName) {
// 函数式接口Predicate<String>:参数String(用户名),返回值boolean(是否为空)
Predicate<String> checkEmpty = this::isUserNameEmpty;
if (checkEmpty.test(userName)) {
throw new RuntimeException("用户名不能为空!");
}
// 后续注册逻辑...
}
}
父类:eg. super::sayHello;
3 引用构造方法(创建对象)
// 学生类
class Student {
private String name;
// 无参构造
public Student() {}
// 有参构造(String name)
public Student(String name) {
this.name = name;
}
// getter
public String getName() {
return name;
}
}
// 测试类
public class Test {
public static void main(String[] args) {
// 1. 引用无参构造
Supplier<Student> createEmptyStudent = Student::new;
Student emptyStudent = createEmptyStudent.get();
// 2. 引用有参构造(String name):匹配Function<String, Student>
Function<String, Student> createNamedStudent = Student::new;
Student tom = createNamedStudent.apply("tom");
System.out.println(tom.getName());
}
}
这里的两个Student::new
,JVM 会根据函数式接口的抽象方法签名,自动匹配对应的构造方法(无参 / 有参、参数个数 / 类型需一致)。
签名(Signature) 在编程中指的是方法或构造方法的唯一标识,它由以下几个要素组成:
- 方法名称
- 参数类型列表(参数的类型、顺序、数量)
- 返回类型(在某些语言中不算签名的一部分,但在Java的方法引用中重要)
4 类名引用成员方法BiFunction<>
这种场景很容易和 “静态方法引用” 混淆,函数式接口的第一个参数,必须是 “引用方法所属的类的对象”(这个对象会作为方法的 “调用者”)
类名::成员方法名
(注意:这里是 “类名”,但引用的是 “成员方法”,而非静态方法)
// 函数式接口BiFunction<String, Integer, String>;
// 第1个参数,是方法的调用者类
// 第2个参数,是参数
// 第3个参数,是返回结果
BiFunction<String, Integer, String> subString = String::subString;
String result = subString.apply("Hello", 2);
System.out.println(result);
等价于Lambda:
BiFunction<String, Integer, String> subString = (str, index) -> str.subString(index);
案例:
转成自定义对象并收集到数组
public class Test {
public static void main(String[] args) {
List<String> nameList = Arrays.asList("Alice", "Bob", "Charlie");
// 步骤1:map -> 姓名转Student对象(引用有参构造)
// 步骤2:toArray -> 收集到Student[]数组(引用数组构造方法)
Student[] studentArray = nameList.stream()
.map(Student::new) // 等价于name -> new Student(name)
.toArray(Student[]::new); // 等价于size -> new Student[size]
// 遍历数组
for (Student student : studentArray) {
System.out.println(student.getName());
// 输出:Alice、Bob、Charlie
}
}
}
获取部分属性并收集到数组
public class Test {
public static void main(String[] args) {
// 准备数据:3个Student对象
List<Student> studentList = Arrays.asList(
new Student("Alice"),
new Student("Bob"),
new Student("Charlie")
);
// 步骤1:map -> 提取姓名(引用成员方法getName)
// 步骤2:toArray -> 收集到String[]数组
String[] nameArray = studentList.stream()
.map(Student::getName) // 等价于student -> student.getName()
.toArray(String[]::new);
// 输出数组
System.out.println(Arrays.toString(nameArray)); // 输出:[Alice, Bob, Charlie]
}
}
5 引用数组的构造方法(创建数组)
数组类型::new
(本质是调用数组的构造方法,指定数组长度并创建数组)
eg. String[]::new
比如创建String
数组和Integer
数组:
public class Test {
public static void main(String[] args) {
// 1. 创建String数组:匹配Function<Integer, String[]>(参数Integer是数组长度,返回String[])
Function<Integer, String[]> createStringArray = String[]::new;
String[] strArray = createStringArray.apply(3); // 创建长度为3的String数组
strArray[0] = "a";
strArray[1] = "b";
System.out.println(Arrays.toString(strArray)); // 输出:[a, b, null]
// 2. 创建Integer数组:匹配Function<Integer, Integer[]>
Function<Integer, Integer[]> createIntArray = Integer[]::new;
Integer[] intArray = createIntArray.apply(2); // 长度为2的Integer数组
intArray[0] = 10;
System.out.println(Arrays.toString(intArray)); // 输出:[10, null]
}
}
场景类型 | 语法格式 | 核心前提 / 示例 |
---|---|---|
引用静态方法 | 类名::静态方法名 | 方法是静态的,如Math::abs |
引用其他类的成员方法 | 对象实例::成员方法名 | 需先创建对象,如str::length |
引用本类成员方法 | this:: 成员方法名 | 在非静态方法中使用,如this::checkName |
引用父类成员方法 | super:: 成员方法名 | 在子类中调用父类方法,如super::sayHi |
引用构造方法 | 类名::new | 匹配构造方法签名,如Student::new |
类名引用成员方法 | 类名::成员方法名 | 接口第一个参数是方法调用者,如String::substring |
引用数组构造方法 | 数组类型::new | 指定数组长度,如String[]::new |
分类:
Java-Backend
标签:
Java
版权申明
本文系作者 @xiin 原创发布在To Future$站点。未经许可,禁止转载。
暂无评论数据