Documentation

The Java™ Tutorials
Hide TOC
Method References方法引用
Trail: Learning the Java Language
Lesson: Classes and Objects
Section: Nested Classes
Subsection: Lambda Expressions

Method References方法引用

You use lambda expressions to create anonymous methods.使用lambda表达式创建匿名方法。Sometimes, however, a lambda expression does nothing but call an existing method.但是,有时lambda表达式只调用现有方法。In those cases, it's often clearer to refer to the existing method by name.在这些情况下,按名称引用现有方法通常更清晰。Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.方法引用使您能够做到这一点;对于已经有名称的方法,它们是紧凑、易于阅读的lambda表达式。

Consider again the Person class discussed in the section Lambda Expressions:再次考虑lambda表达式节中讨论的Person类:

public class Person {

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

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

Suppose that the members of your social networking application are contained in an array, and you want to sort the array by age.假设社交网络应用程序的成员包含在一个数组中,并且希望按年龄对数组进行排序。You could use the following code (find the code excerpts described in this section in the example MethodReferencesTest):您可以使用以下代码(在示例MethodReferencesTest中找到本节中描述的代码摘录):

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

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

The method signature of this invocation of sort is the following:sort调用的方法签名如下所示:

static <T> void sort(T[] a, Comparator<? super T> c)

Notice that the interface Comparator is a functional interface.请注意,接口Comparator是一个功能接口。Therefore, you could use a lambda expression instead of defining and then creating a new instance of a class that implements Comparator:因此,您可以使用lambda表达式,而不是定义然后创建实现Comparator的类的新实例:

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

However, this method to compare the birth dates of two Person instances already exists as Person.compareByAge.但是,此用于比较两个Person实例的出生日期的方法已作为Person.compareByAge存在。You can invoke this method instead in the body of the lambda expression:您可以在lambda表达式的主体中调用此方法:

Arrays.sort(rosterAsArray,
    (a, b) -> Person.compareByAge(a, b)
);

Because this lambda expression invokes an existing method, you can use a method reference instead of a lambda expression:由于此lambda表达式调用现有方法,因此可以使用方法引用而不是lambda表达式:

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

The method reference Person::compareByAge is semantically the same as the lambda expression (a, b) -> Person.compareByAge(a, b).引用Person::compareByAge的方法在语义上与lambda表达式(a, b) -> Person.compareByAge(a, b)相同。Each has the following characteristics:每一种都有以下特点:

Kinds of Method References方法引用的种类

There are four kinds of method references:有四种方法参考:

Kind种类 Syntax语法 Examples例子
Reference to a static method对静态方法的引用 ContainingClass::staticMethodName Person::compareByAge
MethodReferencesExamples::appendStrings
Reference to an instance method of a particular object对特定对象的实例方法的引用 containingObject::instanceMethodName myComparisonProvider::compareByName
myApp::appendStrings2
Reference to an instance method of an arbitrary object of a particular type对特定类型的任意对象的实例方法的引用 ContainingType::methodName String::compareToIgnoreCase
String::concat
Reference to a constructor对构造函数的引用 ClassName::new HashSet::new

The following example, MethodReferencesExamples, contains examples of the first three types of method references:以下示例MethodReferencesExamples包含前三种方法引用的示例:

import java.util.function.BiFunction;

public class MethodReferencesExamples {
    
    public static <T> T mergeThings(T a, T b, BiFunction<T, T, T> merger) {
        return merger.apply(a, b);
    }
    
    public static String appendStrings(String a, String b) {
        return a + b;
    }
    
    public String appendStrings2(String a, String b) {
        return a + b;
    }

    public static void main(String[] args) {
        
        MethodReferencesExamples myApp = new MethodReferencesExamples();

        // Calling the method mergeThings with a lambda expression
        System.out.println(MethodReferencesExamples.
            mergeThings("Hello ", "World!", (a, b) -> a + b));
        
        // Reference to a static method
        System.out.println(MethodReferencesExamples.
            mergeThings("Hello ", "World!", MethodReferencesExamples::appendStrings));

        // Reference to an instance method of a particular object        
        System.out.println(MethodReferencesExamples.
            mergeThings("Hello ", "World!", myApp::appendStrings2));
        
        // Reference to an instance method of an arbitrary object of a
        // particular type
        System.out.println(MethodReferencesExamples.
            mergeThings("Hello ", "World!", String::concat));
    }
}

All the System.out.println() statements print the same thing:所有System.out.println()语句都打印相同的内容:Hello World!

BiFunction is one of many functional interfaces in the java.util.function package.BiFunctionjava.util.function包中许多函数接口之一。The BiFunction functional interface can represent a lambda expression or method reference that accepts two arguments and produces a result.BiFunction函数接口可以表示接受两个参数并生成结果的lambda表达式或方法引用。

Reference to a Static Method对静态方法的引用

The method references Person::compareByAge and MethodReferencesExamples::appendStrings are references to a static method.该方法引用Person::compareByAgeMethodReferencesExamples::appendStrings是对静态方法的引用。

Reference to an Instance Method of a Particular Object对特定对象的实例方法的引用

The following is an example of a reference to an instance method of a particular object:以下是对特定对象的实例方法的引用示例:

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);

The method reference myComparisonProvider::compareByName invokes the method compareByName that is part of the object myComparisonProvider.方法引用myComparisonProvider::compareByName调用作为对象myComparisonProvider一部分的方法compareByNameThe JRE infers the method type arguments, which in this case are (Person, Person).JRE推断方法类型参数,在本例中为(Person, Person)

Similarly, the method reference myApp::appendStrings2 invokes the method appendStrings2 that is part of the object myApp.类似地,方法引myApp::appendStrings2调用作为对象myApp一部分的方法appendStrings2The JRE infers the method type arguments, which in this case are (String, String).JRE推断方法类型参数,在本例中为(String, String)

Reference to an Instance Method of an Arbitrary Object of a Particular Type对特定类型的任意对象的实例方法的引用

The following is an example of a reference to an instance method of an arbitrary object of a particular type:以下是对特定类型的任意对象的实例方法的引用示例:

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

The equivalent lambda expression for the method reference String::compareToIgnoreCase would have the formal parameter list (String a, String b), where a and b are arbitrary names used to better describe this example.方法引用String::compareToIgnoreCase的等效lambda表达式将具有形式参数列表(String a, String b),其中ab是用于更好地描述此示例的任意名称。The method reference would invoke the method a.compareToIgnoreCase(b).方法引用将调用方法a.compareToIgnoreCase(b)

Similarly, the method reference String::concat would invoke the method a.concat(b).类似地,方法引用String::concat将调用方法a.concat(b)

Reference to a Constructor对构造函数的引用

You can reference a constructor in the same way as a static method by using the name new.您可以使用名称new以与静态方法相同的方式引用构造函数。The following method copies elements from one collection to another:以下方法将元素从一个集合复制到另一个集合:

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

The functional interface Supplier contains one method get that takes no arguments and returns an object.函数接口Supplier包含一个方法get,该方法不接受任何参数并返回一个对象。Consequently, you can invoke the method transferElements with a lambda expression as follows:因此,您可以使用lambda表达式调用方法transferElements,如下所示:

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

You can use a constructor reference in place of the lambda expression as follows:可以使用构造函数引用代替lambda表达式,如下所示:

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

The Java compiler infers that you want to create a HashSet collection that contains elements of type Person.Java编译器推断您想要创建包含Person类型元素的HashSet集合。Alternatively, you can specify this as follows:或者,您可以按如下方式指定:

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

Previous page: Lambda Expressions
Next page: When to Use Nested Classes, Local Classes, Anonymous Classes, and Lambda Expressions