Generic Functional Interfaces

  • A lambda expression itself cannot specify type parameters. Thus, a lambda expression cannot be generic.

  • The functional interface associated with a lambda expression can be generic.

  • The target type of the lambda expression is specified when it reference to the functional interface by the type arguments it specifies.

Example:

There is a two functional interfaces as NumericFunc and StringFunc to return numerical values and String values but with the use of Generics we can return both type of values depends on the argument it is passing.

// Use a generic functional interface with lambda expressions.
// A generic functional interface.
interface SomeFunc<T> 
{
 T func(T t);
}
public class GenericFunctionalInterfaceDemo 
{
 public static void main(String args[])
 {
 // Use a String-based version of SomeFunc.
 SomeFunc<String> reverse = (str) -> 
 {
 String result = "";
 int i;
 for(i = str.length()-1; i >= 0; i--)
 result += str.charAt(i);
 return result;
 };
 System.out.println("Lambda reversed is " + reverse.func("Lambda"));
 System.out.println("Expression reversed is " + reverse.func("Expression"));

   // Now, use an Integer-based version of SomeFunc.
 SomeFunc<Integer> factorial = (n) -> 
 {
 int result = 1;
 for(int i=1; i <= n; i++)
 result = i * result;
 return result;
 };
 System.out.println("The factoral of 7 is " + factorial.func(7));
 System.out.println("The factoral of 5 is " + factorial.func(5));
 }
}

Output:

Lambda reversed is adbmaL
Expression reversed is noisserpxE
The factoral of 7 is 5040
The factoral of 5 is 120

Passing Lambda Expressions as Arguments

  • We can pass a lambda expression as an argument which enhances the power of java greatly as it allows an executable statement to a method as an argument.
  • To pass it the type of the parameter receiving the lambda expression argument must be of a functional interface type compatible with the lambda.
// Use lambda expressions as an argument to a method.
interface StringFunc
{
 String func(String n);
}
public class LambdasAsArgumentsDemo 
{
 // the fist parameter can be passed a reference to any instance of that interface as  instance created by a lambda expression.
 // The second parameter specifies the string to operate on.
 static String stringOp(StringFunc sf, String s) 
 {
 return sf.func(s);
 }
 public static void main(String args[])
   {
 String inStr = "Lambdas add power to Java";
 String outStr;
 System.out.println("Here is input string: " + inStr);

   // Here, a simple expression lambda that uppercases a string is passed to stringOp( ).
 outStr = stringOp((str) -> str.toUpperCase(), inStr);
 System.out.println("The string in uppercase: " + outStr);

 // This passes a block lambda that removes spaces.
 outStr = stringOp((str) -> {
 String result = "";
 int i;
 for(i = 0; i < str.length(); i++)
 if(str.charAt(i) != ' ')
 result += str.charAt(i);
 return result;
 }, inStr);
 System.out.println("The string with spaces removed: " + outStr);
 // Of course, it is also possible to pass a StringFunc instance
 // created by an earlier lambda expression. For example,
 // after this declaration executes, reverse refers to an
 // instance of StringFunc.
 StringFunc reverse = (str) -> {
 String result = "";
 int i;
 for(i = str.length()-1; i >= 0; i--)
 result += str.charAt(i);
 return result;
 };
 // Now, reverse can be passed as the first parameter to stringOp()
 // since it refers to a StringFunc object.
 System.out.println("The string reversed: " + stringOp(reverse, inStr));
 }
}

Output:

Here is input string: Lambdas add power to Java
The string in uppercase: LAMBDAS ADD POWER TO JAVA
The string with spaces removed: LambdasaddpowertoJava
The string reversed: avaJ ot rewop dda sadbmaL

Lambda Expressions and Exceptions

  • A lambda expression can throw an exception.
  • if it throws a checked exception , then that must be compatible with the exception(s) listed in the throws clause of the abstract method in the functional interface.
// Throw an exception from a lambda expression.
interface DoubleNumericArrayFunc 
{
 double func(double[] n) throws EmptyArrayException;
}
class EmptyArrayException extends Exception 
{
 EmptyArrayException()
 {
 super("Array Empty");
 }
}
public class LambdaExceptionDemo
{
 public static void main(String args[]) throws EmptyArrayException
 {
 double[] values = { 1.0, 2.0, 3.0, 4.0 ,5.0, 6.0,7.0, 8.0};
 // This block lambda computes the average of an array of doubles.
 DoubleNumericArrayFunc average = (n) -> //the parameter is n even if it is array no need to specify n[] array as the type context from functional interface is double[]
 { 
 double sum = 0;
 if(n.length == 0)
 throw new EmptyArrayException();
 for(int i=0; i < n.length; i++)
 sum += n[i];
 return sum / n.length;
 };
 System.out.println("The average is " + average.func(values));
 // This causes an exception to be thrown.
 System.out.println("The average is " + average.func(new double[0]));
 }
}

Output:

The average is 4.5
Exception in thread "main" EmptyArrayException: Array Empty
at LambdaExceptionDemo.lambda$main$0(LambdaExceptionDemo.java:22)
at LambdaExceptionDemo.main(LambdaExceptionDemo.java:29)

Lambda Expressions and Variable Capture

  • The variables enclosed within lambda expressions are accessible within it only.
  • It can use an instance or static variable defined by its enclosing class.

  • It can also has access to this which refers to the invoking instance of the lambda expression’s enclosing class.

  • It can call a method defined by the enclosing class.

  • When lambda expressions using it's local variables variable capture _will happen where we can't modify the value of the variable if it is assigned once in it's block means like \effectively final_any way we can declare final variables also.

// An example of capturing a local variable from the enclosing scope.
interface MyFunc {
 int func(int n);
}
public class VarCapture 
{
 public static void main(String args[])
 {
 // A local variable that can be captured.
 int num = 10;
 MyFunc myLambda = (n) ->
 {
 // This use of num is OK. It does not modify num.
 int v = num + n;
 // However, the following is illegal because it attempts
 // to modify the value of num.
// num++;
   return v;
 };
 // The following line would also cause an error, because
 // it would remove the effectively final status from num.
// num = 9;

   int i= myLambda.func(13);
   System.out.println("value of i is::"+i);

 }
}

Output:

value of i is::23

results matching ""

    No results matching ""