Tech Master Tutorials
Email Facebook Google LinkedIn Pinterest Twitter
Home Java Java 8 Java Interview Questions Java8 Interview Questions Object Oriented Programming in Java JVM Java Programming

Functional Interfaces

Java 8 has introduced a new concept of Functional interfaces. A functional interface is an interface with only one abstract method.
Functional interfaces can be easily instantiated using Lambda expressions.
Functional interfaces can also be instantiated using anonymous inner classes but using lambda expressions make the code quite compact and easy to understand.

Lambda expressions enable us to pass the functionality as a method argument and functional interfaces enables that functionality.
Let’s have a look at the below example of creating a thread using an anonymous inner class.
public class AnonymousClassTest {

	public static void main(String[] args) {
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("Running inside thread = "+Thread.currentThread().getName());
			}
		});
		
		thread.start();
	}
	
}
In the above example, we are creating an anonymous class where we are defining the functionality for the run method.
We create some unnecessary and bad looking code when we create an anonymous class.

We already know that Runnable interface got only one abstract method that is the run () method. This makes the Runnable interface a Functional Interface.
So instead of creating anonymous class (or creating a Runnable class), can we have some capability
using which we can pass functionality or code as data to the Thread class, and program will understand
that we are passing the implementation code for run() method of Runnable.
We have lambda for that. But we can use lambda only when interface has a single abstract method(When we have Functional Interface).

Interfaces that consist of only one abstract method are called functional interfaces.
We can use lambda expression to pass the functionality only where you are expecting a functional interface type
Wherever we expect Runnable as argument in a method, we can pass lambda expression
instead of anonymous class (or defining a Runnable)and then passing it to a Thread class.
Instead of creating an anonymous inner class, we can pass a Lambda expression for the same


Creating a Thread using Lambda:
public class LambdaTest {

	public static void main(String[] args) {
		
		Thread thread = new Thread(() -> System.out.println("Running in thread = "+Thread.currentThread().getName()));
		
		thread.start();
	}

}



Other Examples :
forEach() method defined in the collection classes take a functional interface Consumer as a parameter.
Definition of forEach method:
default void forEach(Consumer action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
Consumer Interface: This is a functional interface whose functional method is accept(Object).
Interface definition :
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * Returns a composed {@code Consumer} that performs, in sequence, this
     * operation followed by the {@code after} operation. If performing either
     * operation throws an exception, it is relayed to the caller of the
     * composed operation.  If performing this operation throws an exception,
     * the {@code after} operation will not be performed.
     *
     * @param after the operation to perform after this operation
     * @return a composed {@code Consumer} that performs in sequence this
     * operation followed by the {@code after} operation
     * @throws NullPointerException if {@code after} is null
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}
So in the following example, instantiating Consumer functional interface and passing it to the forEach method.

package LambdaExpression;

import java.util.HashSet;

public class LambdaTestInterator {
	
	public static void main(String[] args) {
	
		HashSet<Integer> intSet=new HashSet<>();
		
		intSet.add(1);
		intSet.add(2);
		intSet.add(3);

		/*Passing a Lambda Expression for Consumer functional interface defined in java.util.function package. 
		As forEach method defined for collection classes receives the Consumer reference, a lambda expression is
		being passed for the Consumer functional interface interface. The lambda expression is passed for the get()
		method. Represents an operation that accepts a single input argument and returns no result. */

		Consumer consumerInstance=intVal -> System.out.println(intVal);
		
		intSet.forEach(consumerInstance);
	}
}