Java 8 Predicate Interface using Lambdas

I am going to tell you a short programming story. Let us assume that we have a system which deals with a list of Person objects. Person class has name, age, citizenship and gender.

One fine day your manager comes to your desk.

Manager: The current system should be able to give us a list of all the men.

Developer: That is easy.

Manager:  OK, this is a very critical requirement, check in the code in the next 1 hour.

You are brimming with happiness, you have done this so many times and then you say to yourself, that’s  easy!  I just need to initialize an empty collection, iterate over the list of collection, add an if condition and that’s it. This is what you come up with:

Before checking in the code, you look through the code again, notice the new List of men objects, the iteration and if condition. You feel a great sense of accomplishment and send an email to your manager and possibly your colleagues that your task is completed. You then hop away for lunch.

After a heavy lunch, you come back on your desk and notice the manager walk towards you, it looks like he has a very serious and difficult requirement.

Manager: Good coding, I have a new requirement for you. Now the system needs to fetch the list of all the women from the database.

You: Okay, consider it done.

Manager: Alright, I need you to do this in 45 minutes.

What do you do?  You know the class name, you open it, look at the getAllMen() and use the most favorite operations,  “copy” , “paste” and then rename the method name and change the condition. This is what you come up with:

There is a big smile on your face as you look at your watch, you accomplished this code in 5 full minutes. You look at your code and say to yourself, create new list, iterate, if condition. It looks good and then check in the code, but send the email after 40 minutes just to make sure that your manager notices the 5 minutes that you saved.

Then you suddenly look at the code again, create new empty list, iterate, if condition…… But then you realize that you have forgotten to rename the variable. There is a little bit of panic but you are really fast, you rename that variable, men to women, check in that code so quickly that even Vin Diesel from the Fast and the Furious fame would be ashamed. Now, it’s time for a cup of tea. 

The modified version

It’s 5:30 pm already, you know it is time to go home. But alas, the manager again walking towards you. You do not want to look at him this time, you stare at your PC as if you are really busy and have no time for anyone.

Manager: Good job, great coding, you are really fast but I need you to retrieve the list of all men who are citizens of USA.

Hmm, so, you look at your watch, he looks back at you..

Manager: I would like you to check in the code before you leave for the day.

How do you feel ? Frustrated. You promised to take your girlfriend on that coffee date at 7 pm. The manager leaves your table. You roll up your sleeves and start copy, pasting and profusely start typing.  You look at your code and say to yourself, create new list, iterate, change if condition and this time…..change variable name too!

This time you are more careful to rename the variables, you go through the code once, this time everything looks flawless. Time to check in!

You feel a great sense of accomplishment, 3 full methods in the entire day and pray that there are no bugs. It’s 6 pm, you send an email to your manager and everyone is now happy. Suddenly you look at all the 3 methods and how do you feel?  WASTED!  You ask yourself , can I change something here? You look at the 3 methods one more time and realize that the if condition that checks if the gender is male or female seems repetitive. You look at your watch once again, it is already 6:15! You decide to leave.

On your way to meet your girlfriend, as you are riding your bike, you feel that the air around is polluted but you know deep down inside about polluting the code base. You meet your girl friend, there is a big smile on her face but a lot of dirt on your face caused due to the code pollution.You have also committed another sin, you have forgotten to pick up flowers for her!

You wish you could have at least written a separate method to check if the gender is male. The meeting with your girlfriend does not go that good, well the code…..we all know about that.

The next day, you wake up early, have a shower, and think about the new method you are going to write. You feel really good and go early to office. You bring all your experience to the table and start writing a new method which can be reused.

 As you are belting out that code, your chest swells up as you see that method name:  isMan(). You refactor your old code and change all occurrences of the condition  

             if(person.getGender() == Gender.MALE) to isMan()

You look at your code and say to yourself, new list, iterate, if condition, add to list. You give yourself a pat on your back but this time you do not send an email to your manager.  Well, you don’t want him to know that you made a change to your own code. Time for a morning tea break!

You are back on your desk, the manager has not come to your desk for a long time. You wonder if there are bugs in your code. But just then, there is a ping from the manager……

Manager: Good morning, got a new requirement. The system needs to fetch all women who are American citizens.

You (say this to yourself ☺) : Easy! Copy, Paste, rename, change if!

This time, you look at your code a few more times and realize that you want to refactor anything that repeats. You keep looking at your code and realize that you could write a method isWoman and change all if conditions to use that. You quickly do that. How? Copy, Paste, rename!

You stare at your 2 methods, getAllMenUSA and getAllWomenUSA(). You keep staring at it for a few minutes, you think about today’s meeting at 7 pm and of course, it is with your girlfriend. Now, you really want to refactor something. You realize that you can actually combine 2 methods into one.

You then remove the 2 methods written earlier. You replace the calls to the 2 methods by 1 method.

Earlier:  getAllMenUSA(persons)

                 getAllWomenUSA(persons);

Now:      getAllPersonByGenderAndCitizenship(persons,gender,citizenship)

Time for review, new list, iterate, if condition, check in. Time for a long lunch break!

You are back… Of course, it is now time for a new requirement. No free lunch!

Manager: Hey, need a list of men who are above the age of 35 but citizens of Canada.

You: Silent….

You look at your getAllPersonByGenderAndCitizenhip and say, okay, hmm, let’s add a new parameter to that function and create a new method by copy, pasting and renaming the old method.

getAllPersonByGenderAndCitizenshipAge(persons,Gender.MALE,Citizenship.CANADA, age);

New list, iterate, if condition(s), add to new list. Done! You let out a burp! Heavy lunch, a lot of coding, of course the food had to digest that quickly! Check in……This time, you get up, walk past your manager, and give him a smile. That look on your face for writing really good code!

It is 4 pm now. To kill the time, you read your code, all the methods, and realize that you are really writing the same code all over, but if one is right, they are all right and hence decide not to change anything.

Out of boredom, you then look at your colleague’s machine, he is reading about DRY – Don’t repeat yourself. You ask him what that is. He explains it you and you say oh, that’s easy. The look on your face, well, it’s as if you have been doing it since you were 5. You wonder if you can apply it your code!

Well, what the developer does not realize is the fact that even after refactoring some of the methods, these requirements can spiral out of control. There could be many more methods like:

private List<Person> getPersonByGender(List<Person> persons, Gender gender)

private List<Person> getPersonByGenderCitizenship(List<Person> persons,Gender gender, Citizenship citizenship)

private List<Person> getAllPersonByGenderCitizenshipAge (List<Person> persons,Gender gender, Citizenship citizenship, Age age)

All this is only leading to copy, paste, and repeat. If you look at all the methods above, what is really changing is the “if” condition. Everything else remains the same and yet we are duplicating code. How do we solve this? How do we isolate the “if” condition? Java 8 Predicates to the rescue! The Predicate interface is a functional interface. It has a method called the test method as shown below:

@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t)

}

where t is the parameter that needs to pass a test. If it passes then it returns true else false

How do we use it?

This is done using lambda expressions. Right side represents the condition which in a lambda expression and then assign the condition to a Predicate reference.

How does it help?

Concentrate on the if conditions used in the code above and use a lambda expression instead.

All men: 

Predicate<Person> allMen = person -> person.getGender() == Gender.MALE;

getPeopleWithFilter(persons,allMen);

All women:

Predicate<Person> allWomen = allMen.negate();

getPeopleWithFilter(persons, allWomen);

All US Citizens:

Predicate<Person> usaCitizenship = p -> p.getCitizenship() == Citizenship.USA;

Get all men who are US citizens, done by combining predicates:

getPeopleWithFilter (persons, allMen.and(usaCitizenship));

Age above 35 years:

Predicate<Person> ageAbove35 = p -> p.getAge()  > 35;

Get all men who are US citizens and above the age of 35:

getPeopleWithFilter (persons, allMen.and(usaCitizenship).and(ageAbove35));

Now, all the methods written above can simply be deleted and replaced with:

You say to yourself, create new list, iterate, single if condition using predicate. Hmm, can we do something more? Can we get rid of the creation of the new list, the for loop ?

More refactoring:

The filter method on the stream accepts a Predicate which internally returns true or false. If it returns true, it gets collected into the list else it gets filtered out.

This code has no temporary creation of a new list during the stream or filter calls, has no explicit iteration, no repetitive if conditions!

The code looks cleaner, more expressive and maintenance of this code is easier. Using Lambdas and the Predicate interface we can do powerful things.The next time your manager walks up to you with a new requirement, write a simple Predicate and call the method above. It is 6 pm already, time to check in and leave for the coffee date, this time make sure you reach before time, carry some flowers or may be a card too which says “You look beautiful like my code”!

Moral of the story: Love thy code!

Java 8 Lambdas – A brief introduction

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:

  1. 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.
  2. 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.
  3. 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:

Take a look at the code above and you will probably feel like this :

Confused_Lambdas

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.

Lambdas_Funny

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:

So we have been able to refactor our code from:

To:

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.

To solidify our understanding , let us go through another example.

Let us sort a list of strings by their decreasing length using a Comparator.

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

  1. Is there an instance of an anonymous inner class- Yes
  2. Does Comparator have only 1 abstract method – Yes

Let us go ahead and replace it with a lambda like we did it with Runnable.

  1. What parameters does the compare method take – 2 Strings.
  2. What is the method doing – comparing the length

(String s1, String s2) -> s1.length() < s2.length() ? 1 : -1

Let us replace the code:

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.

We assigned the behavior of comparing strings by length to type Comparator.

To summarize, lambdas:

  1. Help us concentrate on what we want to do rather that how to do it
  2. Pass behavior to function which can be a very powerful mechanism. 
  3. Are anonymous functions that map to functional interfaces.

Finally, I hope we have been able to move our state….

Confused_Lambdas Happy_Lambdas