Method References
TL;DR
- Method References are a shorthand syntax for a Lambda Expression that only does one thing: call an existing method.
- Syntax uses double colons:
ClassName::methodNameorinstanceName::methodName. - They improve readability by making code even more concise than lambdas.
Concept
Sometimes, a lambda expression simply takes its arguments and passes them directly into an existing method.
For example: str -> System.out.println(str)
Because this pattern is so common, Java 8 introduced Method References. Instead of writing out the lambda, you can just reference the method directly: System.out::println. The compiler is smart enough to figure out that the arguments passed to the functional interface should be routed into that method.
Types of Method References
- Static Method:
ClassName::staticMethod - Instance Method of a particular object:
instance::instanceMethod - Instance Method of an arbitrary object of a particular type:
ClassName::instanceMethod - Constructor:
ClassName::new
Examples
import java.util.ArrayList;
import java.util.List;
public class MethodReferenceExample {
public static void main(String[] args) {
List<String> names = new ArrayList<>(List.of("Alice", "Bob", "Charlie"));
// --- 1. Static Method Reference ---
// Lambda: s -> Integer.parseInt(s)
// Reference: Integer::parseInt
// --- 2. Instance Method of a specific object ---
// Lambda: s -> System.out.println(s)
names.forEach(System.out::println);
// --- 3. Instance Method of an arbitrary object ---
// Lambda: (s1, s2) -> s1.compareToIgnoreCase(s2)
// We reference the method on the String class, and Java knows
// the first arg is the object, and the second arg is the method parameter.
names.sort(String::compareToIgnoreCase);
// --- 4. Constructor Reference ---
// Lambda: () -> new ArrayList<>()
// Reference: ArrayList::new
}
}
Interview Questions
Q: If a lambda expression modifies the argument before passing it to a method, can you replace it with a method reference?
A: No. Method references can only be used if the lambda simply passes the parameters through to the method without modifying them. If your lambda looks like str -> System.out.println(str.trim()), you cannot use a method reference. You must use the lambda.
Q: How does the compiler resolve overloaded methods in method references?
A: The compiler uses the target Functional Interface to figure out which overloaded method you mean. If you use Math::max, the compiler checks where you are assigning it. If you assign it to a BiFunction<Integer, Integer, Integer>, it selects Math.max(int, int). If you assign it to a BiFunction<Double, Double, Double>, it selects Math.max(double, double).