Sunday, September 18, 2016

Don’t use Double Brace Initialization – double curly braces Anti pattern


·      -   Double brace initializer is nothing but it is instance initializer inside a inner class.
·      =  Double Brace Initialization looks convenient for variable initialization for collections (map,List,set..). This feel good, because we can declare and initialize collections at the same time.
·        This means we can declare and initialize at the same time using instance initializer.
E.g we a list and we want to add some elements to this like "A","B","C". What we will do.
List<String> list = new ArrayList<String>(); 
list.add("A"); 
list.add("B"); 
list.add("C"); 
Also we can initialize as below. But this is a unmodifiable list, if we try to modify this list, it will give java.lang.UnsupportedOperationException

List<String> listOfLetters1 = Arrays.asList("A", "B", "C"); 
                         
Initialize using Double braces:
List<String> list = new ArrayList<String>()
{
{
add("A"); 
add("B"); 
add("C"); 
}
};
It’s look pretty and simple,  we can do initialization in one line.


What is Double Brace Initialization?
·        Double brace initializer is nothing but it is instance initializer inside a inner class.

instance initializers to instantiate collections
instantiating and initializing collections without having to manually populate the list.
Declaration and initialization in one line.
This is not a special {{ symbol but two { given different meanings. The first { shows this is an anonymous class, the second { means the start of an initializer block.
How the compiler will consider this? or why it is saying avoid this ? or why it is calling as anti pattern ?
·        Creating anonymous class while compilation – that decrease the performance.

Double brace initializer is just a initializer inside (inner braces) anonymous inner class(outer braces).
The outer ‘{ ‘ represent anonymous  inner class
So every time when we are creating a map or any collection using double brace initializer means your creating an anonymous inner class.

At run time compiler will generate *.class file for each anonymous inner class and that will loaded and invoked by class loader at runtime.
e.g>
public class test  {
public test {

List<String> list = new ArrayList<String>() {{
add("A"); 
add("B"); 
add("C"); 
}};
}
public static void main(String[] args) {
        new test();
    }
}

For the above example after compilation this will be having test.class, test$1.class
i.e for every anonymous inner class a ‘.class’ file will be gnereating.

So at the run time class loader will invoke this, this will reduce overall performance of your application.

·        Inner classes Keeping a ‘this’ reference to the outer classes- creating memory leak
For non-static anonymous inner classes that will always keep reference to their enclosing instance. .i.e the inner class always have ‘this’ reference (this$0) to the outer class. This will lead to memory leak- since this is preventing GC from freeing up the occupied memory.
That is to, serialize the collection you have to serialize the entire enclosing class.
·        Doesn’t support empty  diamond operator (<>)
From Java 7 onwards, we will be to declare variables using <>,
List<String> list = new ArrayList< >(); 
But double brace intializrer is not supporting this.
List<String> list = new ArrayList< >()
{
{
add("A"); 
add("B"); 
add("C"); 
}
};
The above code will throw compilation error.
Because of the above all disadvantages, we are not using double brace initializer nowadays, so this become an antipattern.
Where to use:  Used only for testing, demos and debugging.
In Java 8 we have  Stream API and Collectors available for initialization of collections.
List<String> list = Collections.unmodifiableList(Stream.of(("A", "B", "C").collect(toList()));
But the streams collectors make no guarantees about the mutability of collections they return

No comments:

Post a Comment