Java Programming Tutorials

Java programming tutorials with many code examples!

Java 8 Functional Interfaces

Java 8 Functional Interfaces is very important concept, because they are heavily used with Lambda Expressions and Streams to simplify code. Let’s take a deep dive!

What is Functional Interface

Every interface that has single abstract method is a Functional Interface in Java 8. They may have static and/or default methods, but have to have only one abstract method (one that doesn’t have any body). This is very important, because the compiler matches Lambda Expressions with this single method to produce fully working objects.

Let’s look at an example of a functional interface with a couple of different methods, but only one abstract method:

package com.farenda.java.lang;

import java.util.Date;

public interface SimpleProcessor {

    // Single Abstract Method:
    int process();

    // Other methods don't metter:
    static Date now() {
        return new Date();
    }

    default String formatDate(Date date) {
        return date.toString();
    }

    default int sum(int a, int b) {
        return a + b;
    }
}

Only functional interfaces can be used as a basis for Lambda Expressions, therefore we can verify whether our interface is functional by creating a Lambda Expression for it:

package com.farenda.java.lang;

public class MyRunner {

    public static void main(String[] args) {
        // SimpleProcessor as Lambda Expression:
        SimpleProcessor processor = () -> 42;

        // The compiler doesn't protest, so let's call it:
        System.out.println("Processing: " + processor.process());
    }
}

The above code prints:

Processing: 42

@FunctionalInterface annotation

To help developers prevent bugs when changing functional interfaces, Java 8 added @FunctionalInterface that tells the compiler to check if the interface has only single abstract method. If not then it won’t compile it.

Here we have a functional interface to which we’ve added a new abstract method:

package com.farenda.java.lang;

import java.util.Date;

@FunctionalInterface
public interface SimpleProcessor {

    int process();

    int postProcess();
}

The compiler immediately sees this and tells us about the error in two ways. The first error is on the @FunctionalInterface annotation itself:

Error:(5, 1) java: Unexpected @FunctionalInterface annotation
com.farenda.java.lang.SimpleProcessor is not a functional interface
  multiple non-overriding abstract methods found in interface
  com.farenda.java.lang.SimpleProcessor

The second error is in Lambdas assigned to the interface (MyRunner above):

Error:(6, 37) java: incompatible types:
   com.farenda.java.lang.SimpleProcessor is not a functional interface
   multiple non-overriding abstract methods found in
   interface com.farenda.java.lang.SimpleProcessor

Notice that @FunctionalInterface annotation is not required to define a functional interface, but it is a good practice, clearly states your intentions, and makes the compiler to immediately notify about errors.

Interfaces with Single Abstract Method, but without the annotation are also functional. They just won’t have compile type check – when you add another abstract method to such interface it will compile, contrary to classes that implement it.

Share with the World!