Guide to Anonymous Classes and Lambdas in Java
This article introduces you to Anonymous classes in Java, how they are made, what use they are of and what purpose do they achieve. Finally, we’ll also have a look at when not to use them which is a major concern adding their comparison with Java 8 Lambdas.
Anonymous Inner class
Anonymous class are classes which are declared without a name. They enable you to make your code more concise and clean. Let’s look at a bunch of code straightaway which is pretty clear on what it does:
// first set of braces is the Anonymous inner class
Map map = new HashMap() {{
put("key1", "value2");
put("key2", "value2");
}};
Same code can also be written as:
Map map = new HashMap();
map.put("key1", "value1");
map.put("key2", "value2");
In the above example, we used an anonymous class to put values in Hashmap which saved some redundancy when doing a lot of put statements. To elaborate, the first set of braces is the Anonymous inner class (subclassing HashMap). The second set of braces is an instance initializer (rather than a static one) which then sets the values on the HashMap subclass.
>>> Note : Anonymous classes cannot have constructors.
Anonymous inner class enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have any name. Use them if you need to use a local class only once
Example
The following example, OrderPizzaAnonymousClasses, uses anonymous class in the initialization statements of the local variables countryPizza and farmPizza, but uses a local class for the initialization of the variable comingPizza:
public class OrderPizzaAnonymousClasses {
interface MyPizza {
public void pizza();
public void orderPizza(int count);
}
public void letsEat() {
class OrderPizza implements MyPizza {
int count = 2;
public void pizza() {
orderPizza(2);
}
public void orderPizza(int howMany) {
count = howMany;
System.out.println("Pizza count " + count);
}
}
MyPizza comingPizza = new OrderPizza();
MyPizza countryPizza = new MyPizza() {
int count = 4;
public void pizza() {
orderPizza(3);
}
public void orderPizza(int howMany) {
count = howMany;
System.out.println("Country Pizza Count " + count);
}
};
MyPizza farmPizza = new MyPizza() {
int count = 4;
public void pizza() {
orderPizza(3);
}
public void orderPizza(int howMany) {
count = howMany;
System.out.println("Farm pizza Count " + count);
}
};
comingPizza.pizza();
countryPizza.orderPizza(10);
farmPizza.pizza();
}
public static void main(String... args) {
OrderPizzaAnonymousClasses myApp =
new OrderPizzaAnonymousClasses();
myApp.letsEat();
}
}
Consider the instantiation of the countryPizza object:
MyPizza countryPizza = new MyPizza() {
int count = 4;
public void pizza() {
orderPizza(3);
}
public void orderPizza(int howMany) {
count = howMany;
System.out.println("Country Pizza Count " + count);
}
};
The anonymous class expression consists of the following:
- The new operator
- The name of an interface to implement or a class to extend. In this example, the anonymous class is implementing the interface MyPizza.
- Parentheses that contain the arguments to a constructor, just like a normal class instance creation expression. Note: When you implement an interface, there is no constructor, so you use an empty pair of parentheses, as in this example.
When to Use an Anonymous Class
- The class has a very short body.
- Only one instance of the class is needed.
- The class is used right after it is defined.
- The name of the class does not make your code any easier to understand.
- When you need to inherit a few properties of a superclass and it is not a good idea to take overhead of creating a separate subclass for doing things so simple.
Let’s build up on above situations with some examples:
- Use anonymous inner class in situations where you don't need to have a full-blown class just to perform some task. For example, to implement a Runnable, you do the following:
public void someMethod() {
new Thread(new Runnable() {
public void run() {
// do stuff
}
}).start();
}
In certain cases, such as the example above, it can increase readability, especially for one-time tasks, as the code that is to be executed is all written in one spot.
Java8 Lambdas vs. Anonymous classes
- An anonymous inner class (AIC) can be used to create a subclass of an abstract class or a concrete class. An AIC can also provide a concrete implementation of an interface, including the addition of state (fields). An instance of an AIC can be referred to using this in its method bodies, so further methods can be called on it, its state can be mutated over time, etc. None of these apply to lambdas.
- Majority of uses of AICs were to provide stateless implementations of single functions and so can be replaced with lambda expressions, but there are other uses of AICs for which lambdas cannot be used. AICs are here to stay.
- AICs introduce a new scope. That is, names are resolved from the AIC's superclasses and interfaces and can shadow names that occur in the lexically enclosing environment. For lambdas, all names are resolved lexically.
- Lambdas interfaces can contain only a single abstract method. It would fail as soon as your interface contains more than 1 abstract method. That is where anonymous classes will be useful.
- Anonymous classes can be directly annotated with the new Java 8 Type Annotations, for example:
new @MyTypeAnnotation SomeInterface(){};
Above is not possible with lambda expressions.
Apart from being syntactical sugar nature of Lambdas in Java, they also seems to differ in performance side:
- AICs have a slightly slower performance on first use, but it seems negligible.
- Lambdas have a slower performance when called often because of the bigger stack they build up when called.
This means Lambdas and Inner classes have use-cases as when to use what:
- Use Lambdas for readability when a few milliseconds performance loss is not a problem (GUI stuff, etc.)
- Use inner classes for often called, performance critical functions.
Let’s look at a little example of how same code can be written with Lambdas and with Inner classes, we will add an ActionListener to a Button:
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 button event handling logic in a Swing app. Listener code is a lot concise and more readable using lambda expression. */
public class Test extends JFrame {
private final JButton button = new JButton("Start");
public Test() { super("DiscoverSDK : AIC vs Lambda");
getContentPane().setLayout(new BorderLayout());
getContentPane().add(button);
button.addActionListener(new ActionListener() {
@Override public voidactionPerformed(ActionEvent evt) {
System.out.println("DiscoverSDK, this is using Anonymous Inner class.");
}
});
button.addActionListener(e -> System.out.println("DiscoverSDK, the magical (and concise) Lambdas."));
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:
DiscoverSDK, this is using Anonymous Inner class.
DiscoverSDK, the magical (and concise) Lambdas.
Let’s look at final example here using Collections, we’ll let you decide which one is easier to understand and read, AIC or Lambdas. What's easier to read:
myCollection.map(new Mapper<String,String>() {
public String map(String input) {
return new StringBuilder(input).reverse().toString();
}
});
Or:
myCollection.map(element -> new StringBuilder(element).reverse().toString());
or (using a method handle instead of a Lambda):
myCollection.map(String::toUpperCase);
Properties of an Anonymous Class
- It cannot access local variables in its enclosing scope that are not declared as final or effectively final.
- Declaration of static initializers or member interfaces is not allowed.
- It can have static members only if they are constant variables.
- It cannot have any constructors.
- An anonymous class will have access to the members of its enclosing class, only if their access level is not private. Let’s look at an example for this where we will display Inheritance in Anonymous Inner class as well:
public class Rectangle {
protected double length;
protected double width;
protected double perimeter;
public void calculatePerimeter() {
perimeter = (2*length) +(2*width);
}
public static void main(String[] args) {
/*Making square subclass. It overrides calculatePerimeter() and access ‘perimeter’ which is marked as ‘protected’.*/
Rectangle square = new Rectangle() {
public void calculatePerimeter() {
perimeter = 4*length;
}
};
}}
In above example, the Square is made a sub-class and is made to override a method calculatePerimeter(). It can access ‘perimeter’ only if it’s access-level is specified anything apart from ‘protected’.
Best Practices
One advantage of AICs is that no one can ever use it anywhere else, whereas a named inner class can be used (if only by the class that created it is made private). It's a small distinction, but it does mean that you can protect an inner class from being accidentally used elsewhere.
Also, using the anonymous inner class gives anyone reading your code a head's up - "this class is being used just here and nowhere else." If you see a named inner class, someone might think it'd be used in multiple places in the class.
They are very similar, so neither point is a game-changer. I just think it helps for clarity if you use anonymous inner classes for one-offs, and named inner classes when it's used multiple times within the class.
Recent Stories
Top DiscoverSDK Experts
Compare Products
Select up to three two products to compare by clicking on the compare icon () of each product.
{{compareToolModel.Error}}
{{CommentsModel.TotalCount}} Comments
Your Comment