Method References
Replace simple lambdas with the compact :: method reference syntax to improve readability.
Overview
Key Points
- •Static method: ClassName::staticMethod (Integer::parseInt)
- •Bound instance method: instance::method (System.out::println)
- •Unbound instance method: ClassName::instanceMethod (String::toUpperCase)
- •Constructor reference: ClassName::new (ArrayList::new)
- •Method references are only possible when the lambda does nothing other than call the method
- •The compiler infers which overload to use from the functional interface signature
- •Method references are interchangeable with equivalent lambdas; choose whichever is clearer
Examples
Static method references
import java.util.List;
import java.util.function.Function;
public class Main {
static int doubleIt(int n) { return n * 2; }
static String describe(int n) { return "Number " + n; }
public static void main(String[] args) {
// Static method reference
List<String> strings = List.of("1", "2", "3", "4");
// Lambda: s -> Integer.parseInt(s)
// Method reference: Integer::parseInt
strings.stream()
.map(Integer::parseInt) // same as s -> Integer.parseInt(s)
.map(Main::doubleIt) // same as n -> doubleIt(n)
.map(Main::describe)
.forEach(System.out::println);
}
}Integer::parseInt replaces s -> Integer.parseInt(s). The compiler matches the lambda signature to the method signature automatically.
Bound and unbound instance method references
import java.util.List;
import java.util.function.Function;
import java.util.function.Consumer;
public class Main {
public static void main(String[] args) {
// Bound: specific instance
// () -> System.out.println(...) becomes:
Consumer<String> printer = System.out::println; // System.out is the specific instance
printer.accept("hello"); // hello
// Unbound: applies to any instance of String
// s -> s.toUpperCase() becomes:
Function<String, String> upper = String::toUpperCase;
System.out.println(upper.apply("world")); // WORLD
// Used in stream
List<String> words = List.of("hello", "world", "java");
words.stream()
.map(String::toUpperCase)
.forEach(System.out::println);
}
}Bound: the object is known (System.out). Unbound: the object comes from the first argument of the lambda (s in s -> s.toUpperCase()).
Constructor references
import java.util.List;
import java.util.ArrayList;
import java.util.function.Supplier;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Main {
static class User {
String name;
User(String name) { this.name = name; }
public String toString() { return "User(" + name + ")"; }
}
public static void main(String[] args) {
// Supplier: () -> new ArrayList<String>()
Supplier<List<String>> listMaker = ArrayList::new;
List<String> list = listMaker.get();
list.add("item");
System.out.println(list);
// Function: name -> new User(name)
Function<String, User> userFactory = User::new;
User alice = userFactory.apply("Alice");
System.out.println(alice); // User(Alice)
// Collect to list using constructor reference in stream
List<User> users = List.of("Bob", "Carol", "Dave")
.stream()
.map(User::new)
.collect(Collectors.toList());
System.out.println(users);
}
}ClassName::new is a constructor reference. The compiler picks the matching constructor based on the functional interface signature.
Common Mistakes
- Trying to use a method reference when the lambda body does more than call a single method. x -> x.trim().toUpperCase() cannot be simplified to a single method reference
- Confusing bound and unbound references: String::toUpperCase is unbound (takes a String argument); instance::toUpperCase would be bound
- Using the wrong number of arguments: if the functional interface has two parameters, the method must accept two parameters or take one receiver and one argument
Note
Apply the rule: if you can name the method and the lambda body does nothing other than call it, use a method reference. Prefer readability: if the method reference is obvious, use it; if it is cryptic, use a lambda.
Exercises
Write Java code and click Run to execute it instantly. When your output looks correct, mark as done.
Completed: 0 / 4 exercises
Knowledge Check
Question 1 of 4