I have been in the software development industry since 2010, working on enterprise product development using ADF. I am usually keen on learning about software design and emerging technologies. You can find me hanging around in the JavaRanch Forums where I am one of the moderators. Apart from Java, I am fascinated by the ease of use and simplicity of Ruby and Rails. Mohamed is a DZone MVB and is not an employee of DZone and has posted 58 posts at DZone. You can read more from them at their website. View Full User Profile

Double Brace Initialization Idiom and its Drawbacks

10.07.2013
| 5172 views |
  • submit to reddit

This post is inspired by the Double Brace Initialization concept explained here. This technique can be used for creating and initializing objects and represent these operations in a single expression. And the efficiency of this technique has been heavily discussed on stackoverflow.

Conventional way to create and populate an object

We all are familiar with creating and populating data in an ArrayList, we generally do something like:

List<String> names2 = new ArrayList<>();
names2.add("Name1");
names2.add("Name2");
names2.add("Name3");
names2.add("Name4");

there’s yet another approach by using Arrays.asList, but this creates an immutable list, so any further add operations results in UnsupportedOperationException. Lets look at that example as well:

List<String> names3 = Arrays.asList("name1","name2", "name3");

//This throws java.lang.UnsupportedOperationException
names3.add("names4");

Using Double brace initialization idiom

So how does Double Brace Initialization help us here? Lets look at an example for that as well:

List<String> names = new ArrayList<String>(){{
  add("Mr. ABC");
  add("Mr. XYZ");
  add("Mrs. PQR");
  add("MNOP");
}};

It gets the name for the double {{ }} present in the expression. In the above example we are doing 2 things:
1. Create an anonymous inner class which extends ArrayList.
2. Provide an instance initialization block which invokes the add method and adds the required elements. Please read this to know more about initialization blocks.

The advantage we have with this approach is that we can combine creation and initialization into an expression and pass around into different methods. Lets look at an example for this:

class MySomeClass {
  protected String someStrProp;
  protected int someIntProp;
  protected boolean someBoolProp;
}

public class DoubleBraceInitialisationDemo {
  public static void main(String[] args) {
    //There are 3 things happening in the code below:
    //1. Extend the class MySomeClass
    //2. Create an instance of the extension
    //1 and 2 correspond to creating Anonymous inner class
    //3. Create a instance initializer to set values for properties.
    someMethod(new MySomeClass() {{
      someBoolProp = true;
      someIntProp = 12;
      someStrProp = "Some String";
    }});
  }
  
  static void someMethod(MySomeClass someObj) {
    System.out.println(someObj.getSomeIntProp());
    System.out.println(someObj.getSomeStrProp());
    System.out.println(someObj.isSomeBoolProp());
  }
}

Though we say that this approach can be used in creating an object and initializing it in a single expression, we have to be aware that we are not creating the object of that class instead we are creating an object of the extension of that class under consideration.

Drawbacks of using Double Brace Initialization approach

Overusing or abusing this idiom can often lead to bloated number of class files generated and this can cause performance issues as noted in the discussion here. This is because this idiom makes use of anonymous inner classes to achieve the required result.

And the other drawback is that this doesn’t support use of “Diamond operator”, a feature introduced in Java 7, while creating instances of generic types. Let me explain this with an example:

//This is using Double brace initialization.
Map<Integer, String> numbers = 
          new HashMap<Integer, String>() {{
  put(1, "One");
  put(2, "Two");
  put(4, "Four");
  put(7, "Seven");
}};
//Diamond operator in Java 7 allows us to:
Map<Integer, String> myMap = new HashMap<>();

//But one cannot use this feature while using Double brace initialization
Map<Integer, String> numbers2 = 
          new HashMap<>() {{
  put(1, "One");
  put(2, "Two");
  put(4, "Four");
  put(7, "Seven");
}};
//The above code gives an error stating: 
//"Cannot use <> with anonymous inner classes"

This Double brace initialization is an idiom that is good to be aware of as it involves use of anonymous inner class and instance initialization blocks. I think this will be a good Java trivia during the interviews.

Published at DZone with permission of Mohamed Sanaulla, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Andreas Haufler replied on Mon, 2013/10/07 - 2:02am

Nice writeup. That's actually the first time I stumbled on this "hidden feature" of Java.

What I also would like to mention is that there is at least one more way of creating a collection in Java. This can be done by using Googles Guava: List<String> list = Lists.newArrayList();

This saves you from repeating the whole type infos even if you cannot use Java 7 and the diamond operator.

Of course there is also a Maps and a Sets class providing static factory methods for all kinds of collections.

regards Andy

Steven Hatfield replied on Mon, 2013/10/14 - 3:23pm

Something cool about the double brace initialization is that you can actually use programming constructs:

List<String> names = new ArrayList<String>() {{
       for ( int i = 0; i < 10 ; i++ ) {
              add("A" + i );
       }
}};

and this becomes even cooler when you realize that you can avoid declaring a variable entirely if you don't need one:

String names = concatStringList( new ArrayList<String>() {{
       for ( int i = 0; i < 10 ; i++ ) {
              add("A" + i );
       }
}});

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.