Friday, September 10, 2021

How to use Lambda Expression in Place of Anonymous Class in Java 8 - Example Tutorial

Before Java 8, the Anonymous class was the only way you can implement functional idioms in Java. Since prior to Java 8 you cannot pass a function to another function, you would have to wrap it into an object, as seen in Strategy Pattern. Those are also known as function objects in Java. Anonymous class was also handy to create a throw-away implementation of SAM (Single Abstract Methods) interfaces like RunnableCallable,  CommandListener, or ActionListener. Despite all these goodies and flexibility, the Anonymous class adds too much boilerplate code, making it hard to read and understand.

Now with Java 8, you have got the ability to pass a function to another function in the form of the lambda expression,  you can easily replace your Anonymous class with lambda expression in Java.

Even if you don't want to do it for your older project, you shouldn't use the Anonymous class anymore for the purpose described above, instead, you should learn lambda expression and use it in place of the Anonymous class.

To get the ball rolling, I will show how you can use lambda expression instead of Anonymous class to implement ActionListener in Java Swing code.

Since lambda expression is of SAM type in Java and ActionListener only contains one method actionPerformed(ActionEvent ae) you can use lambdas to implement ActionListener, the result is much cleaner and concise code.

By the way, you cannot always use lambda expression in place of Anonymous class, because of its limitation of being SAM type. If you are using an anonymous class to implement an interface with two abstract methods then you cannot replace it with a lambda of Java 8.

And, If you are not familiar with Lambda Expression and Stream in Java then  I suggest you check to Learn Java Functional Programming with Lambdas & Streams by Rang Rao Karnam on Udemy, which explains both Functional Programming and Java Stream fundamentals in good detail.






Lambda Expression vs Anonymous Class in Java 8

Lambda expressions are very powerful and can replace many usages of anonymous class but not all. An anonymous class can be used to create a subclass of an abstract class, a concrete class, and can be used to implement an interface in Java. It can even add state fields.

An instance of an anonymous class can also be refereed by using this keyword inside its methods, which means you can call other methods and states can be changed.

Since the most common use of Anonymous class is to provide a throwaway, stateless implementation of abstract class and interface with a single function, those can be replaced by lambda expressions, but when you have a state field or implementing more than one interface, you cannot use lambdas to replace the anonymous class.

One more difference between lambda expression and anonymous class is that later introduces a new scope, where names are resolved from Anonymous class's parent class or interface and can shadow names that occur in the lexically enclosing environment, but for lambdas, all names are resolved lexically.

In short, lambda expression though a great feature has its limitation of being a SAM type. This means it can only replace the anonymous class when the former is used to implement a single method, if your anonymous class is implementing more than one interface, Java 8 lambdas cannot help.



How to use Lambda Expression in Java

As I said the anonymous class is very powerful but lambda is even better. Let's see a code example of how you can replace the Anonymous class with lambda expression in Java 8. This is a variation of the classical Swing Helloworld program.

Here I have a JFrame and a button, when you press the button ActionEvent will be generated, which is handled by the event listener you have attached to the button. In this example, we are not doing anything fancy but just printing log messages in the console to confirm that we have handled the event.

What is important in this example is the way we have coded event handling code. First, we are using Anonymous class to create an implementation of ActionListener so that we can override the actionPerformed() method, which took 5 lines of code, next to it is a new Java 8 way of handling events using a lambda expression, which just took 1 line of code. 

Imagine how many lines of code you can reduce in a real-world big fat Swing application full of buttons and other GUI components. Lambda is much more readable than an anonymous class.

How to use Lambda Expression in Place of Anonymous Class in Java 8 - Example Tutorial


You can even use this pattern to implement other SAM interfaces e.g. Runnable, Comparable, Comparator, and Callable in Java. If you are not sure how to do that, please check these top 10 Java 8 tutorials.

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

/**
 * Java program to demonstrate how you can use lambda expression in place of
 * Anonymous Inner class to implement event handling logic in Swing application.
 * Any listener code is lot concise and more readable using lambda expression.
 */
public class Test extends JFrame {

    private final JButton button = new JButton("Start");

    public Test() {
        super("Java 8 Lambda Example");

        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(button);

        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                System.out.println("Classic way of handling event 
                                          using Anonymous class");
            }
        });

        button.addActionListener(e -> System.out.println("Java 8 way"
                + " to handle event using Lambda expression"));

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(400, 200);
    }

    public static void main(String[] args) {
        // Lambda expressiont to implement Runnable interface
        SwingUtilities.invokeLater(() -> {
            new Test().setVisible(true);
        });
    }

}

Output:
Java 8 way to handle event using Lambda expression
Classic way of handling event using Anonymous class

When you run this program, you will see the following window, created by JFrame. Button is spread all over because of BorderLayout but as soon as you click on the button you will see the above line printed on the console.
Difference between anonymous class and lambda expression in Java 8

The good thing about Java IDEs is that they are now supporting Java 8 in content assist and providing useful hints to convert the anonymous class to lambda expression automatically. Here is the screenshot from Netbeans, where you can clearly see the hint about converting anonymous to lambda in  Java 8.


Using Lambda expression in place of Anonymous class in Java 8



That's all on how to use Lambda expression in place of an anonymous class in Java 8.  If you are coding in Java 8 make sure you use lambda expression instead of anonymous class for implementing ComparableComparator,  Runnable,  Callable,  CommandListener,  ActionListener, and several other interfaces in Java, which got just one single method.

You should also remember that because of being a SAM type (Single Abstract Method), you cannot use a lambda expression to implement a method with more than one abstract method. In short, it doesn't matter how powerful Lambda is it cannot replace the anonymous class fully, Anonymous class is here to stay.


Related Java 8 Tutorials from Javarevisited Blog
  • Top 5 Books to Learn Java 8 (read here)
  • How to use Stream API in Java 8 (learn here)
  • Understanding Default methods of Java 8 (learn here)
  • How to implement Comparator using lambda expression (see here)
  • How to filter Collection using Streams in Java 8 (check here)
  • 20 Examples of Date and Time in Java 8 (tutorial)
  • How to use Stream class in Java 8 (tutorial)
  • How to use filter() method in Java 8 (tutorial)
  • How to use forEach() method in Java 8 (example)
  • How to join String in Java 8 (example)
  • How to convert List to Map in Java 8 (solution)
  • How to use peek() method in Java 8 (example)
  • 8 Best Lambda and Functional Programming courses (best courses)

Thanks for reading this article so far. If you like this article then please share it with your friends and colleagues. If you have any questions, doubts, or feedback then please drop a comment and I'll try to answer your question.

P.S.: If you want to learn more about new features in Java 8 then please see these best Java 8 to Java 16 courses. It explains all important features of Java 8 like lambda expressions, streams, functional interface, Optionals, new date, and time API, and other miscellaneous changes.

4 comments :

Anonymous said...

Excellent example. Thank you. I believe that tricky Lambda expressions will show up soon on updated Oracle certification tests. If you know any tricky example please consider it in your next posts.

Anonymous said...

but how can we call them out side

leon said...

Great explanation on the limitation of using lambda to replace anonymous classes.(SAM).
Thank you!

TheBaldSpot said...

names are resolved from Anonymous class's parent class or interface and can shadow names that occur in the lexically enclosing environment, but for lambdas all names are resolved lexically ? I didn't get this. I understand what lexical means in terms of Programming , but Here in this context whats the difference between Anonymous and Lampda is something I didn't get. Can you elaborate?

Post a Comment