A few days ago VirtualJUG featured a very interesting talk on the upcoming new version of JUnit, namely JUnit 5. Nicolai Parlog did a great job in explaining the new features and architecture of the new version – if you haven't seen it yet, go ahead and watch it. This weekend I've been getting my hands dirty and I gave the current beta version a try. Intellij IDEA 2016.2 already has JUnit5 integration, so it's quite easy to start off. There's a git project that you can clone which is set up with the required dependencies.
As I said, Nicolai's talk covers the new features of JUnit 5 and there's probably not much to add. So why am I writing a blog post then? And why is this post headlined "Double brace initialisation and initialisation blocks"?
The it() method is defined in the class LambdaTest and is used to create a Dynamic Test, that will be added to a list. A @TestFactory method in LambdaTest will then return that list to the JUnit framework and the tests will be executed. The point here is to make tests easier to read and loose some of Java's verbosity (BTW: This style reminds me of a library I blogged about a while back: Oleaster). The example was presented as "a little hacky", since it supposedly uses double brace initialisation.
Note the double braces when creating the ArrayList. Some people use this style in order to type less, because in an initialisation block you work in the context of an object and don't need to reference it explicitly. But what do the braces actually mean? Well, the outer pair of braces will create an anonymous subclass of ArrayList for which the inner pair of braces sets up an instance initialisation block. That means, everytime you create an instance in that way, you are actually creating a new Type (=subclass of ArrayList) that your classloader will have to manage. That already sounds bad, but there's something more important: The anonymous subclass contains a reference to its enclosing instance, in this case Application. That means, everytime someone calls getFruits() the result will contain a reference to the Application instance. Which potentially will prevent the Application instance to get garbage collected, thus creating a memory leak.
For this reasons double brace initialisation is considered an anti-pattern and you should refrain from using it.
If you like you can read more about this here.
Before returning to the initial example, let's look at initialisation blocks in general. Java provides several ways to initialize classes and objects. The most common way to intitialize objects is obviously through constructors. A class can have several constructors and as a developer you can freely choose an existing one when creating an object.
You can have multiple instance initialisation blocks and they are processed in the order they are defined.
You can read more about initialisation blocks here and here.
When you create a class in Java, you have to use a pair of braces to encapsulate its content. The second pair of braces in the initial example is an instance initialisation block. It gets executed right before the constructor and in the example above executes the it() method to register a dynamic test with the @TestFactory. It does not create an anonymous class. You can actually see that by looking at your project's classes folder. I think the problem that led to the inaccurate explanation is mainly a visual misunderstanding and also maybe an imprecise name for the anti-pattern: Just because you have a succession of two braces doesn't mean that you create an anonymous class. A problem only arises when you create an instance using double brace initialisation.
I want to thank Nicolai and the good folks at VirtualJUG because I wouldn't have looked into that topic, if that example wouldn't have caused some confusion and caught my attention.