Method references and constructor references are generated based on Lambda expressions. For Lambda expressions, see This post.
1. Concept of method reference
When there are ready-made implementation methods for the operations to be passed to the Lambda problem, you can directly use the method reference!
Method reference can be regarded as a deep expression of Lambda expression. In other words, a method reference is a Lambda expression and an instance of a functional interface. Pointing to a method by its name can be regarded as a syntax sugar of a Lambda expression.
Requirements: the parameter list and return value type of the abstract method implementing the functional interface must be consistent with the parameter list and return value type of the method referenced by the method (mainly used in the following two cases: non static method name and class name:: static method name, class name:: non static method name, which is special and will be described later)!
Format: use the operator:: to separate the class (or object) from the method name. You can use the method reference in the following three forms:
- Instance:: non static method name
- Class name:: static method name
- Class name:: non static method name
2. Use of method references
(1) Instance:: non static method name
// Example 1 public class Main { @Test public void test() { // How to write Lambda expressions Consumer<String> consumer = str -> System.out.println(str); consumer.accept("Welcome to Zhejiang!!!"); /** * Consumer Void accpet in * PrintStream Void println in * The formal parameters and return values of the two functions are the same, and method references can be used directly */ PrintStream ps = System.out; // example Consumer<String> consumer2 = ps :: println; consumer2.accept("Welcome to Zhejiang!!!"); } }
// Example 2 public class Main { @Test public void test() { Employee emp = new Employee(1001, "Tom", 23, 5600); Supplier<String> supplier = () -> emp.getName(); System.out.println(supplier.get()); /** * Supplier T get() in * Employee String getName() in * The formal parameters and return values of the two functions are the same, and method references can be used directly */ Supplier<String> supplier2 = emp :: getName; System.out.println(supplier2.get()); } }
(2) Class name:: static method name
// Example 1 public class Main { @Test public void test() { Comparator<Integer> comparator = (o1, o2) -> Integer.compare(o1, o2); System.out.println(comparator.compare(11, 21)); /** * Comparator Int compare in (t O1, t O2) * Integer Int compare in (t O1, t O2) * The formal parameters and return values of the two functions are the same, and method references can be used directly */ Comparator<Integer> comparator2 = Integer :: compare; System.out.println(comparator2.compare(21, 11)); } }
// Example 2 public class Main { @Test public void test() { // Functional interface, because I saw it for the first time, I will also write about the way to implement anonymous classes Function<Double, Long> function = new Function<Double, Long>() { @Override public Long apply(Double value) { return Math.round(value); } }; System.out.println(function.apply(110.11)); // Then write it with a Lambda expression Function<Double, Long> function2 = value -> Math.round(value); System.out.println(function2.apply(211.985)); /** * Function R apply(T o) in * Math Long round(Double value) in * The formal parameters and return values of the two functions are the same, and method references can be used directly */ Function<Double, Long> function3 = Math :: round; System.out.println(function3.apply(985.211)); } }
(3) Class:: non static method name (difficult)
// Example 1 public class Main { @Test public void test() { // Lambda expression Comparator<String> comparator = (o1, o2) -> o1.compareTo(o2); System.out.println(comparator.compare("abc", "abd")); /** * Comparator Int compare in (t O1, t O2) * String int o1.compareTo(o2) in * Logically, the number of parameters of the compareTO function is inconsistent, which does not meet the requirements of the above method reference * However, if o1 is the body calling the method, this type of function is also allowed to be referenced * The format is: Class Name:: non static member function name, which is memorized according to special cases */ Comparator<String> comparator2 = String :: compareTo; System.out.println(comparator2.compare("abc", "abd")); } }
// Example 2 public class Main { @Test public void test() { // Lambda expression is written logically to judge whether two strings are the same BiPredicate<String, String> biPredicate = (s1, s2) -> s1.equals(s2); System.out.println(biPredicate.test("abc", "abc")); /** * BiPredicate Boolean test in (t O1, t O2); * String boolean o1.equals(o2) in * Logically, the number of parameters of the equals function is inconsistent, which does not meet the requirements of the above method reference * However, if o1 is the body calling the method, this type of function is also allowed to be referenced */ BiPredicate<String, String> biPredicate2 = String :: equals; System.out.println(biPredicate2.test("abc", "abc")); } }
// Example 3 public class Main { @Test public void test() { // Lambda expression is written logically to judge whether two strings are the same Function<Employee, String> function = (emp) -> emp.getName(); System.out.println(function.apply(new Employee(1001, "Tom", 23, 5600))); /** * Function R apply(T o) * Employee String emp.getName() in * Logically, the number of parameters of the getName() function is inconsistent, which does not meet the requirements of the above method reference * However, if o is the body calling the method, this type of function is also allowed to be referenced */ Function<Employee, String> function2 = Employee :: getName; System.out.println(function2.apply(new Employee(1001, "Tom", 23, 5600))); } }
2. Constructor reference
Constructor reference is similar to method reference. The abstract method parameter list of functional interface is consistent with that of constructor.
The return value type of the abstract method is the type of the class to which the constructor belongs.
(1) Parameterless constructor reference
borrow S u p p l i e r Supplier In the Supplier interface R R R g e t ( ) get() get() method implementation.
public class Main { @Test public void test() { // Borrow Supplier interface T get() Supplier<Employee> supplier = new Supplier<Employee>() { @Override public Employee get() { return new Employee(); } }; Employee emp = supplier.get(); // Transform anonymous classes into Lambda expressions Supplier<Employee> supplier2 = () -> new Employee(); Employee emp2 = supplier2.get(); // Using constructor references // You can think of the empty argument constructor of Employee as a function Employee new Employee() Supplier<Employee> supplier3 = Employee :: new; Employee emp3 = supplier3.get(); } }
(2) Single parameter constructor reference
borrow F u n c t i o n Function In the Function interface R R R a p p l y ( T apply(T apply(T t ) t) t) Method implementation:
// Suppose that the Employee class now has a public Employee(int id) constructor with parameters public class Main { @Test public void test() { // Borrow Function interface r apply (T) Function<Integer, Employee> function = new Function<Integer, Employee>() { @Override public Employee apply(Integer id) { return new Employee(id); } }; Employee emp = function.apply(1001); // Transform anonymous classes into Lambda expressions Function<Integer, Employee> function2 = id -> new Employee(id); Employee emp2 = function2.apply(1001); // Similarly, use constructor references Function<Integer, Employee> function3 = Employee :: new; Employee emp3 = function3.apply(1001); } }
(3) Constructor reference for two parameters
borrow B i F u n c t i o n BiFunction BiFunction interface R R R a p p l y ( T apply(T apply(T t , U t, U t,U u ) u) u) Method implementation.
// Suppose that the Employee class now has a public Employee(int id, String name) constructor with parameters public class Main { @Test public void test() { // Borrow BiFunction interface r apply (T, t, U) BiFunction<Integer, String, Employee> biFunction = new BiFunction<Integer, String, Employee>() { @Override public Employee apply(Integer id, String name) { return new Employee(id, name); } }; Employee emp = biFunction.apply(1001, "Tom"); // Transform anonymous classes into Lambda expressions BiFunction<Integer, String, Employee> function2 = (id, name) -> new Employee(id, name); Employee emp2 = biFunction2.apply(1001, "Tom"); // Similarly, use constructor references BiFunction<Integer, String, Employee> function3 = Employee :: new; Employee emp3 = biFunction3.apply(1001, "Tom"); } }
3. Array reference
You can regard the array as a special class, and the writing method is consistent with the constructor reference.
Array reference use F u n c t i o n Function In the Function interface R R R a p p l y ( T apply(T apply(T t ) t) t) Method implementation.
public class Main { @Test public void test() { // Integer passes in the length of the created array, which is written as an anonymous implementation class Function<Integer, String[]> function = new Function<Integer, String[]>() { @Override public String[] apply(Integer length) { return new String[length]; } }; String[] strs = function.apply(10); // Created a String array with a length of 5 System.out.println(Arrays.toString(strs)); // Integer passes in the length of the created array, which is written in Lambda expression Function<Integer, String[]> function1 = length -> new String[length]; String[] strs1 = function1.apply(10); // Created a String array with a length of 5 System.out.println(Arrays.toString(strs1)); // Similarly, use constructor references Function<Integer, String[]> function2 = String[] :: new; String[] strs2 = function2.apply(10); System.out.println(Arrays.toString(strs2)); } }