JDK-6231312 : (coll) Map.entrySet() return type needs to be made more generic
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 5.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Won't Fix
  • OS: linux
  • CPU: x86
  • Submitted: 2005-02-21
  • Updated: 2014-07-22
  • Resolved: 2014-07-22
Related Reports
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
The current signature for Map<K, V>.entrySet() is as follows:

Set<Map.Entry<K, V>> entrySet();

I propose that the signature should be:

Set<? extends Map.Entry<K, V>> entrySet();

JUSTIFICATION :
  From a theoretical standpoint, the signature as it is is overspecified. An implementation of Map<K, V> may wish to define its own, more specific Entry classes, and there is no theoretical reason to prevent them from doing so.

For an example of theory meeting practice, I have an ordered map implementaiton which defines a Map.Entry implementation that, in addition to returning the name/value of the entry, also returns the ordinand of the entry:

interface IndexedMap<K, V> extends Map<K, V>
{
  interface Entry<K, V> extends Map.Entry<K, V>
  {
    public int getIndex();
  }

  public Set<? extends Entry<K, V>> entrySet();
}

Ideally, I would like to be able to narrow the return type of entrySet() as shown in the above excerpt, so that classes using the IndexedMap.entrySet() method do not have to cast to get access to the index of the entries:

IndexedMap map;

...

for (IndexedMap.Entry<?, ?> entry : map.entrySet())
  System.out.println(entry.getIndex());

However, the return type defined in Map.entrySet() does not permit this override, so the above needs to be done as follows:

IndexedMap.Entry iEntry;

for (Map.Entry<?, ?> entry : map.entrySet())
{
  // Will generate an "unchecked cast" warning
  iEntry = (IndexedMap.Entry<?, ?>)entry;
  System.out.println(iEntry.getIndex());
}

Many RFEs for collections interfaces never see the light of day because of the need to maintain compatibility with the existing codebase. However, this one is 99% backwards compatible with existing code. Any subinterface or class implementation that has the old return type Set<Map.Entry<K, V>> will still compile and run just as it did before. The only side-effect that I can think of is that if anyone is calling entrySet().add(), then that will generate a compile-time if accessed through a Map reference. This is actually a good thing, I think, because the specification of the entrySet() method is such that one should not usually be calling the "add()" method on the set it returns. Thus, backwards compatibility should not be a reason to discard this particular RFE.

(As an aside: the example I have provided is actually an in-house implementation of the "ordered map" concept - please see RFE 5048530 at http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5048530)

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The supplied test code should compile without error.

ACTUAL -
Code fails to compile because the Map.entrySet() method's return type is not assignment compatible with the return type of IndexedMap.entrySet(). Error message:

MapTest.java:11: entrySet() in IndexedMap clashes with entrySet() in java.util.Map; attempting to use incompatible return type
found   : java.util.Set<? extends IndexedMap.Entry<K,V>>
required: java.util.Set<java.util.Map.Entry<K,V>>
  public Set<? extends Entry<K, V>> entrySet();


---------- BEGIN SOURCE ----------

import java.util.*;

interface IndexedMap<K, V> extends Map<K, V>
{
  interface Entry<K, V> extends Map.Entry<K, V>
  {
    public int getIndex();
  }

  public Set<? extends Entry<K, V>> entrySet();
}

class Test
{
  public void printIndices(IndexedMap<?, ?> map)
  {
    for (IndexedMap.Entry<?, ?> entry : map.entrySet())
      System.out.println(entry.getIndex());
  }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Implement the interface with the specified return type of Set<Map.Entry<K, V>> and use a cast to convert its elements to IndexedMap.Entry.
###@###.### 2005-2-21 09:47:38 GMT

Comments
This would be an incompatible change and of limited value in any event.
22-07-2014