0% found this document useful (0 votes)
60 views11 pages

Ex-Functional Interfaces in Java

Functional interfaces in Java allow for lambda expressions and method references by containing only one abstract method. Common examples include Runnable, Comparable, and ActionListener. Functional interfaces can have default and static methods and override Object methods. They are annotated with @FunctionalInterface and allow cleaner code through lambda expressions. Important built-in functional interfaces are in the java.util.function package, including Consumer, Predicate, and Function interfaces.

Uploaded by

Ravi Kumar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
60 views11 pages

Ex-Functional Interfaces in Java

Functional interfaces in Java allow for lambda expressions and method references by containing only one abstract method. Common examples include Runnable, Comparable, and ActionListener. Functional interfaces can have default and static methods and override Object methods. They are annotated with @FunctionalInterface and allow cleaner code through lambda expressions. Important built-in functional interfaces are in the java.util.function package, including Consumer, Predicate, and Function interfaces.

Uploaded by

Ravi Kumar
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 11

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;

// lambda expression to define the calculate method


Square s = (int x) -> x * x;

// parameter passed and return type must be


// same as defined in the prototype
int ans = s.calculate(a);
System.out.println(ans);
}
}
Output
25
Some Built-in Java Functional Interfaces
Since Java SE 1.8 onwards, there are many interfaces that are converted into functional interface. All these
interfaces are annotated with @FunctionalInterface. These interfaces are as follows –
 Runnable –> This interface only contains the run() method.
 Comparable –> This interface only contains the compareTo() method.
 ActionListener –> This interface only contains the actionPerformed() method.
 Callable –> This interface only contains the call() method.

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);

List<Integer> arlist = new ArrayList<Integer>();


arlist.add(8);
arlist.add(1);
arlist.add(3);

// create a Consumer to multiply 2 to every integer of a list


Consumer<List<Integer> > modify = list -> {
for (int i = 0; i < arlist.size(); i++)
list.set(i, 2 * arlist.get(i));
};
// Implement modify using accept()
modify.accept(arlist);

// Consumer to display a list of numbers


Consumer<List<Integer> > dispList = list -> list.stream().forEach(a -> System.out.print(a + " "));
// Implement dispList using accept()
dispList.accept(arlist);
System.out.println();
List<Integer> arlist2 = new ArrayList<Integer>();
arlist2.add(5);
arlist2.add(4);
arlist2.add(9);

// create a Consumer to multiply 2 to every integer of a list


Consumer<List<Integer> > modify2 = list -> {
for (int i = 0; i < arlist2.size(); i++)
list.set(i, 2 * arlist2.get(i));
};
// Also we can use andThen() method
modify2.andThen(dispList).accept(arlist2);
System.out.println();

List<Integer> arlist3 = new ArrayList<Integer>();


arlist3.add(2);
arlist3.add(7);
arlist3.add(5);
// using null to get NullPointerException in andThen()
try {
modify.andThen(null).accept(arlist3);
}catch (Exception e) {
System.out.println("Exception: " + e);
}

List<Integer> arlist4 = new ArrayList<Integer>();


arlist4.add(10);
arlist4.add(12);
arlist4.add(14);
// create a Consumer to multiply 2 to every integer of a list
Consumer<List<Integer> > modi = list -> {
for (int i = 0; i < arlist4.size(); i++)
list.set(i, 2 * arlist4.get(i));
};

// 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.

2. Predicate Interaface: It improves manageability of code, helps in unit-testing them separately,

The functional method is test(Object).


boolean test(T t) : Evaluates this predicate on the given argument.
Parameters: t - the input argument
Returns: true if the input argument matches the predicate, otherwise false

static Predicate isEqual(Object targetRef) : Returns a predicate that tests if two arguments are equal
according to Objects.equals(Object, Object).

T : the type of arguments to the predicate


Parameters: targetRef : the object reference with which to compare for equality, which may be null
Returns: a predicate that tests if two arguments are equal according to Objects.equals(Object, Object)

default Predicate and(Predicate other) : Returns a composed predicate that represents a


short-circuiting logical AND of this predicate and another.
Parameters : other : a predicate that will be logically-ANDed with this predicate
Returns : a composed predicate that represents the short-circuiting logical AND of this predicate and the other
predicate
Throws : NullPointerException - if other is null
default Predicate negate() :
Returns : a predicate that represents the logical negation of this predicate

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);

// Calling Predicate method


System.out.println(lessthan.test(10));

// 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);

// Calling Predicate method


boolean result2 = greaterThanTen.and(lowerThanTwenty).negate().test(15);
System.out.println(result2);
}
}
Example :
import java.util.*;
import java.util.function.Predicate;
class PredicateDemo2 {
public static void main(String args[]) {

// create a list of strings


List<String> names = Arrays.asList( "Laxmi Sravani", "Leela Krishna", "Lasya Priya", "Nandini Siva",
"Pooja Harika", "Laxmi Sudha");

// declare the predicate type as string and use


Predicate<String> p = (s) -> s.startsWith("L");

// Iterate through the list


for (String st : names) {
// call the test method
if (p.test(st))
System.out.println(st);
}
}
}
Example:
import java.util.*;
import java.util.function.Predicate;
class User{
String name, role;
User(String a, String b) {
name = a;
role = b;
}
String getRole() { return role; }
String getName() { return name; }
public String toString() {
return "User Name : " + name + ", Role :" + role;
}};
class PredicateDemo3 {
public static void main(String[] args) {
List<User> users = new ArrayList<User>();
users.add(new User("Samar", "admin"));
users.add(new User("Ravi", "member"));
users.add(new User("Jiban", "admin"));
users.add(new User("Sudha", "member"));

Predicate<User> predict = us -> us.getRole().equals("admin");


for(User usr : users)
if(predict.test(usr))
System.out.println(usr);

/* List<User> admins = process(users, (User u) -> u.getRole().equals("admin"));


System.out.println(admins);
}
public static List<User> process(List<User> users, Predicate<User> predicate) {
List<User> result = new ArrayList<User>();
for (User user: users)
if (predicate.test(user))
result.add(user);
return result;*/
}
};
The predicate functional interface can also be implemented using a class. The syntax for the implementation
of predicate functional interface using a class is given below –
public class CheckForNull implements Predicate {
@Override
public boolean test(Object o) {
return o != null;
}
}
The Java predicate functional interface can also be implemented using Lambda expressions. The example of
implementation of Predicate functional interface is given below –
Predicate predicate = (value) -> value != null;
This implementation of functional interfaces in Java using Java Lambda expressions is more manageable and
effective than the one implemented using a class as both the implementations are doing the same work, i.e.,
returning the same output.

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;

// Applying the function to get the result


System.out.println(half.apply(10));
}
}

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;

// Now treble the output of half function


half = half.andThen(a -> 3 * a);

// Applying the function to get the result


System.out.println(half.apply(10));
}
}

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.

public class FunctionDemo3 {


public static void main(String[] args) {

Function<Integer, Integer> f1 = num -> (num - 4);


Function<Integer, Integer> f2 = num -> (num * 2);

// Using andThen() method


int a=f1.andThen(f2).apply(10);
System.out.println(a);// Output : 12
/*f1.andThen(f2).apply(10); => first execute f1.apply(10) method. based on output first method,
f2.apply(result_of_f1_method) method execute. */

//Using compose function


int b=f1.compose(f2).apply(10);
System.out.println(b);// Output : 16
/*f1.compose(f2).apply(10); => here just opposite to andThen() method. first f2.apply() and then
f1.apply(output_of_f2_method) execute. */
}
}

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();

// Print the random value using get()


System.out.println(randomValue.get());
}
}

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.

You might also like