Your lambda is just x -> x.toString(). Method reference Object::toString is cleaner. When lambda only calls an existing method, use method reference instead. Same result, more readable.

Static method reference

Reference a static method.

Static.java
import java.util.*;
import java.util.function.*;

public class Static {

    private static int parseIntSafe(String s) {
        return Integer.parseInt(s.trim());
    }

    public static void main(String[] args) {
        Function<String, Integer> a = s -> Integer.parseInt(s);
        Function<String, Integer> b = Integer::parseInt;

        String numericInput = ;
        System.out.println("a('" + numericInput + "') = " + a.apply(numericInput));
        System.out.println("b('" + numericInput + "') = " + b.apply(numericInput));

        Function<String, Integer> safe = Static::parseIntSafe;
        System.out.println("safe(' 7 ') = " + safe.apply(" 7 "));

        List<String> nums = new ArrayList<>(Arrays.asList("10", "2", "30"));
        nums.sort(Comparator.comparingInt(Integer::parseInt));
        System.out.println("sorted numeric strings: " + nums);

    }
}
import java.util.*;
import java.util.function.*;

public class Static {

    private static int parseIntSafe(String s) {
        return Integer.parseInt(s.trim());
    }

    public static void main(String[] args) {
        Function<String, Integer> a = s -> Integer.parseInt(s);
        Function<String, Integer> b = Integer::parseInt;

        String numericInput = ;
        System.out.println("a('" + numericInput + "') = " + a.apply(numericInput));
        System.out.println("b('" + numericInput + "') = " + b.apply(numericInput));

        Function<String, Integer> safe = Static::parseIntSafe;
        System.out.println("safe(' 7 ') = " + safe.apply(" 7 "));

        List<String> nums = new ArrayList<>(Arrays.asList("10", "2", "30"));
        nums.sort(Comparator.comparingInt(Integer::parseInt));
        System.out.println("sorted numeric strings: " + nums);

    }
}
import java.util.*;
import java.util.function.*;

public class Static {

    private static int parseIntSafe(String s) {
        return Integer.parseInt(s.trim());
    }

    public static void main(String[] args) {
        Function<String, Integer> a = s -> Integer.parseInt(s);
        Function<String, Integer> b = Integer::parseInt;

        String numericInput = ;
        System.out.println("a('" + numericInput + "') = " + a.apply(numericInput));
        System.out.println("b('" + numericInput + "') = " + b.apply(numericInput));

        Function<String, Integer> safe = Static::parseIntSafe;
        System.out.println("safe(' 7 ') = " + safe.apply(" 7 "));

        List<String> nums = new ArrayList<>(Arrays.asList("10", "2", "30"));
        nums.sort(Comparator.comparingInt(Integer::parseInt));
        System.out.println("sorted numeric strings: " + nums);

    }
}

ClassName::staticMethod - equivalent to x -> ClassName.staticMethod(x).

method reference Shorthand for lambdas: `String::valueOf` instead of `x -> String.valueOf(x)`.

Instance method reference

Reference an instance method.

Instance.java
import java.util.function.*;

public class Instance {

    static class Prefixer {
        private final String prefix;

        Prefixer(String prefix) {
            this.prefix = prefix;
        }

        String addPrefix(String s) {
            return prefix + s;
        }
    }

    public static void main(String[] args) {
        String prefix = ;
        Prefixer p = new Prefixer(prefix);

        Function<String, String> f1 = s -> p.addPrefix(s);
        Function<String, String> f2 = p::addPrefix;

        System.out.println(f1.apply("Alice"));
        System.out.println(f2.apply("Bob"));

        Supplier<String> supplier1 = () -> "  hi  ".trim();
        Supplier<String> supplier2 = "  hi  "::trim;

        System.out.println("supplier1 = '" + supplier1.get() + "'");
        System.out.println("supplier2 = '" + supplier2.get() + "'");

    }
}
import java.util.function.*;

public class Instance {

    static class Prefixer {
        private final String prefix;

        Prefixer(String prefix) {
            this.prefix = prefix;
        }

        String addPrefix(String s) {
            return prefix + s;
        }
    }

    public static void main(String[] args) {
        String prefix = ;
        Prefixer p = new Prefixer(prefix);

        Function<String, String> f1 = s -> p.addPrefix(s);
        Function<String, String> f2 = p::addPrefix;

        System.out.println(f1.apply("Alice"));
        System.out.println(f2.apply("Bob"));

        Supplier<String> supplier1 = () -> "  hi  ".trim();
        Supplier<String> supplier2 = "  hi  "::trim;

        System.out.println("supplier1 = '" + supplier1.get() + "'");
        System.out.println("supplier2 = '" + supplier2.get() + "'");

    }
}
import java.util.function.*;

public class Instance {

    static class Prefixer {
        private final String prefix;

        Prefixer(String prefix) {
            this.prefix = prefix;
        }

        String addPrefix(String s) {
            return prefix + s;
        }
    }

    public static void main(String[] args) {
        String prefix = ;
        Prefixer p = new Prefixer(prefix);

        Function<String, String> f1 = s -> p.addPrefix(s);
        Function<String, String> f2 = p::addPrefix;

        System.out.println(f1.apply("Alice"));
        System.out.println(f2.apply("Bob"));

        Supplier<String> supplier1 = () -> "  hi  ".trim();
        Supplier<String> supplier2 = "  hi  "::trim;

        System.out.println("supplier1 = '" + supplier1.get() + "'");
        System.out.println("supplier2 = '" + supplier2.get() + "'");

    }
}

object::method - equivalent to x -> object.method(x).

Unbound instance method

Reference method on parameter object.

Unbound.java
import java.util.*;
import java.util.function.*;

public class Unbound {
    public static void main(String[] args) {
        BiFunction<String, String, Boolean> startsWith1 = (s, prefix) -> s.startsWith(prefix);
        BiFunction<String, String, Boolean> startsWith2 = String::startsWith;

        String prefixToCheck = ;
        System.out.println("startsWith2('Alice','" + prefixToCheck + "') = " +
                           startsWith2.apply("Alice", prefixToCheck));
        System.out.println("startsWith2('Bob','" + prefixToCheck + "') = " +
                           startsWith2.apply("Bob", prefixToCheck));

        List<String> names = new ArrayList<>(Arrays.asList("Charlie", "alice", "Bob"));
        names.sort(String::compareToIgnoreCase);
        System.out.println("sorted ignore-case: " + names);

        List<String> raw = Arrays.asList("  a ", " b", "c  ");
        List<String> trimmed = new ArrayList<>();
        raw.forEach(s -> trimmed.add(s.trim()));
        System.out.println("trimmed via lambda: " + trimmed);

        trimmed.clear();
        raw.forEach(s -> trimmed.add(s.trim()));
        System.out.println("trimmed again: " + trimmed);

    }
}
import java.util.*;
import java.util.function.*;

public class Unbound {
    public static void main(String[] args) {
        BiFunction<String, String, Boolean> startsWith1 = (s, prefix) -> s.startsWith(prefix);
        BiFunction<String, String, Boolean> startsWith2 = String::startsWith;

        String prefixToCheck = ;
        System.out.println("startsWith2('Alice','" + prefixToCheck + "') = " +
                           startsWith2.apply("Alice", prefixToCheck));
        System.out.println("startsWith2('Bob','" + prefixToCheck + "') = " +
                           startsWith2.apply("Bob", prefixToCheck));

        List<String> names = new ArrayList<>(Arrays.asList("Charlie", "alice", "Bob"));
        names.sort(String::compareToIgnoreCase);
        System.out.println("sorted ignore-case: " + names);

        List<String> raw = Arrays.asList("  a ", " b", "c  ");
        List<String> trimmed = new ArrayList<>();
        raw.forEach(s -> trimmed.add(s.trim()));
        System.out.println("trimmed via lambda: " + trimmed);

        trimmed.clear();
        raw.forEach(s -> trimmed.add(s.trim()));
        System.out.println("trimmed again: " + trimmed);

    }
}
import java.util.*;
import java.util.function.*;

public class Unbound {
    public static void main(String[] args) {
        BiFunction<String, String, Boolean> startsWith1 = (s, prefix) -> s.startsWith(prefix);
        BiFunction<String, String, Boolean> startsWith2 = String::startsWith;

        String prefixToCheck = ;
        System.out.println("startsWith2('Alice','" + prefixToCheck + "') = " +
                           startsWith2.apply("Alice", prefixToCheck));
        System.out.println("startsWith2('Bob','" + prefixToCheck + "') = " +
                           startsWith2.apply("Bob", prefixToCheck));

        List<String> names = new ArrayList<>(Arrays.asList("Charlie", "alice", "Bob"));
        names.sort(String::compareToIgnoreCase);
        System.out.println("sorted ignore-case: " + names);

        List<String> raw = Arrays.asList("  a ", " b", "c  ");
        List<String> trimmed = new ArrayList<>();
        raw.forEach(s -> trimmed.add(s.trim()));
        System.out.println("trimmed via lambda: " + trimmed);

        trimmed.clear();
        raw.forEach(s -> trimmed.add(s.trim()));
        System.out.println("trimmed again: " + trimmed);

    }
}

String::length - equivalent to s -> s.length(). First param becomes receiver.

Constructor reference

Reference a constructor.

Constructor.java
import java.util.*;
import java.util.function.*;

public class Constructor {

    static class User {
        final String name;

        User(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "User(" + name + ")";
        }
    }

    public static void main(String[] args) {
        Function<String, User> makeUser1 = name -> new User(name);
        Function<String, User> makeUser2 = User::new;

        String userName = ;
        System.out.println(makeUser1.apply(userName));
        System.out.println(makeUser2.apply("Bob"));

        Supplier<List<String>> listSupplier = ArrayList::new;
        List<String> list = listSupplier.get();
        list.add("x");
        list.add("y");
        System.out.println("list: " + list);

        Supplier<Map<String, Integer>> mapSupplier = LinkedHashMap::new;
        Map<String, Integer> map = mapSupplier.get();
        map.put("a", 1);
        System.out.println("map: " + map);

    }
}
import java.util.*;
import java.util.function.*;

public class Constructor {

    static class User {
        final String name;

        User(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "User(" + name + ")";
        }
    }

    public static void main(String[] args) {
        Function<String, User> makeUser1 = name -> new User(name);
        Function<String, User> makeUser2 = User::new;

        String userName = ;
        System.out.println(makeUser1.apply(userName));
        System.out.println(makeUser2.apply("Bob"));

        Supplier<List<String>> listSupplier = ArrayList::new;
        List<String> list = listSupplier.get();
        list.add("x");
        list.add("y");
        System.out.println("list: " + list);

        Supplier<Map<String, Integer>> mapSupplier = LinkedHashMap::new;
        Map<String, Integer> map = mapSupplier.get();
        map.put("a", 1);
        System.out.println("map: " + map);

    }
}
import java.util.*;
import java.util.function.*;

public class Constructor {

    static class User {
        final String name;

        User(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "User(" + name + ")";
        }
    }

    public static void main(String[] args) {
        Function<String, User> makeUser1 = name -> new User(name);
        Function<String, User> makeUser2 = User::new;

        String userName = ;
        System.out.println(makeUser1.apply(userName));
        System.out.println(makeUser2.apply("Bob"));

        Supplier<List<String>> listSupplier = ArrayList::new;
        List<String> list = listSupplier.get();
        list.add("x");
        list.add("y");
        System.out.println("list: " + list);

        Supplier<Map<String, Integer>> mapSupplier = LinkedHashMap::new;
        Map<String, Integer> map = mapSupplier.get();
        map.put("a", 1);
        System.out.println("map: " + map);

    }
}

ClassName::new - equivalent to () -> new ClassName() or x -> new ClassName(x).

constructor reference `ArrayList::new` creates new ArrayList. Used with `Supplier` or `Function`.

Method references with collections

Common patterns in collection operations.

Collections.java
import java.util.*;
import java.util.function.*;

public class Collections {

    private static <T> void forEach(List<T> items, Consumer<T> action) {
        for (T item : items) {
            action.accept(item);
        }
    }

    private static <T, R> List<R> map(List<T> items, Function<T, R> fn) {
        List<R> out = new ArrayList<>();
        for (T item : items) {
            out.add(fn.apply(item));
        }
        return out;
    }

    public static void main(String[] args) {
        List<String> raw = Arrays.asList("  Alice ", " Bob", "CHARLIE  ");

        List<String> trimmed = map(raw, String::trim);
        System.out.println("trimmed: " + trimmed);

        List<String> lowered = map(trimmed, String::toLowerCase);
        System.out.println("lowered: " + lowered);

        forEach(lowered, System.out::println);

        List<String> sorted = new ArrayList<>(lowered);
        sorted.sort(String::compareTo);
        System.out.println("sorted: " + sorted);

    }
}

list.forEach(System.out::println) - clean iteration with method reference.

Exercise: Practical.java

Refactor lambdas to method references