Java, Generics: What's the difference between Set<?> s = HashSet<String>() and Set s = HashSet<String>()?

generics, java

Solution

No, they are not the same. Here's the basic difference:

Set<?> s = HashSet<String>();
s.add(2);  // This is invalid

Set s = HashSet<String>();
s.add(2);  // This is valid.

The point is, the first one is a unbounded parameterized type `Set`. Compiler will perform the check there, and since you can't add anything but `null` to such types, compiler will give you an error.

While the second one being a raw type, the compiler won't do any check while adding anything to it. Basically, you lose the type safety here.

And you can see the result of loosing type safety there. Adding `2` to the set will fail at compile time for `Set<?>`, but for a raw type `Set`, it will be successfully added, but it might throw exception at runtime, when you get the element from the set, and assign it to say `String`.

Differences apart, you should avoid using raw types in newer code. You would rarely find any places where you would use it. Few places where you use raw type is to access `static` fields of that type, or getting `Class` object for that type - you can do `Set.class`, but not `Set<?>.class`.

Problem

I was reading about unknown types and raw types in generics, and this question came to mind. In other words, is... ``` Set<?> s = new HashSet<String>(); ``` and ``` Set s = new HashSet<String>(); ``` ... one and the same? I tried it out, and they both seem to accomplish the same thing, but I would like to know if they are any different to the compiler.

Original source

Related problems