
Can you remember anonymous classes?
What did we actually do with an anonymous class?
Here’s an example. I think you can still remember Java swing. It is used to create graphical user interfaces with Java.
In swing, we have button objects. When a user clicks on a button, some work has to be done. This work is passed to the button via an object implementing ActionListener interface. For that , we use an anonymous class.
1 2 3 4 5 6 7 8 |
JButton btn = new JButton(); btn.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { System.out.println("Hello world"); } }); |
ActionListener interface has only one function called actionPerformed().
When user clicks the button, the code inside that function will be executed.
OK. Now, why are we writing
1 2 3 4 |
new ActionListener(){ @Override public void actionPerformed... |
part?
If you look close enough, you’ll see we need only the function!!!!
Name of the function is also not necessary, because, actionPerformed() is the only method in the interface ActionListener.
So, our useful code part will always be:
1 2 3 |
(ActionEvent e) { System.out.println("Hello world"); } |
Well, now you can remove all the unnecessary parts in our code using a Lambda expression…
Let’s use it.
1 |
btn1.addActionListener((ActionEvent e)->System.out.println("Hello world!")); |
Only one line. How cool is that? This is a Lambda expression.
Let’s see how to use Lambdas 🙂
Lambda expressions?
In the previous example, first we instantiated an anonymous class to describe the functionality of a button. That is, to show how the button works.
But the code of an anonymous class is bit indirect and verbose. With Java 8 lambda expressions, we can directly pass the functionality as an argument.
It’s just an anonymous FUNCTION!
Lambda expressions are used in the context of a functional interface.
Functional Interface
Interface having only ONE abstract method is called a functional interface. For example, in the ActionListener interface above, we have only one method, actionPerformed().
So, when we are creating an object implementing only a functional interface, we don’t need to write long anonymous class thing again. We can use a lambda!
Annotation
If you are creating your own functional interface, you can use the annotation @FunctionalInterface before the declaration. It will show an error if you include more than one method to your interface.
Eg:
1 2 3 4 |
@FunctionalInterface public interface Filter{ boolean test(String s); } |
Parts of a Lambda expression

If you passing multiple lines, use brackets {}
1 2 3 4 |
(ActionEvent e)->{System.out.println("Hello world!")); System.out.println("Hello world!")); System.out.println("Hello world!")); } |
In your functional interface, if the declared method only returns something, you don’t need to type return.
For example if your functional interface is
1 2 3 |
public interface Filter{ boolean test(String s); } |
and you can create an object implementing Filter like this
1 |
Filter testFilter = (String str)-> str.isEmpty(); |
You have to return boolean value when implementing the test() method.
str.isEmpty() method returns a true or false value and you don’t need to explicitly write the “return” keyword when your method has only one line.
If you have multiple lines, then you can use {}. But if you use brackets, you have to include return statement.
1 2 3 4 5 6 |
Filter testFilter = (String str)-> { //several lines return str.isEmpty(); } |
Point to be noted:
Java can detect the type of of the variable str in the (String str) above. How? Because, in the functional interface declaration, we have only ONE method.
In that only method, we are writing the type of the parameter. Here, the type is String. So, it knows str is String.
So, you can just write,
1 |
Filter testFilter = (str)-> str.isEmpty(); |
You can remove the brackets in (str) as well.
1 |
Filter testFilter = str-> str.isEmpty(); |
(Later in this article, you’ll see this example lambda expression can be replaced with a method reference as well.
1 |
Filter testFilter = String::isEmpty; |
)
Functional Interface examples
You can of course create your own functional interface and use lambda expressions for their implementation.
But, there are some common functional interfaces that are already available in java.util.function package.
I’ll describe 2 of them here as examples. The rest, you can easily find details by an online search 🙂
Predicate interface
You can import this interface using
1 |
import java.util.function.Predicate; |
This Predicate example requires the knowledge of behaviour parameterization that I have already discussed in the previous article. For now, Let’s have a quick revision with an example.
Predicate functional interface has a method called test() that accepts an object T and returns a boolean value.
The interface is:
1 2 3 4 |
@FunctionalInterface public interface Predicate { boolean test(T t); } |
Suppose you have an created a class called Book. It is as follows;
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static class Book { private String name; private String category; private String author; private int edition; //get and set methods for the //variables are needed… public String toString(){ return name+", edition "+edition+", by "+author; } } |
It has several variables for various things in a book: Name, category, author and the edition. They are private variables and therefore, get and set methods are needed to be written.
Also, the Book Class has the toString() method so that when we want to print a Book variable by calling print() function, a string containing the name, edition and the author of the book is shown.
Now, suppose we have a list of books. We now need to traverse book list and put all electronics books in to a new list.
We can use a for loop to do that.
1 2 3 4 5 6 7 8 9 10 |
public static ArrayList filter(ArrayList rawList,Predicate p){ ArrayList filteredBooks = new ArrayList<>(); for (Book book:rawList){ if(p.test(book)) filteredBooks.add(book); } return filteredBooks; } |
See, in the filter(), we use a Predicate that accepts an object of type Book and the test() method in predicate should return a boolean value whether the book is in category “Electronics” or not.
How do we call the filter() method?
We have the unfiltered ArrayList of books called rawList.
1 |
ArrayList filteredBooks = filter(rawList,book->book.getCategory().equals("Electronics")); |
the part
1 |
book->book.getCategory().equals("Electronics")); |
is the one which implements the Predicate interface.
The behaviour parameterization is achieved with this interface. We can easily change the Predicate code and pass the new behaviour to the same filter() method.
Then a filtered book list with a different requirement can be obtained. But, if you write the behaviour of filtering electronics books inside the for loop like old days 🙂 then you have to create another new method to get a different filtered book list.
(With Java8 Streams, we even don’t need to write a filter() method with the for loop. Streams has its own filter() method. Then, we can shrink all code we written for filter() and its call to
1 2 |
List filteredBooks = rawList.stream().filter(book->book.getCategory() .equals("Electronics")).collect(toList()); |
I hope to discuss about Java Streams in next articles)
Consumer interface
This interface consists of an abstract method called accept() that takes an object of type T and returns null.
This is useful when performing an operation on the object T.
For example, suppose we want to do something with each book in book list. For that, we can write a method as follows.
1 2 3 4 5 |
public static void forEach(ArrayList list,Consumer oper){ for(Book book:list){ oper.accept(book); } } |
Now, I want to print each book. So I can give,
1 |
forEach(rawList,book->System.out.println(book)); |
(The Book object will give a meaningful output for print() method, because, in the Book class, we have overridden the toString() method in the Book class definition above)
Method references
1. Calling static methods
Sometimes, you use a Lambda expression only to call a method. For example, in the previous example of forEach() method, you are using the lambda only to call print() function. So, you can write,
1 |
forEach(rawList,System.out::println); |
instead of
1 |
forEach(rawList,book->System.out.println(book)); |
that is, you can replace the lambda,
1 |
book->System.out.println(book) |
with
1 |
System.out::println |
Note the structure of this method reference,
Class_name::Method_name
we are calling a method inside the accept() method of the Consumer object.
For the accept() method, we are passing an argument called book which is of type Book.
That same book is used as an argument to another method.
In that case, we don’t need to create the argument book in the first place.
Java can understand you have to input an argument and the same object is used for again as an argument for the method you are going to call.
The method print() is a static one. You can have method references for non static methods as well.
2. Calling non-static methods
The format of the method reference for calling instance method of an object is
Class_name::Instance_method_name
For example, say, you have created a functional interface having a method that takes a book object and gives out the author.
So the lambda expression would be
1 |
book -> book.getAuthor(); |
Now you can do the same thing. The method reference would be
1 |
Book::getAuthor(); |
3. calling non-static method of an existing object
If you are referring an instance method of an existing object, the method reference would be
Existing_object_name::Method_name
Eg:
Suppose you have a Book object created locally. You have written a functional interface like this.
1 2 3 4 |
@FunctionalInterface public interface myInterface{ public String test(); } |
Now, you have a local Book object in your main() method, called book.
You also need an object implementing the functional interface. So you can write,
1 |
myInterface obj = book::getAuthor; |
instead of the lambda expression,
1 |
myInterface obj =()->book.getAuthor(); |
A plenty of articles explaining java lambdas are available in the internet. But, when I searched to learn about the Lambda expressions, I couldn’t find myself a satisfactory result with a quick approach. So, I note down some key points and wrote this article 🙂 If you find any problem, error or anything, please be kind to comment. I really appreciate that!
If you like the post, I request kindly to share it with your friends and support the blog. Thanks for reading!