Let us say that you are in a hurry, you do not know the local language and you need directions to travel from point A to point B. You finally see just one stranger on the road who can speak in your language and this is how he instructs you to get to point B:
- Walk straight for about a 100 metres and around the corner take a right. Hey, on your way don’t forget to notice my favorite restaurant which serves the best pasta.
- Once you take a right, walk straight down for another 100 metres, and take a left. During the 100 m walk, you will see a gymnasium, that is where I work out.
- Then your destination will be on the right side but before you cross over to the other side, don’t forget to look at the beautiful tower clock.
If you are really in a hurry and not hungry, do you really care about the pasta and the tower clock ? Well anonymous classes in Java are a bit like this. You setup a lot of instructions before the actual set of instructions that we are really interested in.
When you sit in a plane, do you go to the pilot and tell him how to get to the destination? You don’t ! You sit in the plane and let the pilot do the job for you. And well, pray that he does it well☺ !
Why am I talking about Anonymous classes ? You must be thinking – Do I have to learn that now to understand lambdas? Aren’t they kind of ugly? Yes, you are right, they are! But sometimes, things in life can get ugly and if I may get a little philosophical, ugly things in life make you stronger and probably motivate you to do the same things in a better way.
Let us take a simple example:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Thread thread = new Thread(new Runnable() | |
{ | |
@Override | |
public void run() | |
{ | |
System.out.println("Do something In the thread…"); | |
} | |
}); | |
thread.start(); |
Take a look at the code above and you will probably feel like this :
If you asked an experienced developer on your team (so called expert), they might say : That is nothing but an anonymous inner class which implements the Runnable interface. Once you implement the Runnable interface, you override the run method. The computation that we need to perform in another thread is written in that run method.
We had to do so much to print that line in the run method so that it executes in another thread. Is there a better way to do that? Let us give it a try, let us break that down a little bit.
What are the parameters to the run method? None. What is the run method doing? Just that one single line which prints a message. Our main focus is the run method which takes no parameters and performs some computation. So we could represent the parameters to the run method as () indicating empty parameters. The body of the method is System.out.println(“Do something in the thread”) and now let’s combine the two.
What do we get ?
() - System.out.println(“Do something in the thread”);
Let us a use a different separator, the ->. The -> is just a separator between the parameters to the run method and the body of the method.
() -> System.out.println(“Do something in the thread”);
And well, that is a lambda expression!
So we can actually replace the code using anonymous class as:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Thread thread = new Thread( () -> System.out.println("Do something in the thread…")); | |
thread.start(); |
So we have been able to refactor our code from:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Thread thread = new Thread(new Runnable() | |
{ | |
@Override | |
public void run() | |
{ | |
System.out.println("Do something In the thread…"); | |
} | |
}); | |
thread.start(); |
To:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Thread thread = new Thread( () -> System.out.println("Do something in the thread…")); | |
thread.start(); |
That surely looks a lot better. This code is quite clear in conveying what we really intend to achieve in the thread, unlike the stranger who gave us a lot of instructions which was not really useful.
Are lambdas just a replacement for the inner class syntax above? Is the compiler doing the same thing behind the scenes?
No, it isn’t! When we write an anonymous class using the anonymous class syntax and compile our code, we actually get 2 classes. <ClassName>.class and <ClassName$1>.class. When we use the lambda expression, we get just 1 .class file. That is one of the most important differences between an anonymous inner class and a lambda expression. How this really works behind the scenes will be covered in another article. But to give you a heads up, this is done using a byte code instruction called the invokedynamic that was introduced in Java 7.
How did we manage put a lambda in place of an anonymous class?
Instance of a Thread class takes a Runnable:
Thread t = new Thread( Runnable target);
Runnable is an interface. We started with an anonymous class which was then replaced with a lambda.
Thread t = new Thread( () -> System.out.println(“Do something in the thread…”));
So it means, we actually managed to do this:
Runnable target = () -> System.out.println(“Do something in the thread…”);
Well, the Runnable interface has been there in the JDK library right from the beginning.How did we just manage to replace all of that code with a lambda ? This is because Runnable is an interface, it has just one method, the run method. This is now called a functional interface – An interface with 1 abstract method. Runnable has just one – run().
@FunctionalInterface public interface Runnable{ void run(); }
Thread class takes Runnable and we can assign a lambda to Runnable since it is a Functional interface. The signature of the run method gives us an insight on the lambda expression.The return type is automatically inferred by the compiler.
A lambda expression can take multiple parameters:
(int a, int b) -> a+b;
A lambda expression can also have multiple statements:
() ->{
System.out.println(“One”);
System.out.println(“Two”);
};
Lambdas that have multiple statements need to be enclosed in curly braces. We must try and avoid having too many statements in the curly braces above as this will defeat one purpose of lambdas – clarity in code. If you see the body of the lambda getting too big, replace it with a function.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Thread thread = new Thread( () -> doSomeLongRunningOperation()); | |
thread.start(); | |
private static void doSomeLongRunningOperation() | |
{ | |
//code in function. | |
} |
To solidify our understanding , let us go through another example.
Let us sort a list of strings by their decreasing length using a Comparator.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
List<String> strings = Arrays.asList("Joey", "Ben","Sandra","Glen"); | |
Collections.sort(strings, new Comparator<String>() { | |
@Override | |
public int compare(String s1, String s2) { | |
return s1.length() < s2.length() ? 1 : –1; | |
} | |
}); | |
System.out.println(strings); |
The 2nd parameter to the sort method is an instance of Comparator. What do we really want to do in the code above ? We want to sort strings by their length but landed up doing a lot more.
Is this a good candidate for Lambdas ? Let us find out by asking the following questions
- Is there an instance of an anonymous inner class- Yes
- Does Comparator have only 1 abstract method – Yes
Let us go ahead and replace it with a lambda like we did it with Runnable.
- What parameters does the compare method take – 2 Strings.
- What is the method doing – comparing the length
(String s1, String s2) -> s1.length() < s2.length() ? 1 : -1
Let us replace the code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
List<String> strings = Arrays.asList("Joey", "Ben","Sandra","Glen"); | |
Comparator<String> sortByLength = (String s1, String s2)-> s1.length() < s2.length() ? 1 : –1; | |
Collections.sort(strings, sortByLength); | |
System.out.println(strings); |
In fact, the compiler is smart to know that we are sorting a list of Strings. Hence the same code can be written without mentioning the type of s1 and s2.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
List<String> strings = Arrays.asList("Joey", "Ben","Sandra","Glen"); | |
Comparator<String> sortByLength = (s1,s2)-> s1.length() < s2.length() ? 1 : –1; | |
Collections.sort(strings, sortByLength); | |
System.out.println(strings); |
We assigned the behavior of comparing strings by length to type Comparator.
To summarize, lambdas:
- Help us concentrate on what we want to do rather that how to do it
- Pass behavior to function which can be a very powerful mechanism.
- Are anonymous functions that map to functional interfaces.
Finally, I hope we have been able to move our state….
![]() |
![]() |