I have found something interesting to happen with Maps, rawtypes and generics. Following code:
static {
Map map = new HashMap ();
Set <Map.Entry> set = map.entrySet ();
for (Map.Entry entry : set) {} // fine
for (Map.Entry entry : map.entrySet()) {} // compilation error
}
I am getting a compilation error about a Type incompatibility, namely: "Object cannot be cast to Entry".
Ideone for convenience
Why is the iterator over entrySet()
losing the type information if there's no variable storing it again?
The rawtypes shouldn't affect the type so that Map.Entry
suddenly is an Object. Or am I mistaken?
Your example makes it look like you have type information that you never had. You have written:
Map map = new HashMap ();
Set <Map.Entry> set = map.entrySet();
for (Map.Entry entry : set) {} // fine
for (Map.Entry entry : map.entrySet()) {} // compilation error
But map.entrySet()
is returning Set
, not Set <Map.Entry>
. You've performed an unchecked assignment which "adds" type information.
In the second for loop, we don't know what's inside the Set
, so we can't iterate over Set <Map.Entry>
without an explicit cast.
For example, compare the original example to this one where we don't "add" type information with the unchecked assignment.
Map map = new HashMap();
Set set = map.entrySet();
for (Map.Entry entry : set) {
} // Object cannot be cast to Entry
for (Map.Entry entry : map.entrySet()) {
} // Object cannot be cast to Entry
In this case, both for loops produce a compilation error.
This behaviour is documented in the Java Language Specification, section 4.8:
The type of a constructor (§8.8), instance method (§8.8, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic declaration corresponding to C. The type of a static member of a raw type C is the same as its type in the generic declaration corresponding to C.
I think the short answer is that Java allows "unchecked cast" in some situations but not others. Dealing with raw types (Generic types without a specified type) is one of these instances.
Keep in mind that for (Map.Entry entry : set)
is equivalent to:
Iterator it = set.iterator();
while (it.hasNext())
{
Map.Entry entry = it.next();
}
The assignment:
Set set = map.entrySet();
is allowed and will not generate any warning, as you are not introducing any new type, but in the for
loop it.next()
will return type Object
and you will get compiler exception if you assign it without an explicit cast.
The assignment:
Set <Map.Entry> set = map.entrySet();
is allowed but will generate an "unchecked cast" warning because of the explicit type Map.Entry
and in the for
loop it.next()
will return type Map.Entry
and the assignment will work fine.
You can put the explicit cast in the for loop like this:
for(Map.Entry entry : (Set<Map.Entry>) map.entrySet())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With