Hacker News new | past | comments | ask | show | jobs | submit login
Java Hack: Double Brace Initialization (refactory.org)
37 points by smokestack on July 16, 2009 | hide | past | favorite | 19 comments



Watch out - double-brace initialization is cool looking, but it's orders of magnitude slower than regular initialization as it must generate an anonymous class.

Also, the generated class is put into the permgen space, which is not garbage collected. The permgen is pretty small by default - and if you fill it up, your system is hosed.

I use them all the time in unit tests, but never in production code.


The compiler generates the anonymous class. To the runtime, isn't it just a class with a name given to it by the compiler, not a developer (question mark...my key broke today)

It's true that it uses up permgen though, but if it only adds an initializer we're not talking about much space.

Edit:

I did an experiment. This is the code:

     new ArrayList<Object>() {
       {}
     };
     new ArrayList<Object>();
Here is the bytecode:

     0  new Main$1 [16]
     3  invokespecial Main$1() [18]
     6  new java.util.ArrayList [19]
     9  invokespecial java.util.ArrayList() [21]
And, the class:

    class Main$1 extends java.util.ArrayList {

    // Method descriptor #6 ()V
    // Stack: 1, Locals: 1
    Main$1();
      0  aload_0 [this]
      1  invokespecial java.util.ArrayList() [8]
      4  return
    Line numbers:
      [pc: 0, line: 10]
      [pc: 4, line: 1]
    Local variable table:
      [pc: 0, pc: 5] local: this index: 0 type: new Main(){}
Just a regular old subclass.


You can always copy and paste a question mark (?). I don't recommend coding that way, I once tried coding with the left quarter of the keyboard broken, not fun.


alt + keypad 63 works too (at least on Windows)


Interesting. Even in Perl we cache and garbage-collect anon classes.

(The caching is for the very common case of creating a subclass with optional roles applied:

    my $class = Some::Meta::Class->create_anon_class(
        superclasses => ['Foo'],
        roles        => [qw/Commonly Applied Traits/],
    );
There is almost no speed hit the second time you create an instance of "Foo" with "Commonly", "Applied", and "Traits" applied. Not sure this would be useful for Java, although we can achieve the same effect as in the article.)


perl has a more stable vm than java :)

I like this trick though, it will help me with my seaside clone in java :)


FWIW, this is all done in "user space". The metaclass instance is attached to every instance that it creates. When all the instances go away, there are no more references to the metaclass, and it gets reclaimed. The destructor handles deleting the symbol table entries that were added, and that's that.

There is something to be said for not baking things into the language.


This is one case where I really prefer C#'s approach; it supports a shortcut syntax (works on anything which implements IEnumerable and has a public Add method):

  List<int> intList = new List<int>() { 1, 2, 3 };
which involves no anonymous classes or anything of the sort. The compiler merely "expands" it into the following before producing the bytecode:

  List<int> intList = new List<int>();
  intList.Add(1);
  intList.Add(2);
  intList.Add(3);
Which is, really, about what I'd expect such a shortcut syntax to do.


I think just generally you have to be aware that it is not a concrete ArrayList (or whatever) that is being created. You have to be careful about which classes you are anonymously subclassing. If the superclass has an equals method, for instance, that follows the getClass().equals(compare.getClass()) approach as part of its logic you are screwed.


And it can break equals() if you're not careful.


Seems wasteful, just to save a few keystrokes.


It's pretty useful in unit tests, since it very clearly lays out the sample data you'll be comparing. I rarely if ever used it in the production code.


For initializing lists there is a less verbose expression in Java:

  List<Integer> list = Arrays.asList(1,2,3,4,5);


. . . except that doesn't get you a modifiable list, it just wraps a List interface around the array that's implicitly created by the var-arg, so it's a trick you have to be careful with.

Personally I often end up writing little helpers like: List<T> list(T... args) { return new ArrayList<T>(Arrays.asList(args)) } usually in test code. A built-in List and Map-initialization syntax is really something every decent programming language ought to have.


(Consider using the Google collections library if possible. It already has that in the form of classes like Lists, Maps, etc that provide builders and factory methods.)


Nice. Could have used that thought about 9 years ago :)


I've been using this for years. It is a fantastic way to build up hierarchies. XML, maps, JSON, UI code etc. It is very concise, fast and produces clean code which also just happens to correctly indent when you apply code formatting.

  School s = new School() {{
    add(new Student() {{
      name = "Bobby";
      age = 15;
      add(new Pet() {{
        name = "Fluffy";
      }});
    }});
  }};

  vs.
  School sc = new School();
  Student st = new Student();
  st.name = "Bobby";
  st.age = 15;
  Pet p = new Pet();
  p.name = "Fluffy";
  st.add(p);
  sc.add(st);


This is where Google Collections comes in handy:

    Lists.newArrayList(1, 2, 3)
Or, if you don't need to modify it:

    ImmutableList.of(1, 2, 3)
Such an awesome library.


One thing though. I love this technique but the home built Eclipse compiler is not fully Java language compliant and it will reject certain forms of this as invalid. Specifically, the sun and eclipse compiler treat "this" differently in these code blocks. My project will not compile under eclipse because of certain usages of this pattern when combined with inner classes. The bug crops up when you need to pass the parent to the child object being initialized in the static block.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: