Method referecnes in Java 8 provide a concise syntax to refer directly to methods or constructors without executing them. They are useful when a lambda expression merely calls an existing method, allowing the code to be more readable and reusable.
Consider a Person class:
public class Person {
public enum Sex { MALE, FEMALE }
String name;
LocalDate birthday;
Sex gender;
String emailAddress;
public int getAge() {
// ...
}
public LocalDate getBirthday() {
return birthday;
}
public static int compareByAge(Person p1, Person p2) {
return p1.birthday.compareTo(p2.birthday);
}
}
To sort a array of Person objects by age, one might traditionally implement a Comparator:
Arrays.sort(personArray, new Comparator<Person>() {
public int compare(Person a, Person b) {
return a.getBirthday().compareTo(b.getBirthday());
}
});
Since Comparator is a functional interface, this can be simplified with a lambda:
Arrays.sort(personArray, (a, b) -> a.getBirthday().compareTo(b.getBirthday()));
If a suitable static method already exists—like compareByAge—the lambda can delegate to it:
Arrays.sort(personArray, (a, b) -> Person.compareByAge(a, b));
This can be further shortened using a method reference:
Arrays.sort(personArray, Person::compareByAge);
The Java runtime infers that the method expects two Person arguments based on the context of the Comparator functional interface.
There are four kinds of method references:
| Kind | Syntax |
|---|---|
| Static method | ClassName::staticMethod |
| Instance method of a specific object | instance::method |
| Instance method of an arbitrary object of a given type | ClassName::method |
| Constructor | ClassName::new |
Static method reference: As shown above, Person::compareByAge refers to a static method.
Instance method of a specific object:
ComparisonProvider provider = new ComparisonProvider();
Arrays.sort(personArray, provider::compareByName);
Here, compareByName is an instance method of the provider object.
Instance method of an arbitrary object:
String[] names = {"Barbara", "James", "Mary"};
Arrays.sort(names, String::compareToIgnoreCase);
This invokes compareToIgnoreCase on each string during comparison.
Constructor reference:
Given a generic utility method:
public static <T, SRC extends Collection<T>, DST extends Collection<T>>
DST transferElements(SRC source, Supplier<DST> factory) {
DST result = factory.get();
for (T item : source) {
result.add(item);
}
return result;
}
A lambda can supply a new collection:
Set<Person> people = transferElements(roster, () -> new HashSet<>());
Using a constructor reference simplifies this:
Set<Person> people = transferElements(roster, HashSet::new);
The compiler infers the generic type, but it can also be made explicit:
Set<Person> people = transferElements(roster, HashSet<Person>::new);