Ex-Functional Interfaces in Java
Ex-Functional Interfaces in Java
An interface that contains only one abstract method is called Functional Interface. Functional Interface is also
known as Single Abstract Method(SAM) interfaces. Runnable, ActionListener, Comparable are some of
the examples of functional interfaces. A functional interface can have any number of default and static
methods and they can declare methods of Object class.
Functional interfaces are introduced in Java SE 8 with Lambda expressions and Method references in order to
make code more readable, clean, and straightforward. Functional interfaces are used and executed by
representing the interface with an annotation called @FunctionalInterface.
Important Points/Observations:
Here are some significant points regarding Functional interfaces in Java:
1. In functional interfaces, there is only one abstract method supported. If the annotation of a
functional interface, i.e., @FunctionalInterface is not implemented or written with a function
interface, more than one abstract method can be declared inside it. However, in this situation with
more than one functional interface, that interface will not be called a functional interface. It is
called a non-functional interface.
2. There is no such need for the @FunctionalInterface annotation as it is voluntary only. This is
written because it helps in checking the compiler level. Besides this, it is optional.
3. An infinite number of methods (whether static or default) can be added to the functional interface.
In simple words, there is no limit to a functional interface containing static and default methods.
4. Overriding methods from the parent class do not violate the rules of a functional interface in Java.
5. The java.util.function package contains many built-in functional interfaces in Java 8.
class Test {
public static void main(String args[]) {
// create anonymous inner class object
new Thread(new Runnable() {
@Override public void run()
{
System.out.println("New thread created");
}
}).start();
}
}
Output
New thread created
Java 8 onwards, we can assign lambda expression to its functional interface object like this:
class Test {
public static void main(String args[]) {
// lambda expression to create the object
new Thread(() -> {
System.out.println("New thread created");
}).start();
}
}
Output
New thread created
@FunctionalInterface Annotation
@FunctionalInterface annotation is used to ensure that the functional interface can’t have more than one
abstract method. In case more than one abstract methods are present, the compiler flags an ‘Unexpected
@FunctionalInterface annotation’ message. However, it is not mandatory to use this annotation.
// Java program to demonstrate lambda expressions to
// implement a user defined functional interface.
@FunctionalInterface
interface Square {
int calculate(int x);
}
class Test {
public static void main(String args[])
{
int a = 5;
Java SE 8 included four main kinds of functional interfaces which are defined in java,util.function
package and these interfaces can be applied in multiple situations. These are:
1. Consumer
2. Predicate
3. Function
4. Supplier
Amidst the previous four interfaces, the first three interfaces,i.e., Consumer, Predicate, and Function, likewise
have additions that are provided beneath –
1. Consumer -> Bi-Consumer,
2. Predicate -> Bi-Predicate
3. Function -> Bi-Function, Unary Operator, Binary Operator
1. Consumer Interface
The consumer interface of the functional interface is the one that accepts only one argument. The consumer
interface has no return value. It returns nothing.
There are also functional variants of the Consumer — DoubleConsumer, IntConsumer, and LongConsumer.
These variants accept primitive values as arguments.
Other than these variants, there is also one more variant of the Consumer interface known as Bi-Consumer.
Methods of Consumer Interface :
1. void accept(T t)
This method Performs some operation on the given argument.
2. default Consumer<T> andThen(Consumer<? super T> after)
Parameters: This method accepts a parameter after which is the Consumer to be applied after
the current one.
Return Value: This method returns a composed Consumer that first applies the current
Consumer first and then the after operation.
Exception: This method throws NullPointerException if the after operation is null.
Example:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String args[]) {
// Consumer to display a number
Consumer<Integer> display = a -> System.out.println(a);
// Implement display using accept()
display.accept(10);
// using addThen()
try {
dispList.andThen(modi).accept(arlist4);
}catch (Exception e) {
System.out.println("Exception: " + e);
}
}
};
Example:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerDemo2 {
static void addList(List<Integer> list){
// Return sum of list values
int result = list.stream()
.mapToInt(Integer::intValue)
.sum();
System.out.println("Sum of list values: "+result);
}
public static void main(String[] args) {
// Creating a list and adding values
List<Integer> list = new ArrayList<Integer>();
list.add(10);
list.add(20);
list.add(30);
list.add(40);
// Referring method to String type Consumer interface
Consumer<List<Integer>> consumer = ConsumerDemo2::addList;
consumer.accept(list); // Calling Consumer method
}
}
Bi-Consumer Interface – Bi-Consumer is the most exciting variant of the Consumer interface. The consumer
interface takes only one argument, but on the other side, the Bi-Consumer interface takes two arguments.
Both, Consumer and Bi-Consumer have no return value. It also returns noting just like the Consumer
interface. It is used in iterating through the entries of the map.
static Predicate isEqual(Object targetRef) : Returns a predicate that tests if two arguments are equal
according to Objects.equals(Object, Object).
default Predicate or(Predicate other) : Returns a composed predicate that represents a short-circuiting
logical OR of this predicate and another.
Parameters : other : a predicate that will be logically-ORed with this predicate
Returns : a composed predicate that represents the short-circuiting logical OR of this predicate and the other
predicate
Throws : NullPointerException - if other is null
Just like the Consumer functional interface, Predicate functional interface also has some extensions. These are
IntPredicate, DoublePredicate, and LongPredicate. These types of predicate functional interfaces accept only
primitive data types or values as arguments.
Example:
import java.util.function.Predicate;
public class PredicateDemo1 {
public static void main(String[] args) {
// Creating predicate
Predicate<Integer> lessthan = i -> (i < 18);
// Predicate Chaining
Predicate<Integer> greaterThanTen = (i) -> i > 10;
Predicate<Integer> lowerThanTwenty = (i) -> i < 20;
boolean result = greaterThanTen.and(lowerThanTwenty).test(15);
System.out.println(result);
Bi-Predicate – Bi-Predicate is also an extension of the Predicate functional interface, which, instead of one,
takes two arguments, does some processing, and returns the boolean value.
3. Function Interaface :
A function is a type of functional interface in Java that receives only a single argument and returns a value
after the required processing.
The Function interface consists of the following 4 methods as listed which are later discussed as follows:
apply()
andThen()
compose()
identity()
R apply(T t)
Parameters: This method takes in only one parameter t which is the function argument
Return Type: This method returns the function result which is of type R.
Example
import java.util.function.Function;
public class FunctionDemo1{
public static void main(String args[]) {
// Function which takes in a number and returns half of it
Function<Integer, Double> half = a -> a / 2.0;
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) : It returns a composed
function wherein the parameterized function will be executed after the first one. If evaluation of either
function throws an error, it is relayed to the caller of the composed function.
where V is the type of output of the after function, and of the composed function
Parameters: This method accepts a parameter after which is the function to be applied after the current one.
Return Value: This method returns a composed function that applies the current function first and then the
after function
Exception: This method throws NullPointerException if the after function is null.
import java.util.function.Function;
public class FunctionDemo2{
public static void main(String args[]) {
// Function which takes in a number and returns half of it
Function<Integer, Double> half = a -> a / 2.0;
The compose() method is similar to andThen() method, but the difference between compose and andThen is
the order they execute the functions. While the compose function executes the caller last and the parameter
first, the andThen executes the caller first and the parameter last.
There are many versions of Function interfaces because a primitive type can’t imply a general type argument,
so we need these versions of function interfaces. Many different versions of the function interfaces are
instrumental and are commonly used in primitive types like double, int, long. The different sequences of these
primitive types are also used in the argument.
These versions are:
Bi-Function – The Bi-Function is substantially related to a Function. Besides, it takes two arguments,
whereas Function accepts one argument.
The prototype and syntax of Bi-Function is given below –
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
.......
}
In the above code of interface, T, U are the inputs, and there is only one output that is R.
Unary Operator and Binary Operator – There are also two other functional interfaces which are named as
Unary Operator and Binary Operator. They both extend the Function and Bi-Function, respectively. In simple
words, Unary Operator extends Function, and Binary Operator extends Bi-Function.
The prototype of the Unary Operator and Binary Operator is given below –
1. Unary Operator
@FunctionalInterface
public interface UnaryOperator<T> extends Function<T, U>
{
……...
}
2. Binary Operator
@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T, U, R>
{
……...
}
We can understand front the above example that the Unary Operator accepts only one argument and returns a
single argument only. Still, in Unary Operator both the input and output values must be identical and of the
same type.
On the other way, Binary Operator takes two values and returns one value comparable to Bi- Function but
similarly like Unary Operator, the input and output value type must be identical and of the same type.
4. Supplier Interface :
The Supplier functional interface is also a type of functional interface that does not take any input or argument
and yet returns a single output. This type of functional interface is generally used in the lazy generation of
values. Supplier functional interfaces are also used for defining the logic for the generation of any sequence.
For example – The logic behind the Fibonacci Series can be generated with the help of the Stream.generate
method, which is implemented by the Supplier functional Interface.
T get() : This functional method does not take in any argument but produces a value of type T.
Returns: This method returns a value of type T.
Example:
import java.util.function.Supplier;
public class SupplierDemo1 {
public static void main(String args[]) {
// This function returns a random value.
Supplier<Double> randomValue = () -> Math.random();
The different extensions of the Supplier functional interface hold many other supplier functions like
BooleanSupplier, DoubleSupplier, LongSupplier, and IntSupplier. The return type of all these further
specializations is their corresponding primitives only.