Java syntax allows you to create instances of anonymous types without much boilerplate. This approach is commonly use to implement single-use instance of Single Abstract Method-style interfaces such as Comparable
and Runnable
:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello, world!");
}
}).start();
In the code above, we simultaneously create an anonymous subtype of Runnable
and an instance of that subtype, which we immediately pass to the Thread
constructor.
This pattern also works with non-abstract types, most notably with the List instance initializer pattern.
List<String> list = new ArrayList<>() {{
add("Hello");
add("world");
}};
The anonymous subtype of ArrayList has an initializer block that invokes its add
method twice, thus populating the list on initialization in a syntactically brief manner.
You can even add NEW methods to these anonymously-typed instances, for example:
Object o = new Object() {
public int getSecret() {
return 9;
}
};
But what's the point of doing this? The Object reference cannot see the new method because it's not defined in the base Object type. It's effectively invisible, which is probably why I've never seen this technique used in a legitimate application...until today.
In a Spring Boot application, I was using Freemarker to implement the view. I wanted to provide an object in the model which had an "id" property that returned a random number. Here's the controller method implementation:
@RequestMapping(value="entity/{id}", produces="text/html")
ModelAndView retrieveEntity(@PathVariable String id) {
ModelAndView mav = new ModelAndView("entity_as_html.ftl");
mav.getModelMap().put("random", new Object() {
final Random random = new Random();
public int getId() {
return random.nextInt();
}
});
return mav;
}
And here's a relevant snippet from the Freemarker template:
<element id="${random.id?string("#")}"/>
Freemarker is essentially doing duck typing here--it doesn't care what actual type that "random" is, only that it has a property named "id." Thus, I can provide to the model an object of whatever type I wish that has an "id" property, and I felt it most convenient for the type of that object to be an anonymous sub-type.