Asking about the interesting behaviours of TreeMap.putAll

Charles Lee littlee at linux.vnet.ibm.com
Fri Mar 2 08:17:21 UTC 2012


Hi guys,

I have a small test case[1] and the two invokes of putAll have different 
behaviors: the first invocation does not use the override put but the 
second invocation does.
The root cause about this can be find in the TreeMap code:

/if (size==0 && mapSize!=0 && map instanceof SortedMap) {
             Comparator c = ((SortedMap)map).comparator();
             if (c == comparator || (c != null && c.equals(comparator))) {
                 ++modCount;
                 try {
                     buildFromSorted(mapSize, map.entrySet().iterator(),
                                     null, null);
                 } catch (java.io.IOException cannotHappen) {
                 } catch (ClassNotFoundException cannotHappen) {
                 }
                 return;
             }
         }/

When meet some situations, buildFromSorted will be invoked instead of 
put. I understand it is a speed up, but it may confuse people: "I need 
my own put because of something, but interestingly sometimes it will not 
be called when putAll and I do not find the reason from the api spec."

 From the api spec of TreeMap's putAll, it says nothing about put. But 
from the api spec of AbstractMap's putAll and Map's putAll, they said:
/    "The effect of this call is equivalent to that of calling put(k, v) 
on this map once for each mapping from key k to value v in the specified 
map. "
/The spec clearly say that, putAll will use put, that means, we can not 
use a putAll in an override put. Otherwise, it will recursive endlessly.
So can I use a putAll in the override put method in an class which 
extends the TreeMap?

[1]
public class TreeMapTest<K, V> extends TreeMap<K, V> {
     @Override
     public V put(K key, V value) {
     System.out.println(key + " : " + value);
     return super.put(key, value);
     }

     /**
      * @param args
      */
     public static void main(String[] args) {
     TreeMapTest<Integer, Integer> mTreeMap = new TreeMapTest<>();
     TreeMap<Integer, Integer> mt = new TreeMap<>();
     mt.put(1, 1);
     mTreeMap.putAll(mt);

     mTreeMap.clear();
     mTreeMap.put(2, 2);
     mTreeMap.putAll(mt);
     }
}

-- 
Yours Charles




More information about the core-libs-dev mailing list