Java8 方法引用详解

作者 | 2020年3月20日

在Java8中,可以使用符号::对方法进行引用,先来点开胃菜:

最开始我们使用匿名类:

List<String> list = Arrays.asList("node""java""python""ruby");
list.forEach(new Consumer<String>() {       // anonymous class
    @Override
    public void accept(String str) {
        System.out.println(str);
    }
});

接下来我们把匿名类换成lambda表达式:

List<String> list = Arrays.asList("node""java""python""ruby");
list.forEach(str -> System.out.println(str)); // lambda

最后,我们来把lambda表达式换成方法引用:

List<String> list = Arrays.asList("node""java""python""ruby");
list.forEach(System.out::println);          // 方法引用

上面演示的这三种写法都可以输出变量list

在Java8中存在4种形式的方法引用:

  • 静态方法引用
  • 实例方法引用
  • 特定类型方法引用
  • 构造方法引用

例子1:静态方法引用

调用SimplePrinter::print输出字符串列表。

Java8MethodReference1a.java

package cc.myexample;

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Java8MethodReference1a {

    public static void main(String[] args) {

        List<String> list = Arrays.asList("A""B""C");

        // 匿名类
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String x) {
                SimplePrinter.print(x);
            }
        });

        // lambda表达式
        list.forEach(x -> SimplePrinter.print(x));

        // 静态方法引用
        list.forEach(SimplePrinter::print);

    }

}

class SimplePrinter {
    public static void print(String str) {
        System.out.println(str);
    }
}

使用静态方法引用把字符串转换为整数。

Intege.java

public static int parseInt(String s) throws NumberFormatException {
    return parseInt(s,10);
}

Java8MethodReference1b.java

package cc.myexample;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Java8MethodReference1b {

    public static void main(String[] args) {

        List<String> list = Arrays.asList("1""2""3");

        // 匿名类
        List<Integer> collect1 = list.stream()
                .map(new Function<String, Integer>() {
                    @Override
                    public Integer apply(String s) {
                        return Integer.parseInt(s);
                    }
                })
                .collect(Collectors.toList());

        // lambda表达式
        List<Integer> collect2 = list.stream()
                .map(s -> Integer.parseInt(s))
                .collect(Collectors.toList());

        // 静态方法引用
        List<Integer> collect3 = list.stream()
                .map(Integer::parseInt)
                .collect(Collectors.toList());

    }

}

例子2: 实例方法引用

使用ComparatorProvider类的compareBySalary()方法按工资对Employee列表排序。

Java8MethodReference2.java

package cc.myexample;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

public class Java8MethodReference2 {

    public static void main(String[] args) {

        List<Employee> list = Arrays.asList(
                new Employee("myexample"38, BigDecimal.valueOf(3800)),
                new Employee("zilap"5, BigDecimal.valueOf(100)),
                new Employee("ali"25, BigDecimal.valueOf(2500)),
                new Employee("unknown"99, BigDecimal.valueOf(9999)));

        // 匿名类
        /*list.sort(new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                return provider.compareBySalary(o1, o2);
            }
        });*/

        ComparatorProvider provider = new ComparatorProvider();

        // lambda表达式
        // list.sort((o1, o2) -> provider.compareBySalary(o1, o2));

        // 静态方法引用
        list.sort(provider::compareBySalary);

        list.forEach(x -> System.out.println(x));

    }

}

class ComparatorProvider {

    public int compareByAge(Employee o1, Employee o2) {
        return o1.getAge().compareTo(o2.getAge());
    }

    public int compareByName(Employee o1, Employee o2) {
        return o1.getName().compareTo(o2.getName());
    }

    public int compareBySalary(Employee o1, Employee o2) {
        return o1.getAge().compareTo(o2.getAge());
    }

}

Employee.java

package cc.myexample;

import java.math.BigDecimal;

public class Employee {

    String name;
    Integer age;
    BigDecimal salary;

    // 省略get/set/toString/构造方法
}

输出

Employee{name='zilap', age=5, salary=100}
Employee{name='ali', age=25, salary=2500}
Employee{name='myexample', age=38, salary=3800}
Employee{name='unknown', age=99, salary=9999}

例子3: 特定类型方法引用

Test1.java

根据分数对学生排序。

public class Test1 {
    public static void main(String[] args) {

        List<Student> list = new ArrayList<>();
        list.add(new Student("Jack1"88));
        list.add(new Student("Jack2"81));
        list.add(new Student("Jack3"82));
        list.add(new Student("Jack4"83));
        list.add(new Student("Jack5"84));
        list.add(new Student("Jack6"85));
        list.sort(Student::compareByScore);
        System.out.println(list);
    }
}

class Student {
    private String name;
    private int score;

    public Student(){

    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public int compareByScore(Student student){
        return this.getScore() - student.getScore();
    }

    @Override
    public String toString(){
        return this.name + "  " + this.score + "  ";
    }
}

例子4: 构造方法引用

引用默认构造方法。

Java8MethodReference4a.java

package cc.myexample;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

public class Java8MethodReference4a {

    public static void main(String[] args) {

        // lambda表达式
        Supplier<Map> obj1 = () -> new HashMap();   // default HashMap() constructor
        Map map1 = obj1.get();

        // 默认构造方法引用
        Supplier<Map> obj2 = HashMap::new;
        Map map2 = obj2.get();

        // lambda表达式
        Supplier<Invoice> obj3 = () -> new Invoice(); // default Invoice() constructor
        Invoice invoice1 = obj3.get();

        // 默认构造方法引用
        Supplier<Invoice> obj4 = Invoice::new;
        Invoice invoice2 = obj4.get();

    }

}

class Invoice {

    String no;
    BigDecimal unitPrice;
    Integer qty;

    public Invoice() {
    }

    // 省略get/set/toString方法
}

引用具有参数的构造方法。

Java8MethodReference4b.java

package cc.myexample;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class Java8MethodReference4b {

    public static void main(String[] args) {

        List<BigDecimal> list = Arrays.asList(
                BigDecimal.valueOf(9.99),
                BigDecimal.valueOf(2.99),
                BigDecimal.valueOf(8.99));

        // lambda表达式
        // List<Invoice> invoices = fakeInvoice(list, (price) -> new Invoice(price));

        // 构造方法引用
        List<Invoice> invoices = fakeInvoice(list, Invoice::new);

        invoices.forEach(System.out::println);
    }

    static List<Invoice> fakeInvoice(List<BigDecimal> list, Function<BigDecimal, Invoice> func) {
        List<Invoice> result = new ArrayList<>();

        for (BigDecimal amount : list) {
            result.add(func.apply(amount));
        }
        return result;
    }

}

class Invoice {

    String no;
    BigDecimal unitPrice;
    Integer qty;

    public Invoice() {
    }

    // 省略get/set/toString方法
}

输出

Invoice{no='null', unitPrice=9.99, qty=null}
Invoice{no='null', unitPrice=2.99, qty=null}
Invoice{no='null', unitPrice=8.99, qty=null}

发表评论

电子邮件地址不会被公开。 必填项已用*标注