In the first post of this easy introductory series we have introduced the basic foundations of how to form a lambda expression.It’s now time to learn how we can use them.
We have already learned that the basic idea behind lambda expressions is to assign a block of code to a variable.
As a variable can be passed, as an argument, to methods, this means that we can pass a block of code around, which will lead to the ultimate goal - passing behaviours around our application, without the need to create extra classes.
Remember, functions live in isolation and they are entities in their own right.
We finished the previous post by showing this piece of code,
and asking ourselves “What is the type of the gentsSalutation variable ?”, because as we know Java is a strong typed language, so all variables need to be assigned a type.
The Functional Interface
Java 8 brought us the concept of Functional Interfaces.
By definition, “A Functional Interface is an Interface that contains one abstract method (a method with no implementation).there is an exception, mentioned below in the post
The java.util.function Java 8 documentation, also states “Functional Interfaces provide target types for lambda expressions and method references”.
By combining the above, we can then say that a functional interface is an interface with only one abstract method that provides a target type for lambda expressions.
I will take the example from the previous post. We can see that an interface named salutation is already in place.
1 | public interface Salutation { |
We have an Interface, which has only one method, and that method has no implementation, so it is abstract. It looks like we have a perfect candidate for the above definition and, as so, we are in the presence of a Functional Interface.
So, if a Functional Interface can be a target type for a lambda expression, what will happen if we assign the Salutation type to our gentsSalutation variable ?
Let’s fetch part of the the code we need from the previous post
the Interface,
1 | public interface Salutation { |
the Service,
1 | public class SalutationService { |
We also had the App class, but we will now change it to include our gentsSalutation variable as being of type Salutation
1 | public class App { |
The salute method of the SalutationService, was already accepting a Salutation object, and now our gentsSalutation variable has been assigned that same type, therefore it becomes possible to pass it as an argument to the method.
When run, this code works perfectly and we get the same result as before, but now we are using the lambda expression.
So, what happened here ?
We got rid of the GentsSalutation and the Ladiessalutation classes. We created two expressions (function - which executes an action) and assigned them to the variables getsSalutation and ladiesSalutation. As variables can be passed around, we passed those variables to the service and there, the code was executed when we called .perform() on it.
To clarify, let’s see what happens if we change our app class in a way that we do not use the service class,
1 | public class App { |
When run, this code does exactly the same.
So we can conclude that the lambda expression is actually acting as if it was an implementation of the interface and we could drop the SalutationService class if we wanted (although in my opinion, the presence of the service class makes things easier to understand).
This is the reason why a Functional Interface can only have one abstract method see exception bellow. If you had more than one, then the compiler would not know which one would be related to the lambda expression.
Java 8 also introduced the annotation @FunctionalInterface, which is to be used so that the compiler knows that an Interface is supposed to be Functional.
It is not mandatory to use the annotation, however is good practice to do so, as it makes clear the nature of the interface. Also if someone changes the code in a way that it becomes a non functional interface, the compiler will immediately complaint about it, pointing us that the interface is not Functional.
As we like to follow good practises, we change our interface to,
1 |
|
Earlier we wrote “a functional interface is an interface with only one abstract method that provides a target type for lambda expressions”.
ImportantHowever there is an exception. If we change our Salutation interface to,
1 |
|
compiling and running the code, will not present any problems. This seems to be in contradiction to the Functional Interface definition. We clearly have 3 abstract methods in there.
About Functional Interfaces what we need to retain is that abstract methods that override public methods in java.lang.Object do not count to the total of the abstract methods in the interface.
Having said that, the above code mantains it’s integrity as a functional interface, as only the perform() method does not overrides public methods from java.lang.Object.
In this and the previous post, we have looked into the very basics of lambda expressions.
In the next post, we will start to create some more elaborated functions,
‘till then…happy coding.