Double brace initialisation and initialisation blocks

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”?

Dynamic Tests

One of the new features JUnit 5 brings are Dynamic Tests. Those are tests that are created by JUnit at runtime. Instead of implementing a concrete @Test you are providing a @TestFactory for that purpose. You can use dynamic tests as a replacement for the Parameterized JUnit 4 test runner. During my JUnit5 exercises I returned to the video and something didn’t feel right about how a code sample in this context was discussed:

class LambdaTest {
 
  private List tests;
 
  protected void it(String name, Executable test) {
    tests.add(dynamicTest(name, test));
  }
 
}
 
class PointTest extends LambdaTest {{
 
  it("A Great Test For Point", () -> {
    // Test code goes here
  });
 
}}

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.

Double brace initialisation

So what’s the problem with double brace initialisation? Let’s look at another example:

public class Application {
 
  public List getFruits() {
    return new ArrayList() {{
      add("Apple");
      add("Orange");
      add("Banana");
    }};
  }
 
}

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.

Initialisation blocks

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.

As mentioned above, a class can also provide instance initialisation blocks. The Java compiler copies the content of an instance initialisation block into every constructor. Instance initialisation blocks look like this:

class Person {
 
  private String firstname;
  private String lastname;
 
  {
    firstname = "Jane";
    lastname = "Doe";
  }
 
}

You can have multiple instance initialisation blocks and they are processed in the order they are defined.

Java also provides static initialisation blocks. They get executed when the classloader reads the class. You can use them to initialize static members of a class:

class Person {
 
  private static defaultFirstname;
  private static defaultLastname;
 
  static {
    defaultFirstname = "Jane";
    defaultLastname = "Doe";
  }
 
}

You can read more about initialisation blocks here and here.

Back to the LambdaTest

So what’s up with the initial example? Yes, you can see double braces there, but if you look closely, that example doesn’t create an instance. It creates a new Type called PointTest, which extends LambdaTest. If that example wouldn’t do anything else, it would look like this:

class PointTest extends LambdaTest {
  // empty
}

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.

2 thoughts on “Double brace initialisation and initialisation blocks

Leave a Reply