Home/Learn/Java A–Z/Method References

Method References

Intermediate
Streams & Functional Java

Replace verbose lambdas with concise :: method references — four forms covering static, bound instance, unbound instance, and constructor references.

Overview

A method reference is shorthand for a lambda that does nothing but call an existing method. The :: operator names the method without calling it. There are four forms: static (Class::staticMethod), bound instance (obj::method), unbound instance (Class::method where first lambda arg is the receiver), and constructor (Class::new). They make stream pipelines more readable and eliminate boilerplate.

Four Forms of Method References

Static: Integer::parseInt → s -> Integer.parseInt(s) Bound instance: str::startsWith → s -> str.startsWith(s) Unbound instance: String::toLowerCase → s -> s.toLowerCase() Constructor: ArrayList::new → () -> new ArrayList<>()

MethodRefForms.java
import java.util.*;
import java.util.stream.*;
import java.util.function.*;

public class MethodRefForms {
    static int doubleIt(int n) { return n * 2; }

    public static void main(String[] args) {
        // 1. Static method reference
        Function<String, Integer> parser = Integer::parseInt;
        System.out.println(parser.apply("42")); // 42

        IntUnaryOperator dbl = MethodRefForms::doubleIt;
        System.out.println(dbl.applyAsInt(5)); // 10

        // 2. Bound instance — object is fixed
        String prefix = "Hello";
        Predicate<String> startsWithHello = prefix::startsWith; // fixed receiver
        System.out.println(startsWithHello.test("Hello World")); // true

        // 3. Unbound instance — object is first lambda arg
        Function<String, String> upper = String::toUpperCase;
        Comparator<String> cmp = String::compareTo;
        System.out.println(upper.apply("java")); // JAVA

        // 4. Constructor reference
        Supplier<List<String>> listFactory = ArrayList::new;
        Function<Integer, int[]> arrFactory = int[]::new;
        List<String> list = listFactory.get();
        int[] arr = arrFactory.apply(5);
        System.out.println(arr.length); // 5

        // Practical stream pipeline with method refs
        List<String> nums = List.of("3", "1", "4", "1", "5");
        List<Integer> sorted = nums.stream()
            .map(Integer::parseInt)          // static
            .sorted(Integer::compareTo)      // unbound
            .collect(Collectors.toList());
        System.out.println(sorted); // [1, 1, 3, 4, 5]

        // Constructor ref in stream
        List<StringBuilder> sbs = List.of("a","b","c").stream()
            .map(StringBuilder::new)         // constructor ref
            .collect(Collectors.toList());
        sbs.forEach(sb -> sb.append("!"));
        System.out.println(sbs); // [a!, b!, c!]
    }
}

Method References in Practice

Method references shine in stream pipelines, Comparator chains, and event handlers. They are most readable when the method name clearly communicates intent. Prefer a lambda when the method reference would require mental indirection.

MethodRefPractice.java
import java.util.*;
import java.util.stream.*;

public class MethodRefPractice {
    record Person(String name, int age) {}

    public static void main(String[] args) {
        List<Person> people = List.of(
            new Person("Charlie", 30),
            new Person("Alice",   25),
            new Person("Bob",     35));

        // Comparator chains with method references
        List<Person> sorted = people.stream()
            .sorted(Comparator.comparingInt(Person::age)
                .thenComparing(Person::name))
            .collect(Collectors.toList());
        sorted.forEach(p -> System.out.println(p.name() + ":" + p.age()));

        // Printing with method reference
        people.stream()
            .map(Person::name)
            .forEach(System.out::println);  // bound instance on System.out

        // Filtering with static method ref
        List<String> strs = List.of("", "hello", "", "world");
        long nonEmpty = strs.stream()
            .filter(Predicate.not(String::isBlank)) // static method
            .count();
        System.out.println(nonEmpty); // 2

        // Collecting names to uppercase
        String result = people.stream()
            .map(Person::name)
            .map(String::toUpperCase)
            .collect(Collectors.joining(", "));
        System.out.println(result); // CHARLIE, ALICE, BOB → sorted earlier: ALICE, CHARLIE, BOB
    }
}

When to Use Lambda vs Method Reference

Use a method reference when: • The lambda does nothing but call one existing method • The method name is self-documenting

Use a lambda when: • The logic involves more than a single method call • You need to adapt parameters (e.g., swap order) • The method reference would be confusing

LambdaVsRef.java
import java.util.*;
import java.util.stream.*;
import java.util.function.*;

public class LambdaVsRef {
    public static void main(String[] args) {
        List<String> words = List.of("banana","apple","cherry");

        // PREFER method reference — single method call
        words.stream().map(String::length).forEach(System.out::println);

        // PREFER lambda — adapting parameter order
        words.sort((a, b) -> b.compareTo(a)); // reverse — no clean method ref

        // PREFER lambda — multiple operations
        words.stream()
            .filter(w -> w.length() > 4 && w.startsWith("b"))
            .forEach(System.out::println);

        // Predicate.not() wraps an instance method ref for negation
        Predicate<String> notEmpty = Predicate.not(String::isEmpty); // Java 11+
        System.out.println(words.stream().filter(notEmpty).count()); // 3

        // BiFunction with unbound method ref
        BiFunction<String, String, Boolean> contains = String::contains;
        System.out.println(contains.apply("hello world", "world")); // true
    }
}

Interactive Visualization

.source()
.filter()
.map()
.sorted()
.collect()
1
2
3
4
5
6
7
8
stream.filter(n → n%2==0).map(n → n*n).sorted().collect(toList())
Source: a stream of integers [1, 2, 3, 4, 5, 6, 7, 8].
1 / 5

Key Points to Remember

  • Four forms: Class::staticMethod, instance::method, Class::instanceMethod, Class::new
  • Unbound instance ref (String::toUpperCase) takes the receiver as the first lambda argument
  • Constructor ref (ArrayList::new) is equivalent to () -> new ArrayList<>()
  • System.out::println is a bound instance reference — System.out is the fixed receiver
  • Prefer method references when the name communicates intent clearly; use lambdas for complex logic
  • Predicate.not(method::ref) (Java 11+) negates a method reference cleanly

Practice Method References in the Playground

Run and modify code directly in your browser - no setup needed.

Interview Questions

Sign in to ask Aria
1

What are the four types of method references in Java?

MediumAmazon
2

What is the difference between a bound and unbound instance method reference?

MediumGoogle
3

How does String::toUpperCase differ from s -> s.toUpperCase()?

EasyOracle
4

When would you use a constructor reference?

EasyMicrosoft
5

Can a method reference throw a checked exception?

MediumTCS

Ask Aria about Method References

Your personal AI tutor — ask anything about this concept