java8官方文档—方法引用

声明:本文翻译自The Java™ Tutorials(官方文档)

java8官方文档—方法引用_第1张图片

方法引用

你使用Lambda 表达式来创建匿名方法,但是有时候,Lambda表达式可能仅仅调用了一个已存在的方法,而不做任何其它事。在这种情况下,通常通过方法名称引用一个已存在的方法会更加清晰。方法引用允许我们这样做。通过方法引用来书写的Lambda表达式是紧凑的、易读的。

再考虑一下在Lambda 表达式一节中讨论的Person类:

public class Person {

    public enum Sex {
        MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    public int getAge() {
        // ...
    }
    
    public Calendar getBirthday() {
        return birthday;
    }    

    public static int compareByAge(Person a, Person b) {
        return a.birthday.compareTo(b.birthday);
    }}

假如社交应用的成员包含在一个数组中,你想参考年龄进行排序。你可以能会使用下面的代码(可以在MethodReferencesTest
类中查看代码说明):

Person[] rosterAsArray = roster.toArray(new Person[roster.size()]);

class PersonAgeComparator implements Comparator {
    public int compare(Person a, Person b) {
        return a.getBirthday().compareTo(b.getBirthday());
    }
}
        
Arrays.sort(rosterAsArray, new PersonAgeComparator());

这个sort调用的方法签名如下:

static  void sort(T[] a, Comparator c)

注意Comparator一个函数式接口。因此你可以使用Lambda表达式代替创建一个新的类实例来实现Comparator接口:

Arrays.sort(rosterAsArray,
    (Person a, Person b) -> {
        return a.getBirthday().compareTo(b.getBirthday());
    }
);

由于这个Lambda表达式调用了一个已经存在的方法,你可以使用方法引用替代Lambda表达式:

Arrays.sort(rosterAsArray, Person::compareByAge);

方法引用Person::compareByAge语义上和Lambda表达式(a, b) -> Person.compareByAge(a, b)相同。都有以下的特征:

  • 它们的正式参数列表都是从 Comparator < Person >.compare(Person,Person)中复制的。
  • 它们的主体部分都是调用方法Person.compareByAge

方法引用的种类

有四种方法引用:

类型 示例
引用静态方法 ContainingClass::staticMethodName
引用特定对象的实例方法 containingObject::instanceMethodName
引用一个特定类型的任意对象的实例方法 ContainingType::methodName
引用一个构造函数 ClassName::new

引用一个静态方法

Person::compareByAge就是一个引用静态方法的例子。

引用特定对象的实例方法

下面就是一个引用特定对象的实例方法的实例:

class ComparisonProvider {
    public int compareByName(Person a, Person b) {
        return a.getName().compareTo(b.getName());
    }
        
    public int compareByAge(Person a, Person b) {
        return a.getBirthday().compareTo(b.getBirthday());
    }
}
ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);

这个方法引用myComparisonProvider::compareByName调用的方法compareByNamemyComparisonProvider对象的一部分。JRE推断这里的方法类型参数是(Person, Person)

引用一个特定类型的任意对象的实例方法

下面是引用特定类型的任意对象实例方法的示例:

String[] stringArray = { "Barbara", "James", "Mary", "John",
    "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

String::compareToIgnoreCase方法引用等价的Lambda表达式,应该有正式参数列表(String a,String b)。其中a和b是任意名称,用于更好的描述这个例子。这个方法引用将会调用a.compareToIgnoreCase(b)方法。

构造函数引用

你可以像引用静态方法一样,使用new关键字引用一个构造器。下面的方法将元素从一个集合复制到另一个集合:

public static , DEST extends Collection>
    DEST transferElements(
        SOURCE sourceCollection,
        Supplier collectionFactory) {
        
        DEST result = collectionFactory.get();
        for (T t : sourceCollection) {
            result.add(t);
        }
        return result;
}

函数式接口Supplier包含一个没有参数,但返回一个对象的get方法。因此你可以使用Lambda表达式调用transferElements方法就像下面这样:

Set rosterSetLambda =
    transferElements(roster, () -> { return new HashSet<>(); });

你可以像下面这样使用构造函数引用代替Lambda表达式:

Set rosterSet = transferElements(roster, HashSet::new);

Java编译器推断你想创建一个包含Person类型的HashSet集合,其实你也可以指定类型,比如:

Set rosterSet = transferElements(roster, HashSet::new);

你可能感兴趣的:(java8官方文档—方法引用)