Before we get to method references, I would highly encourage you to read my lambda expressions article.
What are Method References?
When a lambda expression does nothing but call an existing method, it's often clearer to use that method by name. Method references are compact, easy-to-read lambda expressions that already have a name.
Consider this class Car:
public class Car{
String modelName;
int modelNum;
LocalDate registrationDate;
String vehicleNum;
public String getModelName(){..}
public void printCar() {..}
public static int compareByModelName(Car c1, Car c2){
return c1.getModelName().compareTo(c2.getModelName());
}
}
Suppose you want to sort an array of car instances by the modelName, you could define a class that implements the comparator interface and then sort like so,
public class CarModelNameCompartor implements Comparator<Car> {
public static int compare(Car a, Car b) {
return a.getModelName.compareTo(b.getModelName());
}
}
Arrays.sort(cars, new CarModelNameComparator());
Or you could make use of the simple lambda expression:
Arrays.sort(cars, (a, b) ->
a.getModelName().compareTo(b.getModelName());
However, our class has already implemented a method that can compare cars by modelName.
Arrays.sort(cars, (a, b) -> Car.compareByModelName(a, b));
When a lambda expression has only one statement that calls to another method, we can directly use or refer
that method.
Arrays.sort(cars, Car::compareByModelName);
Method References and Lambda expressions
Method references are semantically the same as the method being called inside lambda expression body (a, b) -> Car.compareByModelName(a, b)
.
- The parameter list is copied from the Comparator compare method.
- Its body calls the compareByModelName method passing in those parameters.
Types of Method References
- Static method reference
- Instance method reference
- Instance method reference of an arbitrary object of a particular type
- Constructor reference
public class MethodReferencesExample {
public static <T> T merge(T a, T b, BiFunction<T,T,T> merger) {
return merger.apply(a, b);
}
public static String appendStringsStaticMethod(String a, String b) {
return a + b;
}
public String appendStringsInstanceMethod(String a, String b) {
return a + b;
}
public static void main(String args[]) {
String one = "Hello";
String two = "World";
// Referring a static method
System.out.println(merge(one, two, MethodReferencesExample::appendStringsStaticMethod));
//Referring an instance method
MethodReferencesExample obj = new MethodReferencesExample();
System.out.println(merge(one, two, obj::appendStringsInstanceMethod));
//Referring an arbitrary object method of a particular type
System.out.println(merge(one, two, String::concat));
}
}
In all of the method references above, the same HelloWorld
output will be generated.
Reference to a Constructor
A Constructor can be referenced the same the way as referencing a static method, like HashSet::new
.
public static List<Car> getObjects(int length, Supplier<Car> supplier){
List<Car> list = new ArrayList<Car>();
for(int i = 0; i < length; i++){
list.add(supplier.get());
}
return list;
}
List<Car> cars = getObjects(5, Car::new);
Similar lambda expression for Car::new
would be
-
() -> { return new Car(); }
.
Conclusion
As mentioned above, if a lambda expression only calls an existing method then using method reference can make code more readable and clear.
Thanks for reading the blog. Feel free to provide inputs and suggestions for any areas of improvement. :)
Top comments (0)