Java 8 new features: method reference, constructor reference and array reference

Posted by carydean on Sat, 06 Nov 2021 23:01:02 +0100


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:

  1. Instance:: non static method name
  2. Class name:: static method name
  3. 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));
	}
}

Topics: Java