Efficiency of Java “Double Brace Initialization”?

前端 未结 15 2124
清歌不尽
清歌不尽 2020-11-21 15:35

In Hidden Features of Java the top answer mentions Double Brace Initialization, with a very enticing syntax:

Set flavors = new HashSet         


        
15条回答
  •  感动是毒
    2020-11-21 16:24

    Every time someone uses double brace initialisation, a kitten gets killed.

    Apart from the syntax being rather unusual and not really idiomatic (taste is debatable, of course), you are unnecessarily creating two significant problems in your application, which I've just recently blogged about in more detail here.

    1. You're creating way too many anonymous classes

    Each time you use double brace initialisation a new class is made. E.g. this example:

    Map source = new HashMap(){{
        put("firstName", "John");
        put("lastName", "Smith");
        put("organizations", new HashMap(){{
            put("0", new HashMap(){{
                put("id", "1234");
            }});
            put("abc", new HashMap(){{
                put("id", "5678");
            }});
        }});
    }};
    

    ... will produce these classes:

    Test$1$1$1.class
    Test$1$1$2.class
    Test$1$1.class
    Test$1.class
    Test.class
    

    That's quite a bit of overhead for your classloader - for nothing! Of course it won't take much initialisation time if you do it once. But if you do this 20'000 times throughout your enterprise application... all that heap memory just for a bit of "syntax sugar"?

    2. You're potentially creating a memory leak!

    If you take the above code and return that map from a method, callers of that method might be unsuspectingly holding on to very heavy resources that cannot be garbage collected. Consider the following example:

    public class ReallyHeavyObject {
    
        // Just to illustrate...
        private int[] tonsOfValues;
        private Resource[] tonsOfResources;
    
        // This method almost does nothing
        public Map quickHarmlessMethod() {
            Map source = new HashMap(){{
                put("firstName", "John");
                put("lastName", "Smith");
                put("organizations", new HashMap(){{
                    put("0", new HashMap(){{
                        put("id", "1234");
                    }});
                    put("abc", new HashMap(){{
                        put("id", "5678");
                    }});
                }});
            }};
    
            return source;
        }
    }
    

    The returned Map will now contain a reference to the enclosing instance of ReallyHeavyObject. You probably don't want to risk that:

    Memory Leak Right Here

    Image from http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/

    3. You can pretend that Java has map literals

    To answer your actual question, people have been using this syntax to pretend that Java has something like map literals, similar to the existing array literals:

    String[] array = { "John", "Doe" };
    Map map = new HashMap() {{ put("John", "Doe"); }};
    

    Some people may find this syntactically stimulating.

提交回复
热议问题