What is a Functional interface in Java 8? @FunctionalInterface Annotation Examples Tutorial
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 likeLambda 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 @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 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 Functional interface in Java 8
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 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 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 aStrategy 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 , a free 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 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 What's New in Java 8course 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 code like filter() method which accepts a Predicate and allows you to pass a code which accepts one argument and return boolean.
You can further see Java 8: basics for beginners , a free course to learn Java 8 to learn more about all those built-in functional interfaces in depth.
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 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 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 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 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 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 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 thisJava 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.
Further Learning
The Complete Java MasterClass
Java 8 New Features in Simple Way
From Collections to Streams in Java 8 Using Lambda Expressions
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 Functional interface and @FunctionalInterface 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 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.
Join the conversation