Tuesday, 2 June 2015

Functional interfaces in Java 8

A functional interface is an interface with only one abstract method. A functional interface is also known as SAM type where SAM stands for (Single Abstract Method). An example of functional interface with in Java would be Runnable interface which has only one method run().

Example of functional interface

interface IMyInterface {
    int getValue();
}
 

In interface IMyInterface there is only single abstract method getValue() (note that in an interface methods are implicitly abstract).

Please note that from Java 8 it is possible for an interface to have default method and static method thus the stress on "only one abstract method" because in a functional interface there may be other default and static methods but there must be only one abstract method.

As Exp.

@FunctionalInterface
interface IFuncInt {
    int func(int num1, int num2);
    // default method
    default int getValue(){
        return 0;
    }    
}

Here we have a default method too with in the functional interface but it is a valid functional interface. Also note that the interface is annotated with @FunctionalInterface this is a new annotation added in Java 8, all the functional interfaces can be annotated with @FunctionalInterface to ensure that they have a single abstract method.

A functional interface can specify Object class public methods too in addition to the abstract method. That interface will still be a valid functional interface. The public Object methods are considered implicit members of a functional interface as they are automatically implemented by an instance of functional interface.
As exp. :This is a valid functional interface -

@FunctionalInterface
interface IFuncInt {
    int func(int num1, int num2);
    // default method
    default int getValue(){
        return 0;
    }
 
    public String toString();
    public boolean equals(Object o);
}

Functional interface and lambda expression

A lambda expression is used with a functional interface; lambda expression provides implementation of the abstract method defined by the functional interface.

Target Type of a Lambda Expression

Lambda expression doesn't have a type of its own, its functional interface that specifies the target type of a lambda expression. The target type of the lambda expression is inferred from the context where it is used. Therefore, lambda expressions can be used only in contexts in which the target type can be inferred. In simple terms it can be understood as wherever we could pass the reference of the class which implements the interface now we can pass lambda expression.
Let's see an example -

interface IMyFunc {
    int getValue(int num);
}

public class LambdaDemo {

    public static void main(String[] args) {
        IMyFunc myFactorialFunc = (num) -> {
            int fact = 1;
            for(int i = 1; i <= num; i++){
                fact = i * fact;
            }
            return fact;
        };
        System.out.println("Factorial of 7 is " + myFactorialFunc.getValue(7));
    }
}

Output

Factorial of 7 is 5040

Here we have an interface IMyFunc with one method getValue() whose return type is int and it also takes one int parameter. Since there is only one abstract method in the interface so IMyFunc is a functional interface.

In this code we can say that behind the scene an instance of the class is created which implements the functional interface, where lambda expression provides the implementation of the abstract method declared by the functional interface.

When the method is called through the interface reference (target type) i.e. myFactorialFunc.getValue in this code, lambda expression will be executed, as that is providing the implementation for the getValue method of the interface.

The contexts where lambda expression can be used are -

  • Variable declarations
  • Assignments
  • Return statements
  • Array initializers
  • Method or constructor arguments
  • Lambda expression bodies
  • A ternary conditional expression
  • A cast expression

Generic functional interface

As we have already seen lambda expression doesn't have type parameters of its own so it can't be generic. But the functional interface that specifies the target type for the lambda expression can be generic. Thus as in the normal case with generics types, type of data upon which they operate is specified as a parameter and using those parameters type of lambda expression is inferred.

As exp. : If we have a functional interface

interface IMyFunc<T, R> {
    R func(T t);
}

Now when we declare the interface reference and specify the type of the parameter, lambda expression will have the same type too.

public class LambdaDemo {
    public static void main(String[] args) {
        // Lambda expression block
          //Here functional interface is declared with types
          // of the parameter 
        IMyFunc<String, Integer> countWords = (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;
        };                
        System.out.println("Words in the string " + countWords.func("Functional interface in Java"));
    }
}

Output

Words in the string 4

Here a Lambda expression block is written which counts the number of words in a String. This lambda expression in implementing the functional interface IMyFunc, which is a generic interface.

Since interface IMyFunc is declared with parameters String and Integer so lambda expression which implements this functional interface will also have the same types of parameters.

Inbuilt functional interfaces

Before Java 8 there were already several functional interfaces but the term functional interface has come into prominence because of Lambda expressions -

Some functional interfaces which were already there -

public interface Comparator<T> {
 int compare(T o1, T o2);
}
 
public interface Callable<V> {
  V call() throws Exception;
}
 
public interface ActionListener extends EventListener {
  public void actionPerformed(ActionEvent e);
}

public interface Runnable {
  public void run();
}

Now with Java 8 many new functional interfaces are being defined, in fact there is a whole new package java.util.function added with many functional interfaces. The interfaces in this package are general purpose functional interfaces used by the JDK, and are available to be used by user code as well.

The following are some of the examples of new functional interfaces in Java-

public interface Predicate<T> {
  boolean test(T t);
}
 
public interface Function<T,R> {
  R apply(T t);
}
 
public interface BinaryOperator<T> {
  T apply(T left, T right);
}
 
public interface Consumer<T> {
  void accept(T t);
}
 
public interface Supplier<T> {
  T get();
}

Starting with Java 8 these functional interfaces can be implemented by means of lambda expressions and method references.
Supposing we want to use already given functional interface named Predicate declared as follows:

public interface Predicate<T> {
  boolean test(T t);
}

We don't need to explicitly define this interface as it is already provided so we just need to import that interface -
import java.util.function.Predicate

Now let's say we have a method which filters the contents of a collection based on a provided predicate (return collection item only if it is greater than 5)

public class LambdaDemo {
    public static <T> Collection<T> filter(Predicate<T> predicate, Collection<T> listItems) {
        Collection<T> result = new ArrayList<T>();
        for(T item: listItems) {
            if(predicate.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);
    }
}

Here we have a filter method which has one parameter as the predicate interface, that's the parameter to which we are passing the lambda expression (n -> n > 5) that implements the test() method of the interface, another parameter is the list which has 4 integer values.

Output

Filtered values [6, 7]

Points to note -

  • A functional interface is an interface with only one abstract method.
  • A functional interface is also known as SAM type where SAM stands for (Single Abstract Method).
  • A functional interface can be annotated with @FunctionalInterface annotation to ensure that it has a single abstract method.
  • In a functional interface there may be other default and static methods but there must be only one abstract method.
  • A functional interface can specify Object class public methods too in addition to the abstract method.
  • Lambda expression can provide implementation of the abstract method defined by the functional interface.
  • Functional interface specifies the target type of a lambda expression, lambda expression doesn't have a type of its own.
  • In Java 8 many new functional interfaces are defined, in fact there is a whole new package java.util.function added with many functional interfaces.

That's all for this topic Functional interfaces in Java 8. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

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

You may also like -

No comments:

Post a Comment