Undefined constructor error in a double bracket collection initializer

In the following code the getEntriesNotWorking method reports a compile-time error:

public class DoubleBracketInitializerTest {

    class Container {}

    class Entry {
        Container container;
        public Entry(Container container) {
            this.container = container;
        }
    }

    class DetailedContainer extends Container {

        List<Entry> getEntriesNotWorking() {
            return new ArrayList<Entry>() {{
                add(new Entry(this)); // compile-time error mentioned below
            }};
        }

        List<Entry> getEntriesWorking() {
            return Arrays.asList(new Entry(this));
        }

    }

}

Error:

The constructor DoubleBracketInitializerTest.Entry(new ArrayList(){}) is undefined

While the getEntriesWorking() method is compiling correctly. The constructor is clearly there since a DetailedContailer is a subclass of Contailer.

What is the difference between those two methods, that makes the code invalid? How can I make the double bracket initializer work for this class hierarchy?

Jon Skeet
people
quotationmark

The problem is that within new ArrayList<Entry>() { ... }, this is an ArrayList<Entry>. The clue is in the error message, which specifies which constructor signature it's looking for.

If you really want to use this sort of initialization, you want:

add(new Entry(DetailedContainer.this));

... to refer to the enclosing instance of DetailedContainer.

I'd also strongly advise you to avoid inner classes unless you really need them. Life is a lot simpler when you only have top level classes, or nested static classes if you really need them.

I'd also avoid this sort of anonymous ArrayList subclass construction - it's a lot more trouble than it's worth, IMO, compared with just creating the array list and adding the item. Or use Guava, with:

return Lists.newArrayList(new Entry(this));

Simpler all round!

people

See more on this question at Stackoverflow