A look into JAVA 8 Functional interfaces

Zakariaa Boudfoust
5 min readSep 10, 2019

--

Introduction

During my documentation on the new features that came along with the Java 8 language, functional interface caught my attention. In this article, I’ll try to share my experience with ‘Functional interfaces’ and I’ll try to tell you why I found this feature one of the most important features in Java 8.

Are you ready? Let’s begin.

Why are functional interfaces so important?

First of all, what is a functional interface? Nothing better than the Oracle definition. It is simply an interface that has just one abstract method (aside from the methods of Object). So why is it important?

We will not argue about the main goal of a functional interface, which is without any doubt, defining a function signature that accepts another function as parameter.

But in my opinion, the importance of functional interfaces come essentially from two other Java 8 features: ‘Method reference ‘ and Lambda expressions’.

With method reference and Lambda expressions, passing methods as parameter has become a way easier and simpler, all the work can be done in just one line of code and we can clearly notice that in streams.

When using stream API operations, chaining of operations looks simple, clear and readable only because of functional interfaces.

Do functional interfaces concept really come with JAVA 8?

Well this is not completely true; any Single Abstract Method interface is a functional interface. That means that any interface that contains only one abstract method and have as many default methods as possible is a functional interface, Runnable and Comparable for example.

What comes new with Java 8 is the optional @FunctionalInterface annotation. It is used to ensure the singularity of abstract methods (aside from the methods of Object) in the annotated interface. This way, we are sure we can’t have more than one abstract method. The compiler will flag an ‘Unexpected @FunctionalInterface annotation’ message if more than one abstract method is present.

And since we are sure only one abstract method is present, the method passed in parameter of function can only be the implementation of this abstract method.

To have a better view, let’s see an example of how things were done before and after Java 8.

Prior to Java 8…

Before Java 8, we had to use anonymous inner classes, which we agree, not so beautiful nor simple to read:

With Java 8…

With Java 8, using a lambda expression reduces all the lines before to just one simple and clear line:

I think that we can all agree, functional interface concept simplify our code and coding experience.

Complete use case

In order to have a complete view, let’s see an example of a use case when we need to parse a string containing coordinates separated by a comma.

The type we are going to create is Coordinates:

Coordinates class

We create a CoordinatesParser class which will do only the parsing. The creation of the coordinates object is delegated to the interface CoordinatesCreator.

To use CoordinatesParser, we call method parse with the string containing the coordinates and method for the interface CoordinatesCreator. We can do that four different ways:

  • Using lambda expression
  • Using reference to constructor
  • Using reference to instance method
  • Using reference to static method

I created a test case for each of those ways in the example below:

You can find the entiere example here.

Package java.util.function

Java 8 come also with a package of ready to use functional interfaces. For simple and current cases, there is no need to define our own functional interfaces. We can simply use what the package proposes.

I will not do the inventory, but here is some of the most known functional interfaces defined in the package:

  • Predicates: a predicate is a function that takes an argument and returns a Boolean value (T -> Boolean)
  • Consumers: a consumer is a function that takes a unique argument and returns nothing (T-> void)
  • Suppliers: a supplier is a function that takes no arguments and returns a value (() ->T)
  • Functions: a function is a function that takes an argument and returns a value (T-> R)

Those were just examples among others. I think it is a good idea to check if the functional interface we need to code already exists, so we can avoid wasting our time coding duplicates.

For example, Streams API operations uses a lot this package, if you check for operations signatures, you will immediately notice that.

Here is some of the Stream API operations with the functional interface they take as parameter.

Beyond simple usage

For those who may be interested with the background and the wiring of things, I want you to have a close look at @FunctionalInterface implementation.

When I first saw the retention policy chosen for this annotation, I found that RUNTIME retention was too much regarding the purpose of just flagging ‘Unexpected @FunctionalInterface annotation’ by the compiler. For me, SOURCE retention was enough. Once the compiler flags its message, there is no need to take the annotation along to the JVM.

After a quick search, I’ve found that Joe Darcy (original committer of @FunctionalInterface) already answered on this topic for a similar interrogation:

So, I understand that the purpose of using RUNTIME retention is not for JVM usage but rather for third-party tools usage through reflection.

Conclusion

As we have seen through all this article, functional interface concept simplifies our code considerably. There is no need to use anonymous inner classes to pass a function as parameter anymore, all is done in one line thanks to lambda expression and method reference, and that makes an appreciable difference in terms of readability and simplicity.

Special thanks to Youssef EL GAMRANI and Taoufik ELGAMRANI for the review!

--

--

Zakariaa Boudfoust

Curious Full Stack Software Developer and Aspiring Software Craftsman. Passionate about code, software architecture and coffee !!