![]() | |
|
Replacing Anonymous Inner Classes with Lambda Expressions
Portions of your code contain anonymous inner classes, which are sometimes difficult to follow. You would like to replace anonymous inner classes with code that is easier to read and maintain.
Replace the anonymous inner classes with lambda expressions. By doing so, development time will be much faster as there will be fewer lines of boilerplate code required. A typical Java Swing application utilizes anonymous inner classes to add functionality to application constructs. For instance, anonymous classes are a great way to add an action to a button. The problem is that inner classes can be difficult to follow, and they contain lots of boilerplate code.
The following lines of code demonstrate a typical anonymous inner class implementation for a button action implementation. Let's look at these lines of code before taking a look at how you can achieve the same solution using a lambda expression.
JButton button = ... JLabel comp = ... button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { comp.setText("Button has been clicked"); } });
In this example, we are creating a new object that provides an implementation of the
ActionListener
interface. This interface has a single method, actionPerformed
, which is
called by the button
instance when a user actually clicks the on-screen button. The
anonymous inner class provides the implementation of this method.
Anonymous inner classes were designed to make it easier for Java programmers to pass around code as data. Unfortunately, they do not make it easy enough. There are still four lines of boilerplate code required in order to call the single line of important logic.
Boilerplate is not the only issue, though: this code is fairly hard to read because it obscures the programmer's intent. We do not want to pass in an object; what we really want to do is pass in some behavior. In Java 8, we would write this code example as a lambda expression, as shown in example below:
JButton button = ... JLabel comp = ... button.addActionListener(e -> comp.setText("Button has been clicked"));
Instead of passing in an object that implements an interface, we are passing in a block of code - a function without a name.
The 'e
' is the name of a parameter (it can be any valid Java identifier), like the parameter
in the anonymous inner class example.
The '->
' separates the parameter from the body of the lambda expression, which is just
some code that is run when a user clicks the button.
Another difference between this example and the anonymous inner class is how we declare the variable
e
. Previously, we needed to explicitly provide its type - ActionEvent e
.
In this example, we have not provided the type at all, yet this example still compiles. What is
happening under the hood is that Java compiler is inferring the
type of the variable e
from its context - here, from the signature
of addActionListener
. It means that you do not need to explicitly write
out the type when it is obvious.
![]() | |
In some situations where the Java compiler cannot infer types, you MUST explicitly specify values for type variables with type witnesses. |
Example below demonstrates explicit type declaration (optional for this particular example) of lambda method parameter:
JButton button = ... JLabel comp = ... button.addActionListener((ActionEvent e) -> comp.setText("Button has been clicked"));
Syntax of Lambda Expressions
A lambda expression consists of the following:
A comma-separated list of formal parameters enclosed in parentheses.
Note: You can omit the data type of the parameters in a lambda expression. In addition, you can omit the parentheses if there is only one parameter. For example, the following lambda expressions are valid:
s -> s.getAge() >= 18
(Student s) -> s.getAge() >= 18
(s) -> s.getAge() >= 18
The arrow token ->
A body, which consists of a single expression or a statement block. This example uses the following expression:
... -> s.getAge() >= 18
If you specify a single expression, then the Java runtime evaluates the expression and
then returns its value. Alternatively, you can use a return
statement:
... -> { return s.getAge() >= 18; }
A return
statement is NOT an expression; in a lambda expression, you MUST enclose
statements in braces ({...}
). However, you do not have to enclose a void
method invocation in braces. For example, the following is a valid lambda expression:
email -> System.out.println(email)
![]() ![]() ![]() |