Method References in Java — Four Types and When to Use Each
Fast recall
Quick revision
Core answer
ClassName::staticMethod (e.g. Integer::parseInt); (2) Instance method on a specific object — instance::method (e.g. System.out::println); (3) Instance method on an arbitrary instance of a class — ClassName::instanceMethod (e.g. String::toUpperCase — the first lambda argument becomes this); (4) Constructor reference — ClassName::new (e.g. ArrayList::new). The compiler handles them identically to equivalent lambdas, through invokedynamic and LambdaMetafactory. Use a method reference when the lambda body would just call one method with no additional logic — it's shorter, conveys intent better, and avoids the parameter-naming decision.Whether you know all four types and can distinguish them — especially bound (instance::method) vs unbound (Class::instanceMethod)
Confusing `ClassName::instanceMethod` (unbound, first arg is receiver) with `instance::method` (bound); not knowing constructor references exist
Explain when a method reference is NOT interchangeable with a lambda (e.g. captures timing for `instance::method`), and give examples using primitive specializations
Interview-ready guide
Interview answer
A method reference is a compact form of a lambda that just invokes an existing method. Four types.
First, static method references — ClassName::staticMethod. Example: Integer::parseInt. Equivalent to s -> Integer.parseInt(s).
Second, bound instance method references — instance::method. The receiver is captured at reference creation. Example: System.out::println — equivalent to x -> System.out.println(x).
Third, unbound instance method references — ClassName::instanceMethod. This is the subtle one: the first lambda argument becomes the receiver. String::toUpperCase is equivalent to (s) -> s.toUpperCase(). String::compareTo is equivalent to (a, b) -> a.compareTo(b) — satisfies Comparator and BiFunction.
Fourth, constructor references — ClassName::new. The target functional interface determines which overload. ArrayList::new is a Supplier for no-arg, or a Function for capacity-arg. Also works for arrays: String[]::new.
The most common confusion is between bound and unbound. System.out::println binds the System.out instance. PrintStream::println is unbound — the first argument is the PrintStream receiver. Different functional interface shapes, different call semantics.
Under the hood: method references compile to the same invokedynamic instruction as equivalent lambdas, calling LambdaMetafactory to produce the implementation. Zero runtime cost difference — it's purely a readability choice.
When to use: prefer method references when the lambda body is a single method call with no extra logic. The parameter name in x -> x.toUpperCase() is arbitrary; String::toUpperCase omits the noise.
When not to use: when the lambda has logic, keep it as a lambda — or extract to a named helper method. And if the method throws a checked exception, standard functional interfaces like Function can't accept it — you'll need a custom @FunctionalInterface ThrowingFunction or a wrapper.
Method References in Java — Four Types and When to Use Each
Direct Answer
A method reference is a compact form of a lambda that simply invokes an existing method. There are four types: (1) Static method reference — ClassName::staticMethod (e.g. Integer::parseInt); (2) Instance method on a specific object — instance::method (e.g. System.out::println); (3) Instance method on an arbitrary instance of a class — ClassName::instanceMethod (e.g. String::toUpperCase — the first lambda argument becomes this); (4) Constructor reference — ClassName::new (e.g. ArrayList::new). The compiler handles them identically to equivalent lambdas, through invokedynamic and LambdaMetafactory. Use a method reference when the lambda body would just call one method with no additional logic — it's shorter, conveys intent better, and avoids the parameter-naming decision.
Common Mistakes & Pitfalls
Confusing ClassName::instanceMethod (unbound, first arg is receiver) with instance::method (bound); not knowing constructor references exist
Check your understanding
Answer these without looking back at the article.
- How does the compiler decide between `Integer::parseInt(String)` and `Integer::parseInt(String, int)` overloads?
- Why does `null::method` throw NPE at reference creation, not invocation?
- How would you create a method reference that throws a checked exception?
- What's the difference between `ArrayList::new` as `Supplier` and as `Function<Integer, ArrayList>`?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.