[ACCEPTED]-Understanding this warning: The serializable class does not declare a static final serialVersionUID-instance-initializers

Accepted answer
Score: 30

The syntax you're using is called double-brace initialization - which 43 is actually an "instance initialization block that is part of an 42 anonymous inner class" (certainly not a hack). So, when 41 using this notation, you are actually defining 40 a new class(!).

The "problem" in 39 your case is that HashMap implements Serializable. This interface 38 doesn't have any methods and serves only to identify the semantics of being serializable. In other 37 words, it's a marker interface and you concretely 36 don't have to implement anything. But, during 35 deserialization, Java uses a version number 34 called a serialVersionUID to verify that the serialized 33 version is compatible with the target. If 32 you don't provide this serialVersionUID, it will be calculated. And, as 31 documented in the javadoc of Serializable, the calculated 30 value is extremely sensitive and it is thus 29 recommended be explicitly declare it to 28 avoid any deserialization problems. And 27 this is what Eclipse is "complaining" about 26 (note that this is just a warning).

So, to 25 avoid this warning, you could add a serialVersionUID to 24 your annonymous inner class:

someMethodThatTakesAHashMap(new HashMap<String, String>() {
    private static final long serialVersionUID = -1113582265865921787L;

        put("a", "value-a");
        put("c", "value-c");

But you loose 23 the conciseness of the syntax (and you may 22 not even need it).

Another option would thus 21 be to ignore the warning by adding a @SuppressWarnings("serial") to 20 the method where you are calling someMethodThatTakesAHashMap(Map). This 19 seems more appropriate in your case.

That 18 all being said, while this syntax is concise, it 17 has some drawbacks. First, if you hold a 16 reference on the object initialized using 15 a double-brace initialization, you implicitly 14 hold a reference to the outer object which 13 won't be eligible for garbage collection. So 12 be careful. Second (this sounds like micro 11 optimization though), double-brace initialization 10 has a very a little bit of overhead. Third, this technique actually uses 9 anonymous inner classes as we saw and thus 8 eats a bit of permgen space (but I doubt 7 that this is really a problem unless you 6 really abuse them). Finally - and this is maybe 5 the most important point - I am not sure 4 it makes the code more readable (it's not 3 a well known syntax).

So, while I like to 2 use it in tests (for the conciseness), I 1 tend to avoid using it in "regular" code.

Score: 6

Yes, you could suppress the warning, but 2 I'd rewrite it like this:

HashMap<String, String> map  = new HashMap<String, String>();

No suppressing 1 needed, and much better to read, IMO.

Score: 0

I generally agree with Bart K., but for 10 informational purposes:
The warning can 9 also be eliminated by adding the field, which 8 can be automatically generated by hitting 7 ctrl+1.
The warning can also be suppressed 6 by adding the @SuppressWarnings("serial") annotation 5 before the definition.
The anonymous class 4 implements Serializeable, and Serializeable 3 requires this static field so that versions 2 can be distinguished when serializing and 1 de-serializing. More information here:

Score: 0

The ImmutableMap class from the Google Collections library 1 is useful for this situation. e.g.

someMethodThatTakesAHashMap(ImmutableMap.<K, V>builder().put("a","value-a").put("c","value-c").build());


Score: 0

To address the other half of your question, "should 16 I suppress it?" --

Yes. In my opinion, this 15 is a terrible warning. serialVersionUID 14 should by default not be used, not the other 13 way around.

If you don't add serialVersionUID, the 12 worst thing that happens is that two versions 11 of an object that are actually serialization-compatible 10 are deemed incompatible. serialVersionUID 9 is a way to declare that the serialization 8 compatibility has not changed, overriding 7 Java's default assessment.

Using serialVersionUID, the 6 worst thing that happens is that you inadvertently 5 fail to update the ID when the class's serialized 4 form changes in an incompatible way. At 3 best, you also get a runtime error. At worst, something 2 worse happens. And imagine how easy it is 1 to fail to update it.

Score: 0

Your intent was to initialize an anonymous 27 instance of HashMap. The warning is clue 26 that your code is doing more than you intended.

What 25 we're looking for is a way to initialize 24 an anonymous HashMap instance. What we have 23 above creates an anonymous subclass of HashMap 22 then creates an anonymous instance of that 21 anonymous class.

Because the code does more 20 than was intended, I'd call it a hack.

What 19 we really want is something like this:

foo(new HashMap<String, String>({"a", "value-a"}, {"c", "value-c"}));

But 18 alas this isn't valid Java. There isn't 17 a way to do anything this in a type-safe 16 way using an array of key/value pairs. Java 15 simple doesn't have the expressive power.

The 14 Google Collection's ImmutableMap.of static 13 methods are close but it means creating 12 a version of the factory method for various 11 numbers of key/value pairs. (See finnw's 10 answer.)

So keep things simple. Go with Bart 9 K's solution unless your code is littered 8 with this initialization. If so use ImmutableMap. Or 7 roll your own HashMap subclass with the 6 "of" style factory methods. Or create these 5 "of" style factory methods in a utility 4 class. Here's one for two key/value pairs:

public final MapUtil {
    public static <K,V> Map<K,V> makeMap(K k1, V v1, K k2, V v2) {
        Map<K,V> m = new HashMap<K,V>();
        m.put(k1, v1);
        m.put(k2, v2);
        return m;

Embrace 3 the verbosity and take solace in the knowledge 2 your corporate co-workers are wearing the 1 same shackles as you.

More Related questions