In this blog, we will learn about one of the features of Java 8 that is Functional Interface with advantages of its and built-in functions with some examples of the Functional Interface.

Functional Interfaces in Java 8

Reading Time: 4 minutes

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. ConsumerPredicate, 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 :

Written by 

Strong in design and integration problem-solving skills. Experience in Java/J2EE with database analysis and design. Skilled in developing business plans, requirements specifications, user documentation, and architectural systems research. Having Good Work Experience with Core Java, Advanced Java, Typescript, and Related Technologies, AWS like S3, Lambda, EC2, Elemental Live, Media Live, Tesseracts, and Textract.