Java 8之方法引用

作者: imule 分类: Java知识 发布时间: 2022-12-23 11:54

Java 8开始支持Lambda表达式,其避免了我们创建匿名内部类的麻烦,形式上更加优雅简洁易读。而如果我们Lambda表达式中只是调用一个已经封装过的方法,则显得过于繁琐、不够简约,为此Java 8在支持Lambda表达式的同时,也提供了一个语法糖:方法引用

方法引用

方法引用有如下4种使用形式:

  1. 类名::静态方法名
  2. 对象实例名::实例方法名
  3. 类名::实例方法名
  4. 类名::new

类名::静态方法名

对于静态方法,通过类名::静态方法名的方式,即可调用该方法

public static void main(String[] args) {
    Set<Integer> set = new HashSet<>();
    set.add(-12);
    set.add(3);
    set.add(-8);
    set.add(4);
    // 方式1: Lambda 表达式
    System.out.println("------------ Lambda Expression ------------");
    set.forEach((e) -> {
        test.getNum(e);
    });
    // 方式2: 方法引用
    System.out.println("\r\n------------ Method Reference ------------");
    set.forEach(test::getNum);
}

public static void getNum(Integer a) {
    Integer num = Math.abs(a);
    System.out.println("num: " + num);
}

测试结果如下,表明上述两种形式作用是一致的,函数式接口中的参数全部传入所指定的静态方法中

------------ Lambda Expression ------------
num: 3
num: 4
num: 8
num: 12

------------ Method Reference ------------
num: 3
num: 4
num: 8
num: 12

对象实例名::实例方法名

对于实例方法,可以通过 对象实例名::实例方法名 的方式来使用,代码如下所示:

public static void main(String[] args) {
    Set<Student> set = new HashSet<>();
    for(int i=0; i<2; i++) {
        Student student = new Student();
        student.setAge(i);
        student.setId(i);
        student.setName(String.valueOf(i));
        set.add(student);
    }

    Student stu = new Student();
    stu.setName("Aaron");
    stu.setId(78);
    stu.setAge(24);

    // 方式1: Lambda 表达式
    System.out.println("------------ Lambda Expression ------------");
    set.forEach( (e) -> {
        stu.getDetail(e);
    } );
    // 方式2: 方法引用
    System.out.println("\r\n------------ Method Reference ------------");
    set.forEach(stu::getDetail);
}

@Data
class Student{
    private Integer age;
    private Integer id;
    private String name;

    public void getDetail() {
        System.out.println("call: " + this);
    }

    public void getDetail(Student s) {
        System.out.println("call: " + this);
        System.out.println("param: " + s);
    }
}

测试结果如下,表明上述两种形式作用是一致的。函数式接口中的参数全部传入所指定的实例方法中,而实例方法的调用者即为在lambda表达式和方法引用中指定的实例对象

Hello Word by Aaron
------------ Lambda Expression ------------
call: Student(age=24,id-78,name=Aaron)
param: Student(age=0,id=0,name=0)
call: Student(age=24,id-=78,name=Aaron)
param: Student(age=1, id=1, name=1)

------------ Method Reference ------------
call: Student(age=24,id-78,name=Aaron)
param: Student(age=0,id=0,name=0)
call: Student(age=24,id-=78,name=Aaron)
param: Student(age=1, id=1, name=1)

类名::实例方法名

对于实例方法,其实还可以通过 类名::实例方法名 的方式来使用,代码如下所示:

public static void main(String[] args) {
    Set<Student> set = new HashSet<>();
    for(int i=0; i<2; i++) {
        Student student = new Student();
        student.setAge(i);
        student.setId(i);
        student.setName(String.valueOf(i));
        set.add(student);
    }

    Student stu = new Student();
    stu.setName("Aaron");
    stu.setId(78);
    stu.setAge(24);

    // 方式1: Lambda 表达式
    System.out.println("------------ Lambda Expression ------------");
    set.forEach( (e) -> {
        e.getDetail();
    } );
    // 方式2: 方法引用
    System.out.println("\r\n------------ Method Reference ------------");
    set.forEach(Student::getDetail);
}

@Data
class Student{
    private Integer age;
    private Integer id;
    private String name;

    public void getDetail() {
        System.out.println("call: " + this);
    }

    public void getDetail(Student s) {
        System.out.println("call: " + this);
        System.out.println("param: " + s);
    }
}

测试结果如下,表明上述两种形式作用是一致的,此时在方法引用中函数式接口所传入的第一个参数即为实例方法的调用者,如果有剩余参数的话,其将全部传入所指定的实例方法中

Hello Word by Aaron
------------ Lambda Expression ------------
param: Student(age=0,id=0,name=0)
param: Student(age=1, id=1, name=1)

------------ Method Reference ------------
param: Student(age=0,id=0,name=0)
param: Student(age=1, id=1, name=1)

类名::new

对于构造器,可通过 类名::new 的方式来调用,代码如下所示:

public static void main(String[] args) {
    String[] array = new String[]{"Aaron", "Bob", "Tony"};
    List<String> list = Arrays.asList(array);

    System.out.println("------------ Lambda Expression ------------");
    List<Student> students1 = list.stream()
            .map(str -> new Student(str) )  // 通过lambda
            .collect(Collectors.toList());
    students1.forEach(System.out::println);

    System.out.println("------------ Method Reference ------------");
    List<Student> students2 = list.stream()
            .map(Student::new)              //  方法引用
            .collect(Collectors.toList());
    students2.forEach(System.out::println);
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class Student{
    private Integer age;
    private Integer id;
    private String name;

    public Student(String name) {
        this.name = name;
    }
}

测试结果如下,表明上述两种形式作用是一致的:

------------ Lambda Expression ------------
student(age=null,id=null, name=Aaron)
student(age=null,id=null, name=Bob)
student(age=null,id=null, name=Tony)
------------ Method Reference ------------
student(age=null,id=null, name=Aaron)
student(age=null,id=null,name=Bob)
student(age=null,id=null, name=Tony)
寄语

    有人在奔跑,有人在睡觉,有人在感恩,有人在抱怨,有目标的睡不着,没目标的睡不醒,努力才是人生应有的态度,睁开眼就是新的开始。

本站文章主要用于个人学习记录,可能对您有所帮助,仅供参考!

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!