What is Double Brace Initialization in Java? Anti Pattern Example

Double brace initialization is a Java idiom to initialize a Collection like a list, set and map at the time of declaration. At times, you need a list of fixed elements e.g. supported products, supported currencies or some other config, and on the spot initialization reduces line of code and improves readability. Double brace initialization idiom becomes popular because there is no standard way to create and initialize Collection at the same time in Java. Unfortunately, unlike another language, Java doesn't support collection literals yet. Due to this limitation, creating an unmodifiable List with small numbers of elements requires many lines of code involving creating list, repeatedly calling add() method to add those elements and then finally wrapping it into unmodifiable list as shown below :

List<Integer> list = new ArrayList<>();
list.add(2);
list.add(3);
list.add(5);
list.add(7);        
List<Integer> unmodifiableList = Collections.unmodifiableList(list);

This is quite verbose, and because it cannot be expressed in a single expression, static lists must be populated in static initializer blocks rather than via a more convenient field initializer.

Double brace initialization idiom can do this in just one line as shown below:
List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>() {{
        add(2);
        add(3);
        add(5);
}});


You can also initialize HashMap with values using double brace initialization as following:
Map<Integer, String> intToString = new HashMap<Integer, String>(){{
         put(1, "one");
         put(2, "two");
         put(3, "three");         
 }};

This looks pretty, but it has its own set of disadvantages, which made it an anti-pattern, we'll see them in next section.



Pros and Cons of Double Brace Initialization in Java

Double brace Initialization idiom internally it uses the instance initializer construct in an anonymous inner class. Which means it quite obscure, and it costs an extra class every time you use it. It also holds a hidden reference to the enclosing instance, which may cause memory leaks. You cannot use diamond operator there as well because it's not allowed to infer types in the anonymous class.

Pros:
1) Less line of code
2) Creation and Initialization in the same expression

Cons:
2) Obscure, internally uses the instance initializer construct of the anonymous class.
2) It cost an extra class every time you use it
3) It holds a hidden reference to the enclosing instance, which may cause memory leaks.

Due to its disadvantage and better alternative double brace initialization is now considered as an anti-pattern in Java world.

Double Brace Initialization, Alternative and Antipattern example


Alternatives of Double Brace Initialization Idiom in Java

The Good thing is that you have better alternatives to achieve the same result in Java e.g. you can create and initialize an ArrayList with values in one line by using Copy constructor from Collection class, as shown below :

List<Integer> list = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(2, 3, 5)));

Arrays.asList() returns a fixed length list, which is passed to ArrayList copy constructor. Remember, there is difference between fixed length list returned from Arrays.asList() and the one returned from Collections.unmodifiableList(). You cannot add or remove elements from the ArayList, but you can change the value at any index using set() in the case of former but not with the list returned by Collections.unmodifiableList() method.

This is the best method if you want a small list, but it becomes obscure and less obvious if you need Set or other Collection, since one has to create a List before creating the Set, but it's still better than double brace initialization because it doesn't create anonymous inner classes every time you use it. See Core Java for Impatient for more details.




There is one more alternative of double brace initialization available, only if you are running in Java 8. The JDK 8 Stream API can be used to construct small collections, by combining stream factory methods and collectors, as shown below:

List<String> list = Collections.unmodifiableList(Stream.of("abc", "bcd", "cde").collect(toList()));

If you want  a Set, you can use Collectors.toSet() method instead of Collectors.toList(), as seen in following example :

Set<String> set = Collections.unmodifiableSet(Stream.of("abc", "bcd", "cde").collect(toSet()));

By the way, The streams collectors make no guarantees about the mutability of collections they return. In Java 8, the returned collections are ordinary, mutable collections such as ArrayList, HashSet, and HashMap, but this might change in future JDK releases.


That's all about Double brace initialization idiom in Java. It's ok for one of the uses, mostly for testing and demo, but it's not good enough to be used in production code. Due to its cons, Double brace initialization has become an antipattern nowadays, especially with more suitable alternatives available. I still use double brace initialization for initializing static maps, but that's it. For List and Set, I prefer the combination of Arrays.asList() and copy constructor of Collection class. If I am running Java 8 then I use Stream API and Collectors to do the job.


Related Java Articles
If you like this tutorial and wants to learn more about patterns, principles and best practices in Java programming language, you may want to see following articles as well:
  • 10 Object Oriented design Principle Every OOP developer should know (article)
  • Why is static code analysis important for Java application? (article)
  • 10 Best Practices to follow while naming variables, class and methods in Java? (article)
  • Must know multi-threading and concurrency best practices for Java Programmers (article)
  • Why you should not call System.exit() on Java Web Application? (answer)
  • Why use SLF4j over Log4j for logging in Java? (answer)
  • 10 Articles Every Programmer must Read. (list)
  • Why should you favor Composition over Inheritance in Java? (answer)
  • Some Practical tips to avoid NullPointerException in Java? (answer)
  • Why getter and setter are better than public fields in Java? (answer)
  • Why use @Override annotation in Java? (tip)
  • How to write thread-safe code in Java? (tip)
  • 10 best practices to follow while commenting code (article)


Further Reading
If you want to learn more about the patterns and best practices then you must read the Effective Java, there is no other book which can take its place. If you relatively less experienced in Java and looking to learn design patterns with some fun and lightweight reading, then you should read Head First Design Pattern 2nd Edition.

1 comment :

Decantação said...

you can use double brace init with objects as well, MyObj myObj = new MyObj() {{ setFoo(foo) }};

Post a Comment