Functional Interfaces in Java 8

Knoldus Blog Audio
Reading Time: 4 minutes

Introduction

Functional interface is an interface that consists of one abstract method. These interface 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 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, but that interface cannot be functional interface.

From functional interface if we remove @FunctionalInterface annotation, it must be valid. We use an annotation so that only single abstract method can be present. In functional interface we can provide implementations as the default methods inside interface.

e.g., Functional Interface Example

@FunctionalInterface
public interface FunctionalInterfaceDemo {  
    public void abstractMethodDemo();
    default void defaultMethodDemo1(){
    //Method body
    }
    default void defaultMethodDemo2(){
    //Method body
    }	   	
}

Some of the new Functional Interfaces in Java 8 are:

  • Consumer – BiConsumer
  • Predicate – BiPredicate
  • Function – BiFunction, Unary Operator, Binary Operator
Consumer – BiConsumer

The Consumer interface shows a function that can be used to take one parameter and gives output, that means these functions not return anything. Since Java 8 is introduced, we can use functional programming as well.

We use accept() in the form of 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. Predicate interface shows a method which take different arguments and return 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 gives 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 that 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 lambda expression to take the parameters and to the return the values after applying 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

Unary Operator is an interface shows a function that can take one parameter and performs operation. This interface 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 operation.

Therfore 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 lambda expression to take the parameters and to the return the values after performing 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

Binary Operator is an interface shows a function that can take two parameters and performs operation to return the value. This interface 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 given operation.

Binary Operator functional interface that can take one generic as :-

X: represents the input type of the parameter

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 lambda expression to take the parameters and to the return the values after performing 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
   }
}

Reference

For brief information on Functional Interfaces, you can click here

Leave a Reply