本质上是Lambda的语法糖。

1 引用静态方法

lambda原表达语句:

Function<String, Integer> lambda = (String s) -> Integer.parseInt(s);

用方法改写:

Function<String, Integer> methodRef = Integer::parseInt;
  • 接口是函数式接口:即接口中只有一个抽象方法(比如FunctionConsumerSupplier等)。
  • 方法签名匹配:引用的方法的 “参数列表” 和 “返回值类型”,必须与函数式接口抽象方法的参数列表、返回值类型完全一致(无返回值时需都无返回值)。

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::newJVM 会根据函数式接口的抽象方法签名,自动匹配对应的构造方法(无参 / 有参、参数个数 / 类型需一致)。

签名(Signature) 在编程中指的是方法或构造方法的唯一标识,它由以下几个要素组成:

  1. 方法名称
  2. 参数类型列表(参数的类型、顺序、数量)
  3. 返回类型(在某些语言中不算签名的一部分,但在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

评论

暂无评论数据

暂无评论数据

目录