Tuesday, December 22, 2020

Java 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 a method parameter in Java, the type of the method argument, which receives the lambda expression as a parameter, must be of functional interface type.

Lambda expression as method parameter Java example

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 first 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.

Bloack lambda as method argument Java example

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 Java Lambda Expression as Method Parameter. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Method Reference in Java
  2. Java Lambda Expression And Variable Scope
  3. Exception Handling in Java Lambda Expressions
  4. @FunctionalInterface Annotation in Java
  5. How to Fix The Target Type of This Expression Must be a Functional Interface Error

You may also like-

  1. How ArrayList Works Internally in Java
  2. How HashSet Works Internally in Java
  3. Why wait(), notify() And notifyAll() Must be Called Inside a Synchronized Method or Block
  4. Synchronization in Java - Synchronized Method And Block
  5. Best Practices For Exception Handling in Java
  6. Java Abstract Class and Abstract Method
  7. Just In Time Compiler (JIT) in Java
  8. Circular Dependency in Spring Framework

No comments:

Post a Comment