Hello Java programmers, if you are wondering what is a functional interface and what is the role of @Functional annotation in Java then you have come to the right place. Earlier, I have shared the best Lambda and Stream courses and books, and in this article, I will explain and teach you how to create a functional interface in Java. A functional interface is nothing but an interface with just one abstract method like Runnable, Callable, Supplier, Predicate, etc. You can use @Functional annotation to mark that this is a functional interface. If a function expects a functional interface then you can also pass a lambda expression to it and that's the main benefit of a Functional interface in Java. This is also a popular Lambda Expression Interview question so, knowing this topic in depth is also better for interviews.
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 the 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 like Lambda expression and Stream API.
Without knowledge of the 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 the lambda expression the method is expecting, hence, it's important to have a good understanding of the 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 @FunctionalInterface annotation, how they are related to a lambda expression, and how they help you to use the lambda expression in your code.
Btw, if you are new to the Java Programming world, I suggest you start with an up-to-date course like The Complete Java Masterclass on Udemy. Since after a six-month release cycle introduced in Java 9, it's changing very fast. Within a span of one and a half years, Java moved from JDK 9 to JDK 12, the latest Java release.
Learning from an up-to-date resource also has the advantage that you learn new techniques like sorting HashMap using lambdas rather than using old techniques of going through loop etc.
So, let's start with the very first thing, what is a 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 like 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 the Comparator interface as shown below:
So, if you look closely, you can see we are passing code to a function using these interfaces. They are also known as strategy interfaces because this is an implementation of a 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 Java Design Patterns and Architecture, an awesome course on Udemy, as knowledge of design patterns is important for effective coding 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 a 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 expressions 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 is the reason that lambda expression in Java is also called of SAM type, where SAM means the Single Abstract Method. If you want to learn more about SAM type then you can also see the What's New in Java 8 course on Pluralsight to learn more about lambda expression in Java.
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 @FunctionalInterface annotation?
Well, it can ensure that the interface actually has 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 @FunctionalInterface 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 interfaces added in java.util.function package is annotated with the @FunctionalInterface 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.
These functional interfaces allow you to the passcode to a function in form of lambda expression and enable the creation of powerful methods which can operate on those codes like the filter() method which accepts a Predicate and allows you to pass a code that accepts one argument and return boolean.
And, If you are not familiar with Lambda Expression and Stream in Java then I suggest you check to Learn Java Functional Programming with Lambdas & Streams by Rang Rao Karnam on Udemy, which explains both Functional Programming and Java Stream fundamentals in good detail.
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 that has a method that 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 like 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 at filter() method of Stream class it accepts a Predicate:
This means you can pass any lambda expression which accepts one argument and return a 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 returns nothing. Good use of this is made in the forEach() method of Iterable in JDK 8, as shown below:
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.
The code System.out.println() return nothing, it just prints a line in the console.
You can see that if you know a 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 interfaces in java.util.function package and understand them.
I'll explain some of the more complex functional interfaces from the java.util.function package incoming 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 @FunctionalInterface 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 the 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.
P. S - One of my readers 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.
Btw, if you are new to the Java Programming world, I suggest you start with an up-to-date course like The Complete Java Masterclass on Udemy. Since after a six-month release cycle introduced in Java 9, it's changing very fast. Within a span of one and a half years, Java moved from JDK 9 to JDK 12, the latest Java release.
Learning from an up-to-date resource also has the advantage that you learn new techniques like sorting HashMap using lambdas rather than using old techniques of going through loop etc.
So, let's start with the very first thing, what is a functional interface?
What is a Functional interface in Java 8? Example
Well, a functional interface is nothing but an interface with just one abstract method like Comparable, Runnable, EventListener, Comparator, etc. You can see these interfaces were present in Java even before JDK 8, but why do we call such an interface a 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 like 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 the 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 interfaces because this is an implementation of a 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 Java Design Patterns and Architecture, an awesome course on Udemy, as knowledge of design patterns is important for effective coding 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 a 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 expressions 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 is the reason that lambda expression in Java is also called of SAM type, where SAM means the Single Abstract Method. If you want to learn more about SAM type then you can also see the What's New in Java 8 course on Pluralsight to learn more about lambda expression in Java.
What does @FunctionalInterface annotation do?
Now, let's see what does @FunctionalInterface annotation does? Will it make an interface functional if you just put the @FunctionalInterface 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 @FunctionalInterface annotation?
Well, it can ensure that the interface actually has 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 @FunctionalInterface 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 interfaces added in java.util.function package is annotated with the @FunctionalInterface 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.
These functional interfaces allow you to the passcode to a function in form of lambda expression and enable the creation of powerful methods which can operate on those codes like the filter() method which accepts a Predicate and allows you to pass a code that accepts one argument and return boolean.
And, If you are not familiar with Lambda Expression and Stream in Java then I suggest you check to Learn Java Functional Programming with Lambdas & Streams by Rang Rao Karnam on Udemy, which explains both Functional Programming and Java Stream fundamentals in good detail.
How Functional interface and Lambda 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 that 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 that has a method that 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 like 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 at 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 a 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 returns nothing. 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 a line in the console.
You can see that if you know a 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 interfaces in java.util.function package and understand them.
I'll explain some of the more complex functional interfaces from the java.util.function package incoming 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 @FunctionalInterface 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 the 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
- Top 5 Courses to Learn Java 8 Programming (courses)
- 5 Books to Learn Java 8 from Scratch (books)
- How to join String in Java 8 (example)
- How to use filter() method in Java 8 (tutorial)
- Java 8 map + filter + stream example (tutorial)
- How to use Stream class in Java 8 (tutorial)
- How to use forEach() method in Java 8 (example)
- How to format/parse the date with LocalDateTime in Java 8? (tutorial)
- 10 Examples to format and parse Date in Java 8? (tutorial)
- 10 Java Date, Time, and Calendar based Questions from Interviews (questions)
- How to change the date format of String in Java 8? (tutorial)
- How to compare two Dates in Java 8? (example)
- How to convert Timestamp to Date in Java? (example)
- 20 Examples to learn new Date and Time API in Java 8 (example)
- 5 Free Courses to learn Java 8 and 9 (courses)
Thanks for reading this article so far. If you like my explanation of the Functional interface and @FunctionalInterface annotation then please share it with your friends and colleagues. If you have any questions or feedback then please drop a comment.
10 comments :
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.
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.
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.
@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.
@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 ...
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.
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
@FunctionalInterface and not the @Functional
Hello Javin,
Can you please verify doubt regarding that a functional interface can extend another interface or not.?
Hello Vicky, interesting question, I haven't tested it but I think as long as you have just one abstract method, I think you can extend interface on Functional interface, but it shouldn't be difficult to test, just try in your Eclipse IDE or IDEA
Post a Comment