Method Reference - RichardDanielOliva/java-learning-wiki GitHub Wiki
When the expression lambda is composed of a single sentence and invokes some existing method by means of its name, it is possible to write it using reference methods, which makes the code more compact and easier to read.
There are three (3) types of reference methods and an additional one (1) for constructors:
When the method invoked is static, the way to write the expression lambda using reference methods is as follows: ClassName :: methodStatic, where ClassName is the name of the class containing the method and methodStatic is the name of the static method to be invoked.
In the following example, we define an addition operation by means of the new static method +Integer.sum(int,int):int which sums the two parameters and returns its result.
First let's see how it would be written using a lambda expression:
BinaryOperator<Integer> sum = (a,b) > Integer.sum(a,b);
And now using reference methods:
BinaryOperator<Integer> sum = Integer::sum;
Note the use of the functional interface java.util.function.BinaryOperator, which defines a function that receives two parameters of the same type and returns a result of the same type of its parameters: +apply(T,T):T**.
When we have a reference to an object and we want to invoke one of its instance methods within the lambda expression, the way we would write it using reference methods is as follows: ObjectRef :: methodInstance, where ObjectRef is the reference to the object and methodInstance is the name of the method to be invoked.
For example, the class java.lang.System has a reference to an object of type java.io.PrintStream named out, we will use that reference for our next example.
First let's see how it would be written using a lambda expression:
Consumer<Integer> print = (a) > System.out.println(a);
And now using reference methods:
Consumer<Integer> print = System.out::println;
Note that the reference to the object is in System.out and invoke its instance method +println(int):void.
This case is similar to the previous one, but it differs in that we don't have a reference to an object, we only know its type and we could write the expression lambda in the following way: Type :: methodInstancia, where Type is the class and methodInstancia is the name of the instance method to invoke.
The following example defines a java.lang.Comparator that will allow us to compare strings no matter if they are upper/lower case.
First let's see how it would be written using a lambda expression:
Comparator<String> upper = (a, b) > a.compareToIgnoreCase(b);
And now using reference methods:
Comparator<String> upper = String::compareToIgnoreCase;
Note that in this case we don't have the reference to an object as such, but we know that we want to buy String objects and that's enough for us to write our lambda expression using instance methods of some kind.
In the case of constructors we can write lambda expressions as reference methods in the following way: Class :: new, where Class is the class we want to instantiate and new is the reserved word already known. The use of this reference method for constructors that do not have parameters is simple, but when constructors have parameters, we must change things a little.
First let's see how it would be written using a lambda expression and a constructor without parameters:
Supplier<List> listSupplier = () > new ArrayList();
List list = listSupplier.get();
And now using reference methods:
Supplier<List> listSupplier = ArrayList::new;
List list = listSupplier.get();
Note the use of the java.util.function.Supplier functional interface and the invocation of its +get():T method which returns the list as such.
If the constructor receives parameters, we have to use a functional interface that defines a method that receives the parameters. In the following example, we are going to create a list again, but this time we want to invoke the constructor that receives the initial capacity of the list.
First let's see how it would be written using a lambda expression:
Function<Integer, List> listSupplier = (num) > new ArrayList(num);
List list = listSupplier.apply(5);
And now using reference methods:
Function<Integer, List> listSupplier = ArrayList::new;
List list = listSupplier.apply(5);
Note the use of the java.util.function.Function functional interface and the invocation of its +apply(T):R method which receives the parameter that will then be passed to the constructor. If the constructor receives two parameters, you could use the functional interface java.util.function.BiFunction<T,U,R> which defines the method +apply(T,U):R which receives two parameters.