The Functional Interface is introduced in Java 8, and it is nothing but an interface with a Single Abstract Method (SAM). A functional interface can act as a target for a lambda expression or a method reference.
Functional Interface in Java
There are several functional interfaces already available in Java, even before Java 8, such as Callable, Comparable, Runnable, ActionListener, etc.
public interface Callable { V call() throws Exception; } public interface Runnable { void run(); } public interface ActionListener extends EventListener { void actionPerformed(ActionEvent e); }
In Java 8, there is a separate package java.util.function for the functional interfaces such as Predicate, Function, Consumer, Supplier, etc.
To start with, let’s create a simple, functional interface.
public interface PrimeNumberValidator { boolean isPrime(int number); }
Since the above interface has only one abstract method, it is a functional interface. From Java 8 onwards, we are allowed to have default and static methods in an interface.
It is perfectly valid to have static and default methods in a functional interface.
package com.javainterviewpoint; public interface PrimeNumberValidator { boolean isPrime(int number); default void myDefaultMethod() { System.out.println("Default Method"); } static void myStaticMethod() { System.out.println("Static Method"); } }
Is Comparator interface a Functional Interface?
Just now, we read through the definition of a functional interface that it should have only the Single Abstract Method (SAM) interface.
But when we look into the Comparator interface, we could see two abstract methods; still, the Comparator interface is a functional interface?
It is legal to define the methods of the Object class as abstract in an interface.
From the Java docs
If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface’s abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.
The above definition says that the method of the Object class will not be included in the single abstract method count of the interface, so the Comparator is still a functional interface.
@FunctionalInterface Annotation
An interface with a Single Abstract Method is called Functional Interface, then why we need @FunctionalInterface annotation?
Let’s take the above function interface where we have isPrime() abstract method, later at some point another developer has added a new abstract method primeChecker() like below.
package com.javainterviewpoint;
public interface PrimeNumberValidator
{
boolean isPrime(int number);
boolean primeChecker(int number);
default void myDefaultMethod()
{
System.out.println("Default Method");
}
static void myStaticMethod()
{
System.out.println("Static Method");
}
}
Though it is still a valid interface, it will lose its ability to be used as a Functional Interface.
@FunctionalInterface annotation comes to the rescue here, as it triggers a compile-time check that the interface satisfies the requirement. If the interface has more than one abstract method or zero abstract methods, you will get a compiler error.
In the above code, if the @FunctionalInterface annotation is added, we will get a compile-time error like “PrimeNumberValidator is not a functional interface.”
Predefined Functional Interface
Let’s take a look at some of the most commonly used functional interfaces
- Predicate
- Function
- Consumer
- Supplier
1. Predicate
The java.util.function.Predicate interface has a Single Abstract Method test(), which accepts the generic object type T and returns a boolean.
boolean test(T t)
Let’s create a simple Predicate to check whether the given number is greater than 10.
package com.javainterviewpoint; import java.util.function.Predicate; public class NumberGreaterThan { public static void main(String[] args) { Predicate numberGreaterThan10 = number -> (number > 10); System.out .println("Is 11 greater than 10 ? " + numberGreaterThan10.test(11)); System.out .println("Is 5 greater than 10 ? " + numberGreaterThan10.test(5)); } }
Output:
Is 11 greater than 10 ? true Is 5 greater than 10 ? false
2. Function
The java.util.function.Function interface has a Single Abstract Method apply(), which accepts the generic object type T and returns a generic object type R.
R apply(T t)
Let’s create a simple even or odd number checker using the Function Interface.
As Function interface can take any object type as input and can return any object type. Let our Even or Odd Checker take an Integer as argument and return an Integer as a response
package com.javainterviewpoint; import java.util.function.Function; public class EvenOrOddChecker { public static void main(String[] args) { Function<Integer, Integer> evenOrOddChecker = number -> number % 2; if (evenOrOddChecker.apply(11) == 0) System.out.println("Even number"); else System.out.println("Odd number"); } }
Output:
Odd number
3. Consumer
The Consumer interface has a single abstract method accept() which accepts the generic object type T and doesn’t return anything (void)
void accept(T t)
Since the accept() doesn’t return anything this ideal for printing the values, let’s create a consumer which prints the values of the list
package com.javainterviewpoint; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; public class PrintElements { public static void main(String[] args) { Consumer printer = e -> System.out.println(e); List elements = new ArrayList(); elements.add(1); elements.add(2); elements.add(3); elements.add(4); System.out.println("Printing the elements of the List"); for (Integer i : elements) { printer.accept(i); } } }
Output:
Printing the elements of the List 1 2 3 4
4. Supplier
The Supplier interface has an abstract method get() which takes no input and returns generic object type T
T get()
Since the get() method doesn’t take any input this method is ideal generating random numbers, let’s create a random number generator which generates a random number within 10
package com.javainterviewpoint; import java.util.function.Supplier; public class RandomNumberGenerator { public static void main(String[] args) { Supplier random = () -> (int) (Math.random() * 10); System.out.println(random.get()); System.out.println(random.get()); System.out.println(random.get()); } }
Output:
6 7 2
Happy Learning !!
Leave a Reply