Friday, June 22, 2018

What is a Functional interface in Java 8? @Functional Annotation and Examples

The functional interface is one of the most important concepts of Java 8 which actually powers lambda expression but many developers don't put enough effort to understand it and spend time learning lambda expression and Stream API without first understanding the role of functional interface in Java 8. Unless you know what is a functional interface and how lambda is related to it, you can't use powerful features of Java 8 e.g. lambda expression and stream API. Without knowledge of functional interface, you won't be able to understand where you can use a lambda in the code but also you will struggle to write lambda expression the method is expecting, hence, it's important to have a good understanding of functional interface in Java 8.

In this article, I'll try to fill that gap by explaining what is a functional interface, what is a @Functional annotation, how they are related to lambda expression and how they help you to use the lambda expression in your code.  So, let's start with the very first thing, what is a functional interface?


What is Functional interface in Java 8

Well, a functional interface is nothing but an interface with just one abstract method e.g. Comparable, Runnable, EventListener, Comparator etc. You can see these interfaces were present in Java even before JDK 8, but why do we call such interface functional interface?

This is a very good question and if you know a little bit about functional programming, you know that it allows you to pass the code i.e. a function just like you pass data or object to the method.


These interface with just one abstract method was used to pass around code, just like you pass a function in functional programming language and that's why they are called functional interface.

For example, you can directly pass the code to compare objects by creating an Anonymous class by implementing Comparator interface as shown below:

Collections.sort(list, new Comparator(){

   public int compare(String s1, String s2){
      return s1.length() - s2.length();
   }
});

So, if you look closely, you can see we are passing code to a function using these interfaces. They are also known as strategy interface because this is an implementation of Strategy pattern where the code which forms the Strategy is injected into the code which runs that strategy at runtime.

Btw, if you don't know what is Strategy pattern, then I suggest you go through From 0 to 1: Design Patterns - 24 That Matter - In Java, as knowledge of design pattern is important for effective coding in Java.

strategy pattern in Java


So, now that we know what is a functional interface, let's understand how they are related to a lambda expression, and how an understanding of functional interface is important for writing code using a lambda expression?

Well, the most important thing to remember is that the only use of lambda expression in Java is to convert them into a functional interface.

This means you can pass lambda expression if a method is accepting a functional interface, which further means, you can pass a lambda to all existing method which accepts Comparator, Runnable or any other interface which has got just one single abstract method.

This the reason that lambda expression in Java is also called of SAM type, where SAM means Single Abstract Method.  If you want to learn more about SAM type then you can also see Java SE 8 for Really Impatient By Cay S. Horstmann to learn more about lambda expression in Java.

What is a Functional interface in Java 8? @Functional Annotation and Examples


What does @Functional annotation do?

Now, let's see what does @Functional annotation do? Will it make an interface functional if you just put the @Functional annotation on top of that? Well, no, it doesn't do that. In fact, it's optional.

This means you can create a functional interface without using @Functioanl annotation just like you can override a method without putting the @Override annotation on top of a method. Then, what is the real purpose of @Functional annotation?

Well, it can ensure that the interface actually have just one abstract method and it also provides a hint to the tools like Javadoc that this interface is a functional interface. It's pretty much similar to @Override annotation, which helps to prevent human error by verifying that you actually overriding a method.

Similar to @Override its best practice to put the @Functional annotation on top of the method with single abstract methods to indicate to the tools like Javadoc that they are a functional interface.

All the new functional interface added in java.util.function package is annotated with the @Functional annotation.

Btw, Yes, we have got more functional interfaces in JDK 8, particularly general-purpose functional interfaces like Predicate, Supplier, Consumer, Function, BiFunction, UnaryOperator etc. See Java 8: basics for beginners to learn more about all those interfaces in depth.

These functional interfaces allow you to pass code to a function in form of lambda expression and enable the creation of powerful methods which can operate on those code e.g. filter() which accept Predicate and allows you to pass a code which accepts one argument and return boolean.



How Functional interface and Lamda Expression are related

How does knowledge of functional interface affect the writing of lambda expression? Well, unless you don't understand the functional interface, you can't write a lambda expression which can be converted into that functional interface.

For example, the merge() method of java.util.Map interface accepts a BiFunction, but if you don't know what is BiFunction then you cannot write lambda for that.

A BiFunction is a functional interface which has a method which accepts two arguments T and U and returns an object R.

This means you can pass a lambda to this method which works on two arguments and return an object e.g. merge(key, value, (v1, v2) -> v1 + v2) here (v1, V2) -> v1 + v2 is a lambda expression which can be converted into an instance of BiFunction functional interface.

A rather simpler example is Predicate which accepts a type T and returns a boolean. If you look filter() method of Stream class it accepts a Predicate:

filter(Predicate predicate)

This means you can pass any lambda expression which accepts one argument and return boolean to this method e.g. age -> age > 15 or s -> s.length == 15, both are acceptable, but if you don't know what is a Predicate interface then you can't do that.

Another example of a functional interface is Consumer which accepts an argument of type T and return nothing. A good use of this is made in the forEach() method of Iterable in JDK 8, as shown below:

forEach(Consumer action)

You can see that forEach() accepts a Consumer, which means you can pass it a lambda expression which has one argument and returns nothing or the void e.g.

s -> System.out.println(s)

The code System.out.println() return nothing, it just prints line in the console.

You can see that if you know functional interface then you can easily write a lambda expression to pass around, hence good knowledge of functional interface is mandatory. I suggest you go through all functional interface in java.util.function package and understand them.

 I'll explain about some of the more complex functional interfaces from the java.util.function package in coming articles but if you can't wait then I suggest you go through this Java 9 Master Class course to learn more about lambdas and other Java 8 concepts.


That's all about what is a functional interface in Java. You have also learned what is the role of @Functional annotation and why a good knowledge of functional interface is required to make effective use of lambda expression in your code in Java 8. If you are yet to start with Java 8, I suggest you do it now because in coming years everybody will code using Java 8 and if you don't know lambda expression and new features introduced in Java 8 then you will be left behind.

Other Java 8 tutorials and Resources for further learning

Thanks for reading this article so far. If you like my explanation of Functional interface and @Functional annotation then please share with your friends and colleagues. If you have any questions or feedback then please drop a comment. 

P.S - One of my reader suggested 'Beginning java 8 language features' book by kishori sharan in comments and I found it really good, even if you have some background. If you want to learn Java 8 in depth, I would also recommend the series of three books on Java 8 from this author.

7 comments :

Anonymous said...

Good article.
Note that it is not completely true to say a functional interface should have exactly one abstract method. Check the comparator interface for reference.

Javin Paul said...

What do you mean sir? That's the whole basic of functional interface unless I have a big misconcept. Comparator always have just one abstract method, the compare() method and if there have been any more abstract method added on JDK 8, every Comparator implementation would have blown away and possibly every Java application around the world.

I think you are referring to several default and static methods added into the Comparator interface in JDK 8 which was made possible because of extender methods in Java 8. That's ok, but functional interface means just one abstract method.

Anonymous said...

Nope, I am not talking about default and static methods at all.
Notice that the comparator has two abstract methods
int compare(T o1, T o2) and
boolean equals(Object obj)
Both are abstract.

Note that an interface may have more than one abstract method, and can still be a functional interface if all but one of them is a redeclaration of the methods in the Object class. I hope this clears your doubt regarding abstract methods in functional interface. If so, Refer book 'Beginning java 8 language features' book by kishori sharan. I would highly recommend this book to all the java developers. I am learning java 8 from this book and I really enjoying it. I would recommend the series of three books on java 8 from this author.

Javin Paul said...

@Anonymous, Thanks, I really didn't know about this point. It make sense though. Sure, I'll refer that book. Thanks for suggestion and adding value to this blog.

Javin Paul said...

@Anonymous, just read the intro on Annotations from this book and got really impressed with the content and writing. Huge Thanks!! for suggesting this book, ordered all three together. Don't know How I missed this book ...

--j aneiros said...

I think equals doesn't count here, it is simply overriding the equals public method of the Object class. See more here: https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html

So Comparator still has only one "countable" abstract method.

Anonymous said...

It clearly written here that equals() method doens't count as an abstract method in terms of functional interface.
https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html

Post a Comment