Functional Interfaces – the new black!

Any Java developer would be familiar with the interfaces such as Runnable, Comparator or Callable. A common feature you would notice in these interfaces is that they declare only one abstract method in the interface definition. Such interfaces are commonly known as Single Abstract Method interfaces or SAM interfaces.

In Java 8, the concept of SAM interfaces has been reintroduced in the form of Functional interfaces. Hence, an interface with exactly one abstract method is called a Functional interface. Java 8 has defined a lot of new Functional interfaces in java.util.function package, and some interfaces such as Predicate, Function, Supplier and Consumer are commonly used.

Given below are some of those interface definitions;

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

// The T is the input argument while R is the return result
@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

The biggest advantage of these Functional interfaces is that Lambda expressions can be used to instantiate them. That is, the abstract method defined in a Functional interface can be implemented using Lambda expressions. This would greatly reduce the amount of code and avoid having to use bulky anonymous class implementations.

Take a look at the example below on Functional interfaces…

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

/**
 * Created by nathasha on 11/12/15.
 */
public class FunctionalInterfaceExample {
    public static void main(String[] args) {

        //A list of ages of people
        List<Integer> ageList = Arrays.asList(12,31,46,30,18,16,37,28,15,22);

        // Lambda Expression
        // age is passed as parameter to test method of Predicate interface
        Predicate<Integer> isAdult = age -> age >= 18;

        System.out.println("The adults are aged:");
        for(Integer n:ageList){

            // test method will return true if age is equal or greater than 18
            boolean adult = isAdult.test(n);

            if (adult==true) System.out.println(n);
        }
    }
}

output:

The adults are aged:
31
46
30
18
37
28
22

Here, the Lambda expression is created by passing age as an argument to the isAdult instant of the Predicate interface. The test method in the Predicate interface will evaluate the parameter and return true if the condition is met.

Here is another example…

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

/**
 * Created by nathasha on 11/12/15.
 */
public class FunctionalInterface {


    public static void main(String[] args) {

        List<Integer> list = Arrays.asList(22,31,46,30,18,33,37,28,34,22);

        System.out.println("Print the list of ages:");
        evaluate(list, age->true);

        System.out.println("Print ages greater than 35:");
        evaluate(list, age-> age > 35 );

    }

    public static void evaluate(List<Integer> list, Predicate<Integer> predicate) {
        for(Integer n: list) {

            if(predicate.test(n)) {
                System.out.printf(n + " ");
            }
        }
        System.out.println();
    }
}

output:

Print the list of ages:
22 31 46 30 18 33 37 28 34 22
Print ages greater than 35:
46 37

Here you can see that the evaluate function takes a list and an instant of the Predicate interface as arguments. That is, with the use of Lambda expressions, instants of interfaces can be easily passed as arguments for methods.

Note

  • When we are declaring our own Functional interface, @FunctionalInterface annotation is used to mark it as a Functional interface. This is optional but is considered best practice in use as this would tell compile time errors. It would ensure that no multiple abstract methods have been defined.
  • If the abstract method defined in the interface takes no arguments, the Lambda expression that implements the method will also take no arguments.
  • A functional interface can have any number of default methods. But it can have only one abstract method. Go through this post to know more about default methods.


One thought on “Functional Interfaces – the new black!

Leave a comment