If you have ever used Streams and Optionals in Java, you must have come across lambda expressions and functional interfaces. But how exactly are lambda expressions tied to functional interfaces?
This article will talk about functional programming in Java and how Streams and Optionals make use of functional interfaces.
What is a functional interface?
An interface that has only one abstract method (unimplemented method) can qualify to be a functional interface. It may or may not have other default and static methods.

LAMBDA EXPRESSIONS
Lambda expressions or functions are blocks of code that can be assigned to a variable, passed around as an argument or even returned from functions. They are anonymous functions and contains parameters, lambda operator (->) and function body.

Lambda Expression Syntax
Lambda expressions were introduced in Java as a means of supporting functional programming. As Lambda expressions are anonymous functions, passed around as arguments, we need a way to execute these functions on demand. This is where functional interfaces come into play.
Functional interfaces, having only a single abstract method, accepts the lambda function or a method reference as the implementation for that particular abstract method.
To understand better, let’s see how streams and optionals uses lambda expressions as implementations for the abstract method in functional interfaces.
FUNCTIONAL INTERFACES USED IN JAVA STREAMS
Streams in Java provide a functional approach to process a collection of objects. Stream.java provides different methods to process list elements, map(), flatMap(), filter(), sorted() etc, each of which takes a functional interface type as an argument.
Let’s consider an example of a LIST of names and Stream on the list to filter out names that contains the letter ‘a’.

The .filter() here is a function to filter out elements from the list that satisfies the specified criteria and the .collect() returns back another list with the filtered elements. Notice that the input passed onto the filter function is a lambda expression. The filter() method in Stream.java has the following structure.
As you can see, filter accepts a Predicate as an argument. So what is a predicate?

Predicate.java
A predicate is a functional interface provided in java.util.function package and contains one abstract method, which is, boolean test(T t).
But how do we get the implementation for test(T t)? What gets executed when predicate.test(t) is called?
Looking back at our stream, when the lambda expression, name -> name.contains(“a”), is passed as a predicate to filter(), this lambda expression is treated as an implementation for predicate.test(t) and gets evaluated inside filter method.

Flowchart: Lambda expression becomes the implementation for the abstract method in Predicate
This is the reason why functional interfaces support only one abstract method. The lambda expression passed will be compiled to provide an implementation for the only abstract method present in the functional interface. Had there been more than one abstract method, the compiler will not know which method should be implemented with the lambda expression passed.
FUNCTIONAL INTERFACES USED IN OPTIONALS
Optionals in Java also use functional interfaces. Optional.ifPresent() accepts an input of type Consumer which is a functional interface.
Consider an example where lambda expression
**value -> displayName("user1")**
will be executed inside name.ifPresent().

Example of Optional.ifPresent()
The implementation of Optional.ifPresent() inside Optional.java takes a Consumer as an argument, to which this lambda expression is passed.

Flowchart: Lambda expression becomes the implementation for the abstract method in Consumer
Consumer contains only one abstract method accept(t) and its implementation will be the lambda expression passed.
The functional interfaces Predicate, Function, Consumer and Supplier are provided in the java.util.function package along with various other interfaces. The functional interfaces provided in java.util.function maybe enough to cover common scenarios, or we can define our own functional interfaces for our requirements .