The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.
See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.
You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. 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.
Consider again the
Person
class discussed in the section
Lambda Expressions:
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
):
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:
static <T> void sort(T[] a, Comparator<? super T> c)
Notice that the interface Comparator
is a functional interface. Therefore, you could use a lambda expression instead of defining and then creating a new instance of a class that implements 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
. You can invoke this method instead in the body of the lambda expression:
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:
Arrays.sort(rosterAsArray, Person::compareByAge);
The method reference Person::compareByAge
is semantically the same as the lambda expression (a, b) -> Person.compareByAge(a, b)
. Each has the following characteristics:
Comparator<Person>.compare
, which is (Person, Person)
.Person.compareByAge
.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:
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: Hello World!
BiFunction
is one of many functional interfaces in the
java.util.function
package. The BiFunction
functional interface can represent a lambda expression or method reference that accepts two arguments and produces a result.
The method references Person::compareByAge
and MethodReferencesExamples::appendStrings
are references to a static method.
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
. The JRE infers the method type arguments, which in this case are (Person, Person)
.
Similarly, the method reference myApp::appendStrings2
invokes the method appendStrings2
that is part of the object myApp
. The JRE infers the method type arguments, which in this case are (String, String)
.
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. The method reference would invoke the method a.compareToIgnoreCase(b)
.
Similarly, the method reference String::concat
would invoke the method a.concat(b)
.
You can reference a constructor in the same way as a static method by using the name 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. Consequently, you can invoke the method transferElements
with a lambda expression as follows:
Set<Person> rosterSetLambda = transferElements(roster, () -> { return new HashSet<>(); });
You can use a constructor reference in place of the lambda expression as follows:
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
. Alternatively, you can specify this as follows:
Set<Person> rosterSet = transferElements(roster, HashSet<Person>::new);