views:

385

answers:

4

This is a question about Java code such as:

List<String> list = new ArrayList<String>() {{add("hello"); add("goodbye");}}

where the programmer has extended ArrayList anonymously just for the sake of shoving in an instance initialization block.

The question is: if the sole intention of the programmer is merely to achieve the same as:

List<String> list = new ArrayList<String>();
list.add("hello");
list.add("goodbye");

then what are the unintended consequences of doing it the first way?

+11  A: 

The danger of doing that sort of code (in the general case) is that you might break equals() methods. That's because there are two general templates for equals():

public boolean equals(Object ob) {
  if (!(ob instanceof MyClass)) return false;
  ...
}

and

public boolean equals(Object ob) {
  if (ob.getClass() != getClass()) return false;
  ...
}

The first will still work with the anonymous subclasses you're talking about but the second won't. Thing is, the second is considered best practice because instanceof isn't necessarily commutative (meaning a.equals(b) might not equal b.equals(a)).

Specifically in this case however ArrayList uses the AbstractList.equals() method which merely checks that the other object is an instanceof the interface List, so you're fine.

It is something to be aware of however.

What I would suggest is to do it slightly differently:

List<String> list = new ArrayList<String>(
    Arrays.asList("hello", "goodbye")
);

Sure it's more wordy but you're less likely to get in trouble this way as the resultant class is a "pure" ArrayList.

cletus
Great answer, well put.
mafutrct
A: 

The first approach is also bad for performance. Cluttering memory with lots of anonymous classes isn't good. Also it will be slower at startup.

HappyCoder
I have to disagree with this. The first and second cases will perform exactly the same. However, the first case is bad because of what cletus explained very well.
LordOfThePigs
A split millisecond of start up performance and around 2K persistent heap (per use).
Tom Hawtin - tackline
+4  A: 

I think the big issue here is that you're creating an inner class of the surrounding class. The list you create will have an implicit this reference to the outer class.

This isn't normally a problem. However, if you serialise this object (I'm thinking particularly of using XStream since I've run into this myself) then the serialised form will contain the serialised outer class. Which isn't at all what you'd normally expect and can result in peculiar behaviour!

I use the above initialisation pattern a lot. So long as you're aware of the inner class mechanism then it's not a problem. bTW. I don't think the equality issue is an issue beyond that of equality implementations on derivations in general.

Brian Agnew
+1 That's an excellent point about the implicit this reference.
cletus
Usually you do this from a static context, or you don't care (in a test, say). If it does matter surrounding with, say, new ArrayList<.>() will do the trick. Using Arrays.asList could reduce memory overhead.
Tom Hawtin - tackline
+2  A: 

The impact on code performance and/or memory is negligible (if even measurable).

The real hit here is that you are making people stop, even for a beat, to think "what's this guy doing?"

If I have to do that 1,000 times while I read your code, THERE is the performance problem.

Code should be easy to read - so long as all performance, completeness, and standards requirements are met.

Most likely you are going to be the person maintaining your code. Be nice to your future self, and make the code as EASY TO READ as possible. If you're going to do some fancy schmancy stuff like that, have a good reason and document it in code. If the only reason is to show off your chops as a programmer, you have failed in the real job of a programmer: to make the difficult easy.

Michael
You have to think first time you see the idiom - then it's done. Much easier to read this code, IMO.
Tom Hawtin - tackline
@Tom You are dead wrong. The second way is standard, so better use that. The first way is DailyWTF material.
starblue