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