dpr
dpr

Reputation: 10964

Why is Collection not simply treated as Collection<?>

Consider the following API method taken from Shiro's org.apache.shiro.subject.PrincipalCollection interface but probably present in other libraries as well:

Collection fromRealm(String realmName);

Yes even nowadays there are still libraries that are using raw-types, probably to preserve pre Java 1.5 compatibility?!

If I now want to use this method together with streams or optionals like this:

principals.fromRealm(realmName).stream().collect(Collectors.toSet());

I get a warning about unchecked conversion and using raw types and that I should prefer using parameterized types.

Eclipse:

Type safety: The method collect(Collector) belongs to the raw type Stream. References to generic type Stream<T> should be parameterized

javac:

Note: GenericsTest.java uses unchecked or unsafe operations.

As I can't change the API method's signature to get rid of this warning I can either annotate with @SuppressWarnings("unchecked") or simply cast to Collection<?> like this:

((Collection<?>) principals.fromRealm(realmName)).stream().collect(Collectors.toSet());

As this cast of course always works I'm wondering why the compilers are not simply treating Collection as Collection<?> but warn about this situation. Adding the annotation or the cast doesn't improve the code a single bit, but decreases readability or might even shadow actual valid warnings about usage of unparameterized types.

Upvotes: 42

Views: 4438

Answers (4)

bvdb
bvdb

Reputation: 24710

A Collection<?> screams:

Please don't add anything to me. I have a strict content type, ... well uh, I just forgot what type it is.

While a Collection says:

It's all cool ! You can add whatever you like, I have no restrictions.

So, why shouldn't the compiler translate Collection to Collection<?> ? Because it would put up a lot of restrictions.

Upvotes: 8

Lino
Lino

Reputation: 19926

The reason is quite simple:

You may read Objects from a Collection<?> the same way as from Collection. But you can't add Objects to a Collection<?> (The compiler forbids this) whereas to a Collection you can.

If after the release of Java 5 the compiler had translated every Collection to Collection<?>, then previously written code would not compile anymore and thus would destroy the backward compatibility.

Upvotes: 72

Ondra K.
Ondra K.

Reputation: 3077

The major difference between raw type and unbounded wildcard <?> is that the latter is type safe, that is, on a compile level, it checks whether the items in the collection are of the same type. Compiler won't allow you to add string and integer to the collection of wildcard type, but it will allow you to do this:

List raw = new ArrayList();
raw.add("");
raw.add(1);

Actually, in case of unbounded wildcard collections (List<?> wildcard = new ArrayList<String>()), you can't add anything at all to the list but null (from Oracle docs):

Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.

Upvotes: 21

Ashishkumar Singh
Ashishkumar Singh

Reputation: 3600

A use-case that I can think of as to why Collection is not considered as Collection<?> is let say we have a instance of ArrayList

Now if the instance is of type ArrayList<Integer> or ArrayList<Double> or ArrayList<String>, you can add that type only(type checking). ArrayList<?> is not equivalent to ArrayList<Object>.

But with only ArrayList, you can add object of any type. This may be one of the reason why compiler is not considering ArrayList as ArrayList<?> (type checking).

One more reason could be backward compatibility with Java version that didn't have generics.

Upvotes: 3

Related Questions