javabeginner

Method References — All Four Types

Use method references for concise lambda expressions: static, instance, arbitrary object, and constructor.

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

public class MethodRefs {

    // 1. Static method reference: ClassName::staticMethod
    static int square(int n) { return n * n; }

    // 2. Instance method of a particular object: instance::method
    static class Printer {
        String prefix;
        Printer(String prefix) { this.prefix = prefix; }
        void print(String msg) { System.out.println(prefix + msg); }
    }

    // 3. Instance method of an arbitrary object: ClassName::instanceMethod
    // Used when the stream element IS the object to call the method on

    // 4. Constructor reference: ClassName::new
    record User(String name) {}

    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5);
        List<String> names = List.of("Alice", "bob", "Carol");

        // 1. Static method ref
        List<Integer> squares = numbers.stream()
            .map(MethodRefs::square) // instead of n -> square(n)
            .toList();

        // Also: Integer::parseInt, Math::abs, String::valueOf
        List<Integer> parsed = List.of("1", "2", "3").stream()
            .map(Integer::parseInt)
            .toList();

        // 2. Instance method of specific object
        Printer logger = new Printer("[LOG] ");
        names.forEach(logger::print); // instead of n -> logger.print(n)

        // 3. Instance method of arbitrary object (first param becomes `this`)
        List<String> upper = names.stream()
            .map(String::toUpperCase) // instead of s -> s.toUpperCase()
            .toList();

        List<String> sorted = names.stream()
            .sorted(String::compareToIgnoreCase) // (a, b) -> a.compareToIgnoreCase(b)
            .toList();

        // 4. Constructor reference
        List<User> users = names.stream()
            .map(User::new) // instead of name -> new User(name)
            .toList();

        // With functional interfaces
        Function<String, User> factory = User::new;
        Supplier<List<String>> listFactory = ArrayList::new;
        BiFunction<String, String, String> concat = String::concat;

        System.out.println(squares);  // [1, 4, 9, 16, 25]
        System.out.println(upper);    // [ALICE, BOB, CAROL]
        System.out.println(users);    // [User[name=Alice], ...]
    }
}

Use Cases

  • Concise functional-style code with method references
  • Stream pipeline operations
  • Factory patterns with constructor references

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.