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:
Luckily, someone found a less verbose way to create an ArrayList:
ListImproved 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
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:
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:
ListSecond, 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