Skip to main content

8.3 Method References

← Back to Chapter 8: Java 8 Features

Method references provide a compact, easy-to-read shorthand syntax for lambda expressions that simply invoke an existing method by name. They use the :: (double colon) operator.


What is a Method Reference?​

A method reference is simply a shorter way of writing a Lambda expression when the Lambda is only calling an existing method.

Lambda Expressions - Provies the implementaion of already existing method

Method Reference - Refer the method directly without implementing it again

// Lambda:
Consumer<String> lambda = s -> System.out.println(s);

// Method Reference:
Consumer<String> methodRef = System.out::println;

Both essentially mean:

Take name and pass it to System.out.println().

The :: operator is called the method reference operator.


Why was Method Reference introduced?​

Method references were introduced in Java 8, along with Lambda expressions.

The problem was that sometimes we write a Lambda that does nothing except call an existing method.

For example:

names.forEach(name -> System.out.println(name));

The Lambda is basically saying:

Take name and call System.out.println(name).

So Java 8 lets us shorten it:

names.forEach(System.out::println);

This makes the code:

shorter
cleaner
easier to read

Four Kinds of Method References​

Java 8 categorizes method references into four distinct types:

TypeSyntaxLambda EquivalentExample
1. Static MethodClass::staticMethod(args) -> Class.staticMethod(args)Integer::parseInt
2. Instance Method of a Particular Objectinstance::method(args) -> instance.method(args)System.out::println
3. Instance Method of an Arbitrary Object of a Given TypeClass::instanceMethod(target, args) -> target.method(args)String::toUpperCase
4. Constructor ReferenceClass::new(args) -> new Class(args)ArrayList::new

1. Reference to a Static Method​

Syntax: ContainingClass::staticMethodName

Function<String, Integer> parser1 = s -> Integer.parseInt(s);
Function<String, Integer> parser2 = Integer::parseInt;

List<Double> numbers = Arrays.asList(4.0, 16.0, 25.0);
List<Double> squareRoots = numbers.stream()
.map(Math::sqrt)
.collect(Collectors.toList());

2. Reference to an Instance Method of a Particular Object​

Syntax: containingObjectRef::instanceMethodName

String prefix = "SARVY-";
Predicate<String> startsWithPrefix = prefix::startsWith;

PrintStream out = System.out;
Consumer<String> printer = out::println;

3. Reference to an Instance Method of an Arbitrary Object of a Specific Type​

Syntax: ContainingType::methodName Here, the first argument to the lambda becomes the target object upon which the method is invoked.

// Lambda: (s) -> s.toLowerCase()
Function<String, String> toLower = String::toLowerCase;

// Comparing two strings
List<String> names = Arrays.asList("David", "Alice", "Bob");
names.sort(String::compareToIgnoreCase);

4. Reference to a Constructor​

Syntax: ClassName::new

// No-arg constructor via Supplier
Supplier<List<String>> listSupplier = ArrayList::new;
List<String> freshList = listSupplier.get();

// Parameterized constructor via Function
Function<String, User> userFactory = User::new;
User user = userFactory.apply("sarvy");

// Array Constructor Reference
IntFunction<String[]> arrayCreator = String[]::new;
String[] array = arrayCreator.apply(5); // Creates new String[5]

Lambda vs Method Reference: When to Use What?​

ScenarioPreferred ApproachWhy?
Direct 1:1 call to existing methodMethod Reference (String::trim)Cleaner, removes redundant parameter noise
Arguments need modification or calculationLambda (x -> calculate(x * 2))Method reference cannot modify argument values
Ambiguous method overloadsLambda ((String s) -> log(s))Resolves compiler overload ambiguity cleanly
Multi-statement business logicLambda or extract to private methodKeeps functional pipeline clean and readable
Java 8
│
↓
Method Reference
│
::
│
┌─────────────┼─────────────┐
↓ ↓ ↓
Static method Instance Constructor
│ method │
│ │ │
Math::abs obj::method Class::new
│
│
Class::method
(arbitrary object)