// MethodReferences.java — the four kinds of method reference.
import java.util.*;
import java.util.function.*;

public class MethodReferences {

    static boolean isValidSku(String s) {
        return s.matches("[A-Z]{2}-\\d{3}");
    }

    record Customer(String name) {
        String greeting() { return "Hello, " + name; }
    }

    public static void main(String[] args) {
        List<String> skus = List.of("AX-200", "bad", "BX-310");

        // 1. Static method:            ClassName::staticMethod
        Predicate<String> valid = MethodReferences::isValidSku;          // s -> isValidSku(s)
        System.out.println(skus.stream().filter(valid).toList());       // [AX-200, BX-310]

        // 2. Instance method of a particular object:  object::method
        String prefix = "SKU:";
        Predicate<String> hasPrefix = prefix::equals;                     // s -> prefix.equals(s)
        System.out.println(hasPrefix.test("SKU:"));                      // true
        skus.forEach(System.out::println);                               // s -> System.out.println(s)

        // 3. Instance method of an arbitrary object of a type:  ClassName::instanceMethod
        Function<String, String> upper = String::toUpperCase;            // s -> s.toUpperCase()
        Function<Customer, String> greet = Customer::greeting;           // c -> c.greeting()
        System.out.println(upper.apply("acme") + " / " + greet.apply(new Customer("Globex")));

        // 4. Constructor:              ClassName::new
        Function<String, Customer> create = Customer::new;               // n -> new Customer(n)
        Supplier<List<String>> newList = ArrayList::new;                 // () -> new ArrayList<>()
        List<String> names = newList.get();
        names.add(create.apply("Initech").name());
        System.out.println(names);                                       // [Initech]

        // Comparator built from method references
        List<Customer> customers = new ArrayList<>(List.of(new Customer("Zed"), new Customer("Amy")));
        customers.sort(Comparator.comparing(Customer::name));
        System.out.println(customers);
    }
}
