What is Functional Interface in Java 8 ?
A functional interface is an interface that consists of one abstract method. These interfaces can show only one functionality. Beyond Java 8, lambda expressions can be used to represent the instance of a functional interface. Functional Interfaces can contain any number of static and default methods. Consumer, Predicate, Function, Unary Operator, Binary Operator are some of the examples of predefined functional interfaces.
Points to remember which are allowed and which are not allowed in a functional interface:
- In any functional interface, single abstract method is allowed.
- In a functional interface, more than one abstract method cannot exist.
- We can have more than one abstract method if we remove @FunctionalInterface Annotation in Java, but that interface cannot be functional interface.
From the functional interface, if we remove @FunctionalInterface annotation, it must be valid. We use an annotation so that only a single abstract method can be present. In the functional interface, we can provide implementations as the default methods inside the interface.
e.g., Functional Interface Example
@FunctionalInterface
public interface FunctionalInterfaceDemo {
public void abstractMethodDemo();
default void defaultMethodDemo1(){
//Method body
}
default void defaultMethodDemo2(){
//Method body
}
}
Built-in Functional Interfaces in Java 8 are:
- Consumer
- Predicate
- Function
- Unary Operator
- Binary Operator
Consumer – BiConsumer
The Consumer interface shows a function that can be used to take one parameter and give output, which means these functions do not return anything. Since Java 8 is introduced, we can use functional programming as well.
We use accept() in the form of a lambda expression to take one argument and do not return any value. Consumers can be used when there is no need to return any value.
e.g., Consumer Interface Example
public class ConsumerDemo {
public static void main (String args[]) {
Consumer<String> consumer = (s) -> System.out.println(s.toUpperCase());
consumer.accept("Java 8");
}
}
e.g., BiConsumer Interface Example
public class BiConsumerDemo {
public static void main (String args[]) {
BiConsumer<String, String> biConsumer = (a,b) -> {
System.out.println("x: "+ a +", b: "+b);
};
biConsumer.accept("Java8", "Implementation");
BiConsumer<Integer, Integer> add = (a,b) -> {
System.out.println("Addition is: "+(a+b));
};
BiConsumer<Integer, Integer> subtract = (a,b) -> {
System.out.println("Subtraction is: "+(a-b));
};
addition.andThen(subtraction).accept(2,1);
}
}
Predicate-BiPredicate
Predicate interface is a part of java.util.Function package. It shows a method that takes different arguments and returns boolean as value. These interfaces can be helpful in testing and improving manageability.
public interface Predicate {
public boolean test(T t);
}
e.g., Predicate Interface Example
public class PredicateDemo {
public static void main (String args[]) {
Predicate<Integer> predict = (a) -> i%2 == 0;
System.out.println(p.test(2));
}
}
e.g., BiPredicate Interface Example
public class BiPredicateDemo {
public static void main(String[] args) {
BiPredicate<Integer, Integer> biPredicate1 = (n1, n2) -> (n1 % n2 == 0);
BiPredicate<Integer, Integer> biPredicate2 = (n1, n2) -> (n1 * n2 > 100);
System.out.println(biPredicate1.and(biPredicate2).test(120, 6)); // false
BiPredicate<String, String> biPredicate3 = (s1, s2) -> s1.startsWith(s2);
BiPredicate<String, String> biPredicate4 = (s1, s2) -> s1.endsWith(s2);
System.out.println(biPredicate3.and(biPredicate4).test("Java", "J"));
// false
System.out.println(biPredicate3.and(biPredicate4).test("CODEC", "C"));
// true
}
}
Function
Function interface shows a method that can take one argument and give output or can return any value. This interface exists in java.util.function package as the release version of Java 8.
Therefore Function functional interface can take two generics as:-
X: represents an input type of the parameter
R: represents the value as the return type
We can use apply() method in the form of a lambda expression to take the parameters and to return the values after applying the function on the given parameters.
e.g., Function Interface Example
public class FunctionDemo {
static Function<String, String> function = (name) -> name.toUpperCase();
public static void main (String args[]) {
System.out.println("Result is: "+function.apply("Java8")); // JAVA8
}
}
Unary Operator
A unary Operator is an interface that shows a function that can take one parameter and performs the operation. It exists in java.util.function package as the release version of Java 8. And it is helpful to use when we want the same value as input and output after performing the operation.
Therefore Unary Operator functional interface that can take one generic as:-
X: represents the input type of the parameter
Therefore Unary Operator can overload Function type. So this interface can inherit methods of the Function Interface:
X apply(X x)
default <Y> Function<X, Y> andThen(Function<? super S, ? extends Y> after)
default <Y> Function<Y, S> compose(Function<? super Y, ? extends X> before)
We can use accept() method in the form of a lambda expression to take the parameters and to return the values after performing the given operation.
e.g., Unary Operator Interface Example
public class UnaryOperatorDemo {
static UnaryOperator<String> unaryOperator = (a) -> a.concat("Default");
public static void main (String args[]) {
System.out.println(unaryOperator.apply("Java8"));
}
}
Binary Operator
A binary Operator is an interface that shows a function that can take two parameters and performs the operation to return the value. It exists in java.util.function package as the release version of Java 8. And it is helpful to use when we want the same value as input and output after performing a given operation.
Binary Operator functional interface that can take one generic as:-
X: represents the input type of the parameter
The binary Operator interface can extend the BiFunction type. So it can inherit the methods of the BiFunction Interface:
apply(X a, X b)
andThen(Function<? super S, ? extends Y> after)
We can use apply() method in the form of a lambda expression to take the parameters and to return the values after performing the given operation.
e.g., Binary Operator Interface Example
public class BinaryOperatorDemo {
static Comparator<Integer> comparator = (a,b) -> a.compareTo(b);
public static void main (String args[]) {
BinaryOperator<Integer> binaryOperator = (a,b) -> a*b;
System.out.println(binaryOperator.apply(1,2));
BinaryOperator<Integer> result = BinaryOperator.result(comparator);
System.out.println("Result is: " result.apply(1,2)); // 2
}
}
Example 1 of Functional Interfaces:
Let’s see the example of a Functional interface with object class methods.
@FunctionalInterface
interface sayable{
void say(String msg); // abstract method
// It can contain any number of Object class methods.
int hashCode();
String toString();
boolean equals(Object obj);
}
public class FunctionalInterfaceExample1 implements sayable{
public void say(String msg){
System.out.println(msg);
}
public static void main(String[] args) {
FunctionalInterfaceExample1 fie = new FunctionalInterfaceExample1();
fie.say("Hello there");
}
}
Output :

Example 2 of Functional Interfaces :
Let’s see an example of a non-functional interface
interface Doable{
default void doIt(){
System.out.println("Do it now");
}
}
@FunctionalInterface
interface Sayable extends Doable{
void say(String msg); // abstract method
}
public class FunctionalInterfaceExample2 implements Sayable{
public void say(String msg){
System.out.println(msg);
}
public static void main(String[] args) {
FunctionalInterfaceExample2 fie = new FunctionalInterfaceExample2();
fie.say("Hello there");
fie.doIt();
}
}
Output :
