The Third
Map<K, V> m = new HashMap();
This is the worst way to initialize m
. HashMap
here is a raw type, which means it ignores all generic data. It is cast to Map<K, V>
safely, but the usage of the raw type causes a compiler warning anyway. This is for a good reason, as since generic data is being ignored, you can do this:
Map<String, String> m;
Map<Int, Int> m2 = new HashMap(m); // no error
Raw types exist for interoperability with old pre-Java 5 code, where generics didn't exist. All generic types are seen as their erasure. Therefore, the raw HashMap
constructor no longer takes a Map<? extends K, ? extends V>
, it takes a raw Map
. The get
method no longer takes a K
to return a V
, it takes an Object
(erasure of K
) and returns Object
(erasure of V
). This greatly impairs type safety, and the silent conversion of raw types to parameterized types does not help.
Never do it this way.
The First
Map<K, V> m = new HashMap<K, V>();
This is the pre-Java 7 way of initializing a generic type. Since the HashMap
constructor is being passed type parameters, it is much safer than the third way. Generic information is now used to its full extend and everything is type safe. It is leaps and bounds better than the third, but you may as well do it the second way if you can.
The Second
Map<K, V> m = new HashMap<>();
This is the new and best way of initializing a generic type, introduced in Java 7. This is the same as the first way, except since it's a pain to write out the same type parameters on the left and right sides of a declaration, the type parameters may be omitted on the right. The <>
is known as the diamond operator. Use this whenever you can.
TL;DR
The second way if you're on Java 7+, the first if you're not, and the third is too evil to even think about using.