; last updated - 5 minutes read

Lukas Eder has an interesting story: The popular double braces idiom is a poisoned gift. It causes memory leaks.

Let me start with a quick note on my article. Originally, I simply wanted to provide a link to the article written by Lukas. However, there are several points I disagree with him. You need some background to understand my contradictions, so I ended up with an article that covers almost the same story as the original article. That said, I recommend to read The Double Curly Braces Anti Pattern as well as reading my article. There's a lot of shared content, but there are also differences.

Double braces idiom in a nutshell

Everybody who's seen one of the newer JVM languages asks why Java is such a ceremonious language. It can't be so difficult to implement something like

ArrayList trafficLights = ["green", "yellow", "red"];

As far as I know, this isn't going to happen. The Java language has become the foundation of the JVM ecosystem. It has to be rock-solid. There's little headroom for experiments. Java often reminds me of an assembler language. You can do everything with it, your programs run fast, but it's not a language to implement things quickly. In our case, Java forces you to create the ArrayList the hard way:

List trafficLights = new ArrayList<>(); trafficLights.add("green"); trafficLights.add("yellow"); trafficLights.add("red");

Luckily, someone found a less verbose way to create an ArrayList:

List trafficLights = new ArrayList() {{ add("green"); add("yellow"); add("red"); }};

Improved readability

That's a lot better. It's reads better, thus adding to the maintainability of the program. For some reason, Lukas Eder disagrees, but that's another day's story. In my personal opinion developers quickly learn there's an inner class with an initializer. A short time later they'll forget it again. Instead they'll recognize the double braces idiom at first glance, much the way they already recognize a getter at first glace. My bet is hardly anyone actually reads the code of a getter. They just recognize the visual pattern and know what it's meant. It might be an interesting experiment to introduce an error in such a getter. How long does it take until the error is detected? You know, it's hard find an error in code you simply don't see.

Update Jan 28, 2015: HashMaps are a better example

Several readers pointed out the most simple way to create an ArrayList is

import static java.util.Arrays.*; List trafficLights = asList("green", "yellow", "red");

Beware: Arrays.asList isn't an ordinary ArrayList (even if the class name of the resulting object is also called ArrayList. More precisely, it's an java.util.Arrays.ArrayList, not an ordinary java.util.ArrayList.). It's immutable, but only partially: you can't add or remove items from the list, but you can replace existing elements by calling the set method.

Another interesting option is Guava's ImmutableList.of(...), as Nerdwaller mentioned on Reddit. This class has another advantage: it's immutable - clearly an interesting trait for traffic lights. It wouldn't do no good to add "blue" to the trafficLights array.

However, my arguments also apply to HashMap, which is a more interesting use case of the double curly braces idiom:

Map trafficLights = new HashMap() {{ put("green", new Go()); put("yellow", new SlowDown()); put("red", new Wait()); }};

So what's wrong with it?

The double brace idiom looks nicely, but there's a catch. Actually, there's more than one.

First, Java can't infer types. You can't use target typing. This version won't work:

List trafficLights = new ArrayList<>() {{ // doesn't compile! add("green"); add("yellow"); add("red"); }};

Second, Eclipse starts to draw yellow squiggles. It complains about the missing serialVersionUID. But that's a minor nuisance.

Lukas Eder also points out that every double braces idiom is an inner class. He considers this a disadvantage because it clutters the file system with lots and lots of class files. I disagree: there's nothing wrong with inner classes. Groovy and Scala use them a lot, and it works fine for them.

Except for one thing. Inner classes tend to cause memory leaks. An inner class contains a pointer to the surrounding class. So when you start to pass the ArrayList around, you also pass the surrounding object around. More precisely, there's another reference to the surrounding object, which brings the garbage collector into trouble. It can't remove the surrounding object from memory as long as there's at least one instance of the ArrayList. The ArrayList itself hasn't got anything to do with the surrounding object, so that's a nasty catch.

Update Jan 28, 2015

This article is currently being discussed on Reddit. As it turns out, the resulting class behaves slightly unexpected, like this snippet shows:

//prints "class Test$1" or similar System.out.println(trafficLights.getClass()); // prints true System.out.println(trafficLights instanceof Map); // prints true System.out.println(trafficLights instanceof HashMap); // prints false System.out.println(trafficLights.getClass().equals(HashMap.class)); // prints true System.out.println(HashMap.class.isAssignableFrom(trafficLights.getClass()));

Wrapping it up

Every once in a while, I used the double braces idiom myself. It looks smart, so what's wrong with it? But sometimes it's not good to be smart. Kudos to Lukas Eder for pointing this out! Now I'd like to point you to his article. The Double Curly Braces Anti Pattern has several details I omitted for brevity. By the way, there's also an interesting article from 2013 by Mohamed Sanaulla covering the topic.

Dig deeper

The Double Curly Braces Anti Pattern by Lukas Eder

Double braces initialization covered by Mohamed Sanaulla

Discussion on Reddit.


Comments