Friday, March 4, 2016

Method Refernce(double colon operator) vs Lambda Expression in Java 8

In our previous post we saw that we can use lambda expression to implement function interface.But it is not the only way to implement functional interface. A new feature introduced in Java 8 known as Method Reference.It has the ability to replace an instance  of functional interface with a method having same argument as the method of the functional interface.Usually in Java :: operator is used for method reference.The method in the functional interface and the passing method reference should match for the argument and return type.
Let's take an example

package com.brainatjava;

import java.util.Arrays;

import java.util.List;

import java.util.function.Predicate;

public class Test {

    static List wordList = Arrays.asList(new String[]{"a","b","Lambda","d"});
    public static void findString(List list, Predicate predicate) {
            for (String p : list) {
                if (predicate.test(p)) {
                   System.out.println("we found Lambda by method expression.");
                }             }         }     public static void main(String[] args) {         Predicate predicate=Test::check;         findString(wordList,predicate);     }     public static boolean check(String value){         return value.equalsIgnoreCase("Lambda");     } }

@FunctionalInterface
public interface Predicate {
    boolean test(T t); }
Here if we  look at the findString() method, we see that a functional interface named Predicate is used.And we used the abstract method test() of the interface Predicate  to verify the result.

In our above example  we have defined method named check() in our class Test having same signature as method test() of funcational interface Predicate.So we can use method expression here.So in main method we call findString as findString(wordList,Test::check).By using method expression we utilized the existing method check().As we stated above that we can replace an instance of the functional interface with a method expression.So we could write  the line  Predicate predicate=Test::check.Here check is a static method of our class Test so we use it directly along with the class name.And used the instance of Predicate in findString method as findString(wordList,predicate).Just note the use of ::(double colon) operator , we are not calling the check() method,but we are only getting a reference to it's name.

Method reference are three types
1.Static Method References
2.Instance Method Reference
3.Constructor Method References

Now let's consider another functional interface namely Function provided in Java 8.

@FunctionalInterface
public interface Function <T,R>{

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

....
....
//along with some other methods

}


It has an abstract method namely apply having argument T and return type R.
Suppose we have a requirement to take some strings and convert those into doubles.
So we will take the help of the apply() method of the above  functional interface.
So we wrote a method namely changeFormat like below.

public static  List changeFormat(Function function, List source) {
        List sink = new ArrayList<>();
        for (T item : source) {
        R value = function.apply(item);
        sink.add(value);
        }
        return sink;
        }

As we know that the job of a method refernece is to replace an instance of the functional interface.Now here we will do the same.But we know very well that Java has a constructor of Double class like below.

public Double(String s) throws NumberFormatException {
        value = parseDouble(s);
    }
If we observe here we find that the signature of the above Double constructor is similar with the apply method of the functional interface.
So we can replace the instance of the functional interface with the method reference.But this time we call it as Constructor Method References, as we are using a constructor here.So we can write the same as

Function function=Double::new;
By adding the above code segments in a main method ,our complete code look like below.
package com.brainatjava;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

public class Test {
  
    public static void main(String[] args) {
        List digits = Arrays.asList("1","2","9","7","5");
        Function function=Double::new;
        List numbers = changeFormat(function, digits);
    }
public static List changeFormat(Function function, List source) {
        List sink = new ArrayList<>();
        for (T item : source) {
        R value = function.apply(item);
        sink.add(value);
        }
        return sink;
        }
  
}

Please refer the series java streams which always used with lambda expression for parallel processing.

No comments:

Post a Comment