Tuesday, 2 June 2015

Lambda expression as method parameter

As we have already seen in the post about functional interface that lambda expression provides implementation for the abstract method present in the functional interface and the target type for the lambda expression is the functional interface. In the simple terms we can say that lambda expression is an object that can be used where ever the reference of functional interface is required.

One of these uses is passing lambda expression as an argument. To pass a lambda expression as an argument the type of the parameter, which receives the lambda expression as an argument, must be of functional interface type.

Let's see an example where we have a functional interface with an abstract method boolean test(int num). Lambda expression n -> n > 5 implements this method, logic here is it will retrun true if the passed int is greater than 5.

interface IMyFunc {
   boolean test(int num);
}

public class LambdaDemo {
    public static List<Integer> filter(IMyFunc testNum, List<Integer> listItems) {
        List<Integer> result = new ArrayList<Integer>();
        for(Integer item: listItems) {
            if(testNum.test(item)) {
                result.add(item);
            }
        }
        return result;
    }
    public static void main(String[] args) {
        List<Integer> myList = new ArrayList<Integer>();
        myList.add(1);
        myList.add(4);
        myList.add(6);
        myList.add(7);
                
        Collection<Integer> values = filter(n -> n > 5, myList);
                
        System.out.println("Filtered values " + values);
    }
}

Output

Filtered values [6, 7]

Here, a lambda expression is passed as an argument. Notice that the second parameter in the filter method is of type IMyFunc (functional interface). We know that a lambda expression itself does not contain the information about the functional interface it is implementing; that information is deduced from the context in which it is used where as functional interface defines the target type of a lambda expression

How that information is deduced is based on these restrictions -

  • The parameter type of the abstract method and the parameter type of the lambda expression must be compatible. For Example, if the abstract method in the functional interface specifies one int parameter, then the lambda should also have one int parameter explicitly defined or implicitly inferred as int by the context.
  • Its return type must be compatible with the method's type.
  • Lambda expression can throw only those exceptions which are acceptable to the method.

It can be seen that in the above program these restrictions are followed. When the execution occurs, an instance of the functional interface IMyFunc is created and a reference to that object is passed to the first parameter of filter method. The code written as lambda expression is an implementation of the abstract method test of the interface, so when we say testNum.test(item) in the filter method lambda expression will be called.

To make it little more simpler main() method can also be written as -

public static void main(String[] args) {
        List<Integer> myList = new ArrayList<Integer>();
        myList.add(1);
        myList.add(4);
        myList.add(6);
        myList.add(7);
        
        // lambda expression
        IMyFunc im = n -> n > 5;
                
        Collection<Integer> values = filter(im, myList);
                
        System.out.println("Filtered values " + values);
}

In the code see this line IMyFunc im = n -> n > 5; it explains what I already stated above, In the simple terms we can say that lambda expression is an object that can be used where ever the reference of functional interface is required.

Block lambda as an argument

We can also have a lambda block which is passed as an argument.
Let us see an example where there is a functional interface that takes string as parameter and returns int.

interface IMyFunc {
    int func(String n);
}

public class LambdaDemo {
    // A utility method to call the functional interface method
    static int utilMeth(IMyFunc myFunc, String str) {
        return myFunc.func(str);
    }
    
    public static void main(String args[])
    {
        String inStr = "Lambdas are a new addition to Java";
        // calling the utilMeth method with 2 params, 
        // first param is a lambda expression
        int count = utilMeth((str) -> {
            int c = 0;
            char ch[]= new char[str.length()];
            for(int i = 0; i < str.length(); i++){
                ch[i] = str.charAt(i);
                if(((i > 0) && (ch[i] != ' ') && (ch[i-1] == ' ')) || 
                  ((ch[0] != ' ') && (i == 0)))
                    c++;
            }
            return c;
        }, inStr);
        System.out.println("The word count is " + count);
    }
}

Here it can be seen that in utilMeth() method first parameter is a lambda block.

Passing a lambda bock like this may decrease the readability of the code and an overly long lambda block may make it very unwieldy. In that case it is advisable to assign the lambda block to a functional interface reference and then pass that reference to the method.

interface IMyFunc {
    int func(String n);
}

public class LambdaDemo {
    // A utility method to call the functional interface method
    static int utilMeth(IMyFunc myFunc, String str) {
        return myFunc.func(str);
    }
    
    public static void main(String args[])
    {
        String inStr = "Lambdas are a new addition to Java";
        // lamda block assigned to a functional interface reference
        IMyFunc myFunc = (str) -> {
            int c = 0;
            char ch[]= new char[str.length()];
            for(int i = 0; i < str.length(); i++){
                ch[i] = str.charAt(i);
                if(((i > 0) && (ch[i] != ' ') && (ch[i-1] == ' ')) || 
                  ((ch[0] != ' ') && (i == 0)))
                    c++;
            }
            return c;
        };
        // calling the utilMeth method with that functional interface 
        // variable that holds the lambda expression
        int count = utilMeth(myFunc, inStr);
        System.out.println("The word count is " + count);
    }
}

It can be seen that lambda block is assigned to the functional interface reference and then that reference is passed.

That's all for this topic Lambda expression as method parameter. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Overview of lambda expressions
  2. Functional interfaces & lambda expression
  3. Lambda expression and exception handling
  4. Lambda expression and variable scope
  5. Functional interface annotation in Java 8
  6. Method reference in Java 8
  7. Lambda expression examples in Java 8

You may also like -

No comments:

Post a Comment