Java Functional Interfaces Tutorial

A tutorial about Java Functional Interfaces. Learn the concept of Functional Interfaces and why were they added in Java 8 – with the help of code examples.

What is Java Functional Interface ?

Functional Interface is an interface that has just one Abstract method and thus represents a single function contract. In other words, the Functional Interfaces facilitate only a single Function or a method.

Functional Interface is also called as SAM (Single Abstract Method Interface). Thing to note: Although, a Functional Interface can have a Single abstract method. However, it can have any number of Default Methods.

Functional or Not Functional ?

The word Single is not so simple here. Because, the ‘Single’ method can exist in the form of multiple abstract methods that are inherited from super interfaces. But, in that case the inherited methods should logically represent a single method. Alternatively, it might redundantly declare a method that is provided by classes like Object, e.g. toString.

Now, let’s see some of the examples of interfaces and understand if they are Functional.

// Functional
interface Runnable {
    void run();

// Not functional; equals is already an implicit member
interface Foo {
    boolean equals(Object obj);

// Functional; Bar has one abstract non-Object method
interface Bar extends Foo {
    int compare(String o1, String o2);

// Functional; Comparator has one abstract non-Object method
interface Comparator {
    boolean equals(Object obj);
    int compare(T o1, T o2);

// Not functional; method Object.clone is not public
interface Foo {
    int m();
    Object clone();

interface X {
    int m(Iterable arg);
interface Y {
    int m(Iterable arg);

// Functional: two methods, but they have the same signature
interface Z extends X, Y {}
Code language: Java (java)

Annotation @FunctionalInterface

I hope these examples help you understand which Interfaces are actually Functional Interfaces. Alternatively, you can use @FunctionalInterface annotation on the top of an Interface. However, this annotation doesn’t make your interface functional, but throws compilation error if your interface is not a Functional interface.

This annotation is like @Override, which is juts a check and it also improves the code readability.

Functional Interface and Lambda Expressions

In Java 8 and onwards the function interfaces can implemented by the Lambda expressions.

When a method or a expression requires a type Interface which is functional, you can use Lambda syntax to provide inline implementation of the interface.

public interface Runnable {
   public abstract void run();
}Code language: Java (java)

For example, Runnable class in Java is a Functional Interface. And, below is a traditional way you provide anonymous inner class to provide its implementation.

new Thread(new Runnable() {
    public void run() {
        System.out.println("I am running in separate thread");
}).start();Code language: Java (java)

Now below is how Lambda expression can implement the same interface in a short syntax.

new Thread(() -> System.out.println("I am running in separate thread")).start();Code language: Java (java)

In-built Functional Interfaces

Till this point, hope you are clear with the concept of Functional Interfaces and how Lambda expressions implement them. Java has provided some very useful functional interfaces which are ready to use. Instead of creating one, you can use them in many places.


The Function Interface is for applying certain transformation on the given object. Which has a single abstract method called as apply. It can take an argument of a type and can return other type.

public interface Function<T,U> {
    public <U> apply(T parameter);
}Code language: Java (java)

For example, java’s accepts a Function implementation. Firstly, we will see an example of Anonymous implementation. Function<Employee, String>() {
       public String apply(Employee e) {
           return e.getName();
}).collect(Collectors.toList());Code language: Java (java)

With lambda the above statement look a lot readable and simpler.
    .map(x -> x.getName())
    .collect(Collectors.toList());Code language: Java (java)

The syntax can more be simplified using the Method Reference.
    .collect(Collectors.toList());Code language: Java (java)

To sum up, Function interface can be used where an object or a value is being transformed – like the map method above – where the Stream of Employees is then mapped into Stream of Strings..


This is one more pre-defined Functional Interface. As the name suggest it defines a function which consumes the given parameter.

public interface Consumer <T> {
    void accept(T t);
}Code language: Java (java)

For example, Stream.forEach. Which is called once per element in the Stream and returns void. Let’s see how we can use Consumer implementation here.
    .forEach(System.out::println);Code language: Java (java)

The Stream of Employee is first mapped to Stream of Strings (employee names). After that each name is printed inside the forEach method.


The Predicate represents a function that evaluates the state of an object into Boolean value. The function accepts an object and returns boolean.

public interface Predicate {   boolean test(T t); }Code language: Java (java)

For example, we can refer to Stream.filter method, which is used to filtering out elements from the stream.
    .filter(e -> e.getAge() >= 40)
    .collect(Collectors.toList());Code language: Java (java)

Here, the filter method is filtering out employees ageing over 40 and collecting the rest in a list.


The Supplier interface is to supply things. The Supplier function doesn’t accept any argument but can return an object of provided generic type.

public Interface Supplier<T>{
    T get();
}Code language: Java (java)

You cannot re-use java Streams.. In other words, you call a Terminal Operation on a stream the stream is dead.

Stream<Employee> empStream = Stream.of(new Employee("a", 43), new Employee("b",39));

// Terminal Operation is Called on the Stream
empStream.filter(emp -> emp.getAge() >= 40).forEach(System.out::println);

//Using same stream results in Runtime Exception
//Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed

empStream.forEach(System.out::println);Code language: Java (java)

In such cases, supplier helps. Also it is very useful where you want to create reusable data-set. For example, mock datasets in tests.

Supplier<Stream<Employee>> supplier = () -> {Stream.of(new Employee("a", 43), new Employee("b", 39)};
    .filter(emp -> emp.getAge() >= 40)

    .forEach(System.out::println);Code language: Java (java)

In the above example, both of the operations are possible. Because every time you use the Supplier as new Stream is created.

Binary Operator

This BinaryOperator interface represents a function which takes to parameters and returns one. You can use it to define a Mathematical operations like comparison, addition etc.

For example, Java Stream.reduce method takes BinaryFunction. Using reduce, we will find youngest employee in the stream.

    .reduce((x, y) -> x.getAge() <= y.getAge() ? x : y)
Code language: Java (java)

Unary Operator

The UnaryOperator interface defines a function that takes one parameter and return an object of same time. You can use this function to change the value of given objet. For example, finding square of a number or converting String to upper case.

List<Double> longs = Arrays.asList(1d, 2d, 3d, 4d, 5d);
//square of each number in the list
longs.replaceAll(l -> Math.sqrt(l));
//Or, using method reference
longs.replaceAll(Math::sqrt);Code language: Java (java)

Additionally, we will see an example of generating infinite stream of sequential numbers using Stream.iterate method which accepts a UnaryOperator. We will print only first 10 elements from the stream.

    .iterate(1, x -> x + 1)
    .forEach(System.out::println);Code language: Java (java)


This was Java Functional Interfaces Tutorial. Where, you learnt that Functional Interfaces have Single Abstract Method (SAM). They represent a single functional contract.

The Java 8 Lambda Expressions provide in-line implementations for the functional interfaces. Moreover, these in-line implementations are short and simpler compared to the anonymous implementations. Also, you learnt some of the in-built functional interfaces by java, and you can re-use them in variety of situations.