Codectionary / Developer documentation / Java

Method References

A method reference is shorthand syntax for a lambda that does nothing but call an existing method, using the :: operator. Java supports four kinds: a reference to a static method (ClassName::staticMethod), an instance method on a particular object (object::instanceMethod), an instance method on an arbitrary object of a type (ClassName::instanceMethod), and a constructor reference (ClassName::new).

Syntax

ClassName::methodName

Examples

Static Method Reference

Referring to a static method instead of writing a lambda that just calls it.

import java.util.List;
import java.util.function.Function;

Function<String, Integer> parser = Integer::parseInt;  // instead of s -> Integer.parseInt(s)
System.out.println(parser.apply("42"));  // 42

List<String> numbers = List.of("3", "1", "4", "1", "5");
List<Integer> parsed = numbers.stream()
    .map(Integer::parseInt)
    .toList();
System.out.println(parsed);  // [3, 1, 4, 1, 5]

Instance Method Reference on a Particular Object

Referring to a method on an already-existing object.

import java.util.function.Supplier;

String greeting = "Hello, World!";

Supplier<String> upperSupplier = greeting::toUpperCase;  // instead of () -> greeting.toUpperCase()
System.out.println(upperSupplier.get());  // HELLO, WORLD!

Instance Method Reference on an Arbitrary Object

The most common form used in streams - calling an instance method on whatever object the stream provides.

import java.util.List;

List<String> words = List.of("banana", "apple", "cherry");

List<String> upper = words.stream()
    .map(String::toUpperCase)  // instead of w -> w.toUpperCase()
    .toList();

System.out.println(upper);  // [BANANA, APPLE, CHERRY]

words.stream().sorted(String::compareTo).forEach(System.out::println);

Constructor Reference

Referring to a constructor to create new objects as part of a stream pipeline.

import java.util.List;
import java.util.stream.Collectors;

record Point(int x, int y) {}

List<Integer> xValues = List.of(1, 2, 3);

// Using a constructor-like reference to build simple wrapped values
List<String> labels = xValues.stream()
    .map(x -> "Point-" + x)
    .collect(Collectors.toList());

System.out.println(labels);  // [Point-1, Point-2, Point-3]

Best practices

  • Use a method reference instead of a lambda whenever the lambda body does nothing but call one existing method - it is more concise and often clearer
  • Fall back to a full lambda once you need any extra logic beyond a single direct method call
  • Use System.out::println as a quick, idiomatic replacement for x -> System.out.println(x) inside forEach()
  • Remember method references still require a matching functional interface - the referenced method's signature must be compatible

At a glance

Purpose
General-purpose application development
File extension
.java
Runs in
Java Virtual Machine
Usually used with
JDK and Java libraries

Specifications & further reading

Related Java documentation

Lambda Expressions
A lambda expression is a compact way to represent an anonymous function - a block of code that can be passed around as a value. Lambdas work with functional interfaces (interfaces with exactly one abstract method), letting you replace a full anonymous class implementation with a short, focused expression. Lambdas are the foundation that makes Java's Stream API and functional-style programming possible.
Stream Basics (map, filter, forEach)
The Stream API, introduced in Java 8, provides a functional, declarative way to process sequences of elements from collections, arrays, or other sources. A stream pipeline consists of a source, zero or more intermediate operations (like filter and map, which are lazy and return a new stream), and exactly one terminal operation (like forEach or collect) that actually triggers processing.
Stream Terminal Operations
Terminal operations are what actually trigger a stream pipeline to execute and produce a final result, consuming the stream in the process - after a terminal operation runs, the stream cannot be reused. Common terminal operations include reduce() for combining elements into a single value, count(), sum-style operations for numeric streams, anyMatch()/allMatch() for boolean checks, and findFirst() for retrieving a single element.
Collectors
Collectors, used with the stream terminal operation collect(), provide ready-made ways to accumulate stream elements into a final result - a List, Set, Map, a joined String, or grouped/partitioned data. The java.util.stream.Collectors class offers factory methods like toList(), joining(), groupingBy(), and counting() that cover the vast majority of real-world aggregation needs.