Method Reference (introduced in Java 8) provides a shorter and cleaner way to write lambda expressions when an existing method can be reused.
Instead of writing:
list.forEach(x -> System.out.println(x));We can write:
list.forEach(System.out::println);It improves readability and avoids unnecessary lambda boilerplate.
Method reference works only when the lambda matches an existing method signature.
Java provides four types of method references:
| Type | Syntax | Meaning |
|---|---|---|
| 1. Reference to a static method | ClassName::staticMethod |
Calls a static method |
| 2. Reference to an instance method of a particular object | obj::instanceMethod |
Calls a method on a specific object |
| 3. Reference to an instance method of an arbitrary object (of a given type) | ClassName::instanceMethod |
Calls an instance method on each object in the stream |
| 4. Reference to a constructor | ClassName::new |
Calls a constructor to create objects |
Let's study each in detail.
Syntax:
ClassName::staticMethodpublic class Utils {
public static void printSquare(int x) {
System.out.println(x * x);
}
}
List<Integer> list = List.of(1, 2, 3);
list.forEach(Utils::printSquare);Equivalent lambda:
list.forEach(x -> Utils.printSquare(x));Syntax:
object::instanceMethodpublic class Printer {
public void print(String msg) {
System.out.println(msg);
}
}
Printer p = new Printer();
List<String> names = List.of("Java", "Spring", "SQL");
names.forEach(p::print);Equivalent lambda:
names.forEach(s -> p.print(s));Syntax:
ClassName::instanceMethodUsed when the lambda uses the parameter as the calling object.
List<String> names = List.of("java", "spring", "docker");
names.stream()
.map(String::toUpperCase)
.forEach(System.out::println);Equivalent lambda:
names.stream()
.map(s -> s.toUpperCase())Another example:
list.stream().map(String::length);Equivalent lambda:
list.stream().map(s -> s.length());Syntax:
ClassName::newUsed to create new objects.
Supplier<Employee> supplier = Employee::new;
Employee e = supplier.get();Equivalent lambda:
Supplier<Employee> supplier = () -> new Employee();Function<String, User> function = User::new;
User u = function.apply("Ben");Equivalent lambda:
Function<String, User> function = name -> new User(name);| Lambda Expression | Method Reference |
|---|---|
| Can have logic | Only refers to existing method |
| More flexible | More concise |
| Slightly slower | Faster (direct call) |
| Preferred when logic is complex | Preferred when logic is simple |
list.sort(String::compareToIgnoreCase);Instead of:
list.sort((a, b) -> a.compareToIgnoreCase(b));Stream.of(1, 2, 3)
.map(String::valueOf)
.forEach(System.out::println);List<String> names = List.of("A", "B", "C");
List<Employee> employees =
names.stream()
.map(Employee::new)
.collect(Collectors.toList());Equivalent lambda:
.map(name -> new Employee(name))Use them when:
- lambda simply calls an existing method
- code becomes cleaner and more readable
- no additional logic is needed in the lambda
Avoid when:
- lambda contains logic
- readability decreases
- method reference becomes ambiguous
A shorthand syntax for calling existing methods using :: operator.
Four:
- static method
- instance method of object
- instance method of class
- constructor
String::length→ method of arbitrary object (stream element)obj::method→ method of a specific object
No. Only when lambda body calls an existing method directly.
Supplier<T>→ no-arg constructorFunction<A,T>→ one-arg constructorBiFunction<A,B,T>→ two-arg constructor
-
Method references are a concise form of lambda expressions.
-
They use the
::operator. -
Four types: static, specific instance, arbitrary instance, constructor.
-
Useful for clean, readable, functional-style code.
-
Cannot contain custom logic—only method calls.