You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ba...@apache.org on 2009/09/15 07:56:25 UTC

svn commit: r815089 - /commons/proper/collections/trunk/src/java/org/apache/commons/collections/MapUtils.java

Author: bayard
Date: Tue Sep 15 05:56:25 2009
New Revision: 815089

URL: http://svn.apache.org/viewvc?rev=815089&view=rev
Log:
Merging from -r468106:814127 of collections_jdk5_branch - namely where this code was generified; mostly in r738956.

Also see the following revisions:

    ------------------------------------------------------------------------
    r751887 | mbenson | 2009-03-09 15:40:01 -0700 (Mon, 09 Mar 2009) | 1 line
    
    add methods to wrap Maps and SortedMaps not based on Commons Collections classes to their Iterable*Map counterparts
    ------------------------------------------------------------------------
    r740457 | mbenson | 2009-02-03 13:23:15 -0800 (Tue, 03 Feb 2009) | 1 line
    
    ws
    ------------------------------------------------------------------------
    r740150 | mbenson | 2009-02-02 15:24:00 -0800 (Mon, 02 Feb 2009) | 1 line
    
    make all [collections] maps implement IterableMap
    ------------------------------------------------------------------------
    r471166 | scolebourne | 2006-11-04 03:33:22 -0800 (Sat, 04 Nov 2006) | 1 line
    
    Removed Typed* containers such as TypedList and TypedMap as generics now provides type safety
    ------------------------------------------------------------------------

Modified:
    commons/proper/collections/trunk/src/java/org/apache/commons/collections/MapUtils.java

Modified: commons/proper/collections/trunk/src/java/org/apache/commons/collections/MapUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/java/org/apache/commons/collections/MapUtils.java?rev=815089&r1=815088&r2=815089&view=diff
==============================================================================
--- commons/proper/collections/trunk/src/java/org/apache/commons/collections/MapUtils.java (original)
+++ commons/proper/collections/trunk/src/java/org/apache/commons/collections/MapUtils.java Tue Sep 15 05:56:25 2009
@@ -19,6 +19,7 @@
 import java.io.PrintStream;
 import java.text.NumberFormat;
 import java.text.ParseException;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -30,6 +31,8 @@
 import java.util.TreeMap;
 import java.util.Collection;
 
+import org.apache.commons.collections.map.AbstractMapDecorator;
+import org.apache.commons.collections.map.AbstractSortedMapDecorator;
 import org.apache.commons.collections.map.FixedSizeMap;
 import org.apache.commons.collections.map.FixedSizeSortedMap;
 import org.apache.commons.collections.map.LazyMap;
@@ -40,12 +43,10 @@
 import org.apache.commons.collections.map.PredicatedSortedMap;
 import org.apache.commons.collections.map.TransformedMap;
 import org.apache.commons.collections.map.TransformedSortedMap;
-import org.apache.commons.collections.map.TypedMap;
-import org.apache.commons.collections.map.TypedSortedMap;
 import org.apache.commons.collections.map.UnmodifiableMap;
 import org.apache.commons.collections.map.UnmodifiableSortedMap;
 
-/** 
+/**
  * Provides utility methods and decorators for
  * {@link Map} and {@link SortedMap} instances.
  * <p>
@@ -89,17 +90,19 @@
  * @author Neil O'Toole
  */
 public class MapUtils {
-    
+
     /**
      * An empty unmodifiable map.
      * This was not provided in JDK1.2.
      */
-    public static final Map EMPTY_MAP = UnmodifiableMap.decorate(new HashMap(1));
+    public static final Map<Object, Object> EMPTY_MAP = UnmodifiableMap.decorate(new HashMap<Object, Object>(1));
+
     /**
      * An empty unmodifiable sorted map.
      * This is not provided in the JDK.
      */
-    public static final SortedMap EMPTY_SORTED_MAP = UnmodifiableSortedMap.decorate(new TreeMap());
+    public static final SortedMap<Object, Object> EMPTY_SORTED_MAP = UnmodifiableSortedMap.decorate(new TreeMap<Object, Object>());
+
     /**
      * String used to indent the verbose and debug Map prints.
      */
@@ -109,8 +112,8 @@
      * <code>MapUtils</code> should not normally be instantiated.
      */
     public MapUtils() {
-    }    
-    
+    }
+
     // Type safe getters
     //-------------------------------------------------------------------------
     /**
@@ -120,7 +123,7 @@
      * @param key  the key to look up
      * @return the value in the Map, <code>null</code> if null map input
      */
-    public static Object getObject(final Map map, final Object key) {
+    public static <K, V> V getObject(final Map<? super K, V> map, final K key) {
         if (map != null) {
             return map.get(key);
         }
@@ -136,7 +139,7 @@
      * @param key  the key to look up
      * @return the value in the Map as a String, <code>null</code> if null map input
      */
-    public static String getString(final Map map, final Object key) {
+    public static <K> String getString(final Map<? super K, ?> map, final K key) {
         if (map != null) {
             Object answer = map.get(key);
             if (answer != null) {
@@ -160,17 +163,17 @@
      * @param key  the key to look up
      * @return the value in the Map as a Boolean, <code>null</code> if null map input
      */
-    public static Boolean getBoolean(final Map map, final Object key) {
+    public static <K> Boolean getBoolean(final Map<? super K, ?> map, final K key) {
         if (map != null) {
             Object answer = map.get(key);
             if (answer != null) {
                 if (answer instanceof Boolean) {
                     return (Boolean) answer;
-                    
-                } else if (answer instanceof String) {
+                }
+                if (answer instanceof String) {
                     return new Boolean((String) answer);
-                    
-                } else if (answer instanceof Number) {
+                }
+                if (answer instanceof Number) {
                     Number n = (Number) answer;
                     return (n.intValue() != 0) ? Boolean.TRUE : Boolean.FALSE;
                 }
@@ -192,18 +195,17 @@
      * @param key  the key to look up
      * @return the value in the Map as a Number, <code>null</code> if null map input
      */
-    public static Number getNumber(final Map map, final Object key) {
+    public static <K> Number getNumber(final Map<? super K, ?> map, final K key) {
         if (map != null) {
             Object answer = map.get(key);
             if (answer != null) {
                 if (answer instanceof Number) {
                     return (Number) answer;
-                    
-                } else if (answer instanceof String) {
+                }
+                if (answer instanceof String) {
                     try {
                         String text = (String) answer;
                         return NumberFormat.getInstance().parse(text);
-                        
                     } catch (ParseException e) {
                         logInfo(e);
                     }
@@ -222,11 +224,12 @@
      * @param key  the key to look up
      * @return the value in the Map as a Byte, <code>null</code> if null map input
      */
-    public static Byte getByte(final Map map, final Object key) {
+    public static <K> Byte getByte(final Map<? super K, ?> map, final K key) {
         Number answer = getNumber(map, key);
         if (answer == null) {
             return null;
-        } else if (answer instanceof Byte) {
+        }
+        if (answer instanceof Byte) {
             return (Byte) answer;
         }
         return new Byte(answer.byteValue());
@@ -241,11 +244,12 @@
      * @param key  the key to look up
      * @return the value in the Map as a Short, <code>null</code> if null map input
      */
-    public static Short getShort(final Map map, final Object key) {
+    public static <K> Short getShort(final Map<? super K, ?> map, final K key) {
         Number answer = getNumber(map, key);
         if (answer == null) {
             return null;
-        } else if (answer instanceof Short) {
+        }
+        if (answer instanceof Short) {
             return (Short) answer;
         }
         return new Short(answer.shortValue());
@@ -260,11 +264,12 @@
      * @param key  the key to look up
      * @return the value in the Map as a Integer, <code>null</code> if null map input
      */
-    public static Integer getInteger(final Map map, final Object key) {
+    public static <K> Integer getInteger(final Map<? super K, ?> map, final K key) {
         Number answer = getNumber(map, key);
         if (answer == null) {
             return null;
-        } else if (answer instanceof Integer) {
+        }
+        if (answer instanceof Integer) {
             return (Integer) answer;
         }
         return new Integer(answer.intValue());
@@ -279,11 +284,12 @@
      * @param key  the key to look up
      * @return the value in the Map as a Long, <code>null</code> if null map input
      */
-    public static Long getLong(final Map map, final Object key) {
+    public static <K> Long getLong(final Map<? super K, ?> map, final K key) {
         Number answer = getNumber(map, key);
         if (answer == null) {
             return null;
-        } else if (answer instanceof Long) {
+        }
+        if (answer instanceof Long) {
             return (Long) answer;
         }
         return new Long(answer.longValue());
@@ -298,11 +304,12 @@
      * @param key  the key to look up
      * @return the value in the Map as a Float, <code>null</code> if null map input
      */
-    public static Float getFloat(final Map map, final Object key) {
+    public static <K> Float getFloat(final Map<? super K, ?> map, final K key) {
         Number answer = getNumber(map, key);
         if (answer == null) {
             return null;
-        } else if (answer instanceof Float) {
+        }
+        if (answer instanceof Float) {
             return (Float) answer;
         }
         return new Float(answer.floatValue());
@@ -317,11 +324,12 @@
      * @param key  the key to look up
      * @return the value in the Map as a Double, <code>null</code> if null map input
      */
-    public static Double getDouble(final Map map, final Object key) {
+    public static <K> Double getDouble(final Map<? super K, ?> map, final K key) {
         Number answer = getNumber(map, key);
         if (answer == null) {
             return null;
-        } else if (answer instanceof Double) {
+        }
+        if (answer instanceof Double) {
             return (Double) answer;
         }
         return new Double(answer.doubleValue());
@@ -337,11 +345,11 @@
      * @param key  the key to look up
      * @return the value in the Map as a Map, <code>null</code> if null map input
      */
-    public static Map getMap(final Map map, final Object key) {
+    public static <K> Map<?, ?> getMap(final Map<? super K, ?> map, final K key) {
         if (map != null) {
             Object answer = map.get(key);
             if (answer != null && answer instanceof Map) {
-                return (Map) answer;
+                return (Map<?, ?>) answer;
             }
         }
         return null;
@@ -359,10 +367,10 @@
      *  @return  the value in the map, or defaultValue if the original value
      *    is null or the map is null
      */
-    public static Object getObject( Map map, Object key, Object defaultValue ) {
-        if ( map != null ) {
-            Object answer = map.get( key );
-            if ( answer != null ) {
+    public static <K, V> V getObject(Map<K, V> map, K key, V defaultValue) {
+        if (map != null) {
+            V answer = map.get(key);
+            if (answer != null) {
                 return answer;
             }
         }
@@ -377,13 +385,13 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a string, or defaultValue if the 
+     *  @return  the value in the map as a string, or defaultValue if the
      *    original value is null, the map is null or the string conversion
      *    fails
      */
-    public static String getString( Map map, Object key, String defaultValue ) {
-        String answer = getString( map, key );
-        if ( answer == null ) {
+    public static <K> String getString(Map<? super K, ?> map, K key, String defaultValue) {
+        String answer = getString(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
@@ -397,13 +405,13 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a boolean, or defaultValue if the 
+     *  @return  the value in the map as a boolean, or defaultValue if the
      *    original value is null, the map is null or the boolean conversion
      *    fails
      */
-    public static Boolean getBoolean( Map map, Object key, Boolean defaultValue ) {
-        Boolean answer = getBoolean( map, key );
-        if ( answer == null ) {
+    public static <K> Boolean getBoolean(Map<? super K, ?> map, K key, Boolean defaultValue) {
+        Boolean answer = getBoolean(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
@@ -417,13 +425,13 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a number, or defaultValue if the 
+     *  @return  the value in the map as a number, or defaultValue if the
      *    original value is null, the map is null or the number conversion
      *    fails
      */
-    public static Number getNumber( Map map, Object key, Number defaultValue ) {
-        Number answer = getNumber( map, key );
-        if ( answer == null ) {
+    public static <K> Number getNumber(Map<? super K, ?> map, K key, Number defaultValue) {
+        Number answer = getNumber(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
@@ -437,13 +445,13 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a number, or defaultValue if the 
+     *  @return  the value in the map as a number, or defaultValue if the
      *    original value is null, the map is null or the number conversion
      *    fails
      */
-    public static Byte getByte( Map map, Object key, Byte defaultValue ) {
-        Byte answer = getByte( map, key );
-        if ( answer == null ) {
+    public static <K> Byte getByte(Map<? super K, ?> map, K key, Byte defaultValue) {
+        Byte answer = getByte(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
@@ -457,13 +465,13 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a number, or defaultValue if the 
+     *  @return  the value in the map as a number, or defaultValue if the
      *    original value is null, the map is null or the number conversion
      *    fails
      */
-    public static Short getShort( Map map, Object key, Short defaultValue ) {
-        Short answer = getShort( map, key );
-        if ( answer == null ) {
+    public static <K> Short getShort(Map<? super K, ?> map, K key, Short defaultValue) {
+        Short answer = getShort(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
@@ -477,13 +485,13 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a number, or defaultValue if the 
+     *  @return  the value in the map as a number, or defaultValue if the
      *    original value is null, the map is null or the number conversion
      *    fails
      */
-    public static Integer getInteger( Map map, Object key, Integer defaultValue ) {
-        Integer answer = getInteger( map, key );
-        if ( answer == null ) {
+    public static <K> Integer getInteger(Map<? super K, ?> map, K key, Integer defaultValue) {
+        Integer answer = getInteger(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
@@ -497,13 +505,13 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a number, or defaultValue if the 
+     *  @return  the value in the map as a number, or defaultValue if the
      *    original value is null, the map is null or the number conversion
      *    fails
      */
-    public static Long getLong( Map map, Object key, Long defaultValue ) {
-        Long answer = getLong( map, key );
-        if ( answer == null ) {
+    public static <K> Long getLong(Map<? super K, ?> map, K key, Long defaultValue) {
+        Long answer = getLong(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
@@ -517,13 +525,13 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a number, or defaultValue if the 
+     *  @return  the value in the map as a number, or defaultValue if the
      *    original value is null, the map is null or the number conversion
      *    fails
      */
-    public static Float getFloat( Map map, Object key, Float defaultValue ) {
-        Float answer = getFloat( map, key );
-        if ( answer == null ) {
+    public static <K> Float getFloat(Map<? super K, ?> map, K key, Float defaultValue) {
+        Float answer = getFloat(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
@@ -537,13 +545,13 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a number, or defaultValue if the 
+     *  @return  the value in the map as a number, or defaultValue if the
      *    original value is null, the map is null or the number conversion
      *    fails
      */
-    public static Double getDouble( Map map, Object key, Double defaultValue ) {
-        Double answer = getDouble( map, key );
-        if ( answer == null ) {
+    public static <K> Double getDouble(Map<? super K, ?> map, K key, Double defaultValue) {
+        Double answer = getDouble(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
@@ -557,18 +565,17 @@
      *  @param key  the key of the value to look up in that map
      *  @param defaultValue  what to return if the value is null or if the
      *     conversion fails
-     *  @return  the value in the map as a number, or defaultValue if the 
+     *  @return  the value in the map as a number, or defaultValue if the
      *    original value is null, the map is null or the map conversion
      *    fails
      */
-    public static Map getMap( Map map, Object key, Map defaultValue ) {
-        Map answer = getMap( map, key );
-        if ( answer == null ) {
+    public static <K> Map<?, ?> getMap(Map<? super K, ?> map, K key, Map<?, ?> defaultValue) {
+        Map<?, ?> answer = getMap(map, key);
+        if (answer == null) {
             answer = defaultValue;
         }
         return answer;
     }
-    
 
     // Type safe primitive getters
     //-------------------------------------------------------------------------
@@ -586,12 +593,8 @@
      * @param key  the key to look up
      * @return the value in the Map as a Boolean, <code>false</code> if null map input
      */
-    public static boolean getBooleanValue(final Map map, final Object key) {
-        Boolean booleanObject = getBoolean(map, key);
-        if (booleanObject == null) {
-            return false;
-        }
-        return booleanObject.booleanValue();
+    public static <K> boolean getBooleanValue(final Map<? super K, ?> map, final K key) {
+        return Boolean.TRUE.equals(getBoolean(map, key));
     }
 
     /**
@@ -603,7 +606,7 @@
      * @param key  the key to look up
      * @return the value in the Map as a byte, <code>0</code> if null map input
      */
-    public static byte getByteValue(final Map map, final Object key) {
+    public static <K> byte getByteValue(final Map<? super K, ?> map, final K key) {
         Byte byteObject = getByte(map, key);
         if (byteObject == null) {
             return 0;
@@ -620,7 +623,7 @@
      * @param key  the key to look up
      * @return the value in the Map as a short, <code>0</code> if null map input
      */
-    public static short getShortValue(final Map map, final Object key) {
+    public static <K> short getShortValue(final Map<? super K, ?> map, final K key) {
         Short shortObject = getShort(map, key);
         if (shortObject == null) {
             return 0;
@@ -637,7 +640,7 @@
      * @param key  the key to look up
      * @return the value in the Map as an int, <code>0</code> if null map input
      */
-    public static int getIntValue(final Map map, final Object key) {
+    public static <K> int getIntValue(final Map<? super K, ?> map, final K key) {
         Integer integerObject = getInteger(map, key);
         if (integerObject == null) {
             return 0;
@@ -654,7 +657,7 @@
      * @param key  the key to look up
      * @return the value in the Map as a long, <code>0L</code> if null map input
      */
-    public static long getLongValue(final Map map, final Object key) {
+    public static <K> long getLongValue(final Map<? super K, ?> map, final K key) {
         Long longObject = getLong(map, key);
         if (longObject == null) {
             return 0L;
@@ -671,7 +674,7 @@
      * @param key  the key to look up
      * @return the value in the Map as a float, <code>0.0F</code> if null map input
      */
-    public static float getFloatValue(final Map map, final Object key) {
+    public static <K> float getFloatValue(final Map<? super K, ?> map, final K key) {
         Float floatObject = getFloat(map, key);
         if (floatObject == null) {
             return 0f;
@@ -688,7 +691,7 @@
      * @param key  the key to look up
      * @return the value in the Map as a double, <code>0.0</code> if null map input
      */
-    public static double getDoubleValue(final Map map, final Object key) {
+    public static <K> double getDoubleValue(final Map<? super K, ?> map, final K key) {
         Double doubleObject = getDouble(map, key);
         if (doubleObject == null) {
             return 0d;
@@ -715,7 +718,7 @@
      *     conversion fails
      * @return the value in the Map as a Boolean, <code>defaultValue</code> if null map input
      */
-    public static boolean getBooleanValue(final Map map, final Object key, boolean defaultValue) {
+    public static <K> boolean getBooleanValue(final Map<? super K, ?> map, final K key, boolean defaultValue) {
         Boolean booleanObject = getBoolean(map, key);
         if (booleanObject == null) {
             return defaultValue;
@@ -725,7 +728,7 @@
 
     /**
      * Gets a byte from a Map in a null-safe manner,
-     * using the default value if the the conversion fails.     
+     * using the default value if the the conversion fails.
      * <p>
      * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
      *
@@ -735,7 +738,7 @@
      *     conversion fails
      * @return the value in the Map as a byte, <code>defaultValue</code> if null map input
      */
-    public static byte getByteValue(final Map map, final Object key, byte defaultValue) {
+    public static <K> byte getByteValue(final Map<? super K, ?> map, final K key, byte defaultValue) {
         Byte byteObject = getByte(map, key);
         if (byteObject == null) {
             return defaultValue;
@@ -745,7 +748,7 @@
 
     /**
      * Gets a short from a Map in a null-safe manner,
-     * using the default value if the the conversion fails.     
+     * using the default value if the the conversion fails.
      * <p>
      * The short is obtained from the results of {@link #getNumber(Map,Object)}.
      *
@@ -755,7 +758,7 @@
      *     conversion fails
      * @return the value in the Map as a short, <code>defaultValue</code> if null map input
      */
-    public static short getShortValue(final Map map, final Object key, short defaultValue) {
+    public static <K> short getShortValue(final Map<? super K, ?> map, final K key, short defaultValue) {
         Short shortObject = getShort(map, key);
         if (shortObject == null) {
             return defaultValue;
@@ -765,7 +768,7 @@
 
     /**
      * Gets an int from a Map in a null-safe manner,
-     * using the default value if the the conversion fails.     
+     * using the default value if the the conversion fails.
      * <p>
      * The int is obtained from the results of {@link #getNumber(Map,Object)}.
      *
@@ -775,7 +778,7 @@
      *     conversion fails
      * @return the value in the Map as an int, <code>defaultValue</code> if null map input
      */
-    public static int getIntValue(final Map map, final Object key, int defaultValue) {
+    public static <K> int getIntValue(final Map<? super K, ?> map, final K key, int defaultValue) {
         Integer integerObject = getInteger(map, key);
         if (integerObject == null) {
             return defaultValue;
@@ -785,7 +788,7 @@
 
     /**
      * Gets a long from a Map in a null-safe manner,
-     * using the default value if the the conversion fails.     
+     * using the default value if the the conversion fails.
      * <p>
      * The long is obtained from the results of {@link #getNumber(Map,Object)}.
      *
@@ -795,7 +798,7 @@
      *     conversion fails
      * @return the value in the Map as a long, <code>defaultValue</code> if null map input
      */
-    public static long getLongValue(final Map map, final Object key, long defaultValue) {
+    public static <K> long getLongValue(final Map<? super K, ?> map, final K key, long defaultValue) {
         Long longObject = getLong(map, key);
         if (longObject == null) {
             return defaultValue;
@@ -805,7 +808,7 @@
 
     /**
      * Gets a float from a Map in a null-safe manner,
-     * using the default value if the the conversion fails.     
+     * using the default value if the the conversion fails.
      * <p>
      * The float is obtained from the results of {@link #getNumber(Map,Object)}.
      *
@@ -815,7 +818,7 @@
      *     conversion fails
      * @return the value in the Map as a float, <code>defaultValue</code> if null map input
      */
-    public static float getFloatValue(final Map map, final Object key, float defaultValue) {
+    public static <K> float getFloatValue(final Map<? super K, ?> map, final K key, float defaultValue) {
         Float floatObject = getFloat(map, key);
         if (floatObject == null) {
             return defaultValue;
@@ -825,7 +828,7 @@
 
     /**
      * Gets a double from a Map in a null-safe manner,
-     * using the default value if the the conversion fails.     
+     * using the default value if the the conversion fails.
      * <p>
      * The double is obtained from the results of {@link #getNumber(Map,Object)}.
      *
@@ -835,7 +838,7 @@
      *     conversion fails
      * @return the value in the Map as a double, <code>defaultValue</code> if null map input
      */
-    public static double getDoubleValue(final Map map, final Object key, double defaultValue) {
+    public static <K> double getDoubleValue(final Map<? super K, ?> map, final K key, double defaultValue) {
         Double doubleObject = getDouble(map, key);
         if (doubleObject == null) {
             return defaultValue;
@@ -848,15 +851,15 @@
     /**
      * Gets a new Properties object initialised with the values from a Map.
      * A null input will return an empty properties object.
-     * 
+     *
      * @param map  the map to convert to a Properties object, may not be null
      * @return the properties object
      */
-    public static Properties toProperties(final Map map) {
+    public static <K, V> Properties toProperties(final Map<K, V> map) {
         Properties answer = new Properties();
         if (map != null) {
-            for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
-                Map.Entry entry = (Map.Entry) iter.next();
+            for (Iterator<Map.Entry<K, V>> iter = map.entrySet().iterator(); iter.hasNext();) {
+                Map.Entry<?, ?> entry = iter.next();
                 Object key = entry.getKey();
                 Object value = entry.getValue();
                 answer.put(key, value);
@@ -867,24 +870,24 @@
 
     /**
      * Creates a new HashMap using data copied from a ResourceBundle.
-     * 
+     *
      * @param resourceBundle  the resource bundle to convert, may not be null
      * @return the hashmap containing the data
      * @throws NullPointerException if the bundle is null
      */
-    public static Map toMap(final ResourceBundle resourceBundle) {
-        Enumeration enumeration = resourceBundle.getKeys();
-        Map map = new HashMap();
+    public static Map<String, Object> toMap(final ResourceBundle resourceBundle) {
+        Enumeration<String> enumeration = resourceBundle.getKeys();
+        Map<String, Object> map = new HashMap<String, Object>();
 
         while (enumeration.hasMoreElements()) {
             String key = (String) enumeration.nextElement();
             Object value = resourceBundle.getObject(key);
             map.put(key, value);
         }
-        
+
         return map;
     }
- 
+
     // Printing methods
     //-------------------------------------------------------------------------
     /**
@@ -908,9 +911,9 @@
     public static void verbosePrint(
         final PrintStream out,
         final Object label,
-        final Map map) {
+        final Map<?, ?> map) {
 
-        verbosePrintInternal(out, label, map, new ArrayStack(), false);
+        verbosePrintInternal(out, label, map, new ArrayStack<Map<?, ?>>(), false);
     }
 
     /**
@@ -934,9 +937,9 @@
     public static void debugPrint(
         final PrintStream out,
         final Object label,
-        final Map map) {
+        final Map<?, ?> map) {
 
-        verbosePrintInternal(out, label, map, new ArrayStack(), true);
+        verbosePrintInternal(out, label, map, new ArrayStack<Map<?, ?>>(), true);
     }
 
     // Implementation methods
@@ -953,15 +956,15 @@
     }
 
     /**
-     * Implementation providing functionality for {@link #debugPrint} and for 
+     * Implementation providing functionality for {@link #debugPrint} and for
      * {@link #verbosePrint}.  This prints the given map with nice line breaks.
-     * If the debug flag is true, it additionally prints the type of the object 
-     * value.  If the contents of a map include the map itself, then the text 
-     * <em>(this Map)</em> is printed out.  If the contents include a 
-     * parent container of the map, the the text <em>(ancestor[i] Map)</em> is 
-     * printed, where i actually indicates the number of levels which must be 
-     * traversed in the sequential list of ancestors (e.g. father, grandfather, 
-     * great-grandfather, etc).  
+     * If the debug flag is true, it additionally prints the type of the object
+     * value.  If the contents of a map include the map itself, then the text
+     * <em>(this Map)</em> is printed out.  If the contents include a
+     * parent container of the map, the the text <em>(ancestor[i] Map)</em> is
+     * printed, where i actually indicates the number of levels which must be
+     * traversed in the sequential list of ancestors (e.g. father, grandfather,
+     * great-grandfather, etc).
      *
      * @param out  the stream to print to
      * @param label  the label to be used, may be <code>null</code>.
@@ -969,7 +972,7 @@
      *  It typically represents the name of the property in a bean or similar.
      * @param map  the map to print, may be <code>null</code>.
      *  If <code>null</code>, the text 'null' is output
-     * @param lineage  a stack consisting of any maps in which the previous 
+     * @param lineage  a stack consisting of any maps in which the previous
      *  argument is contained. This is checked to avoid infinite recursion when
      *  printing the output
      * @param debug  flag indicating whether type names should be output.
@@ -978,10 +981,10 @@
     private static void verbosePrintInternal(
         final PrintStream out,
         final Object label,
-        final Map map,
-        final ArrayStack lineage,
+        final Map<?, ?> map,
+        final ArrayStack<Map<?, ?>> lineage,
         final boolean debug) {
-        
+
         printIndent(out, lineage.size());
 
         if (map == null) {
@@ -1002,34 +1005,33 @@
 
         lineage.push(map);
 
-        for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
-            Map.Entry entry = (Map.Entry) it.next();
+        for (Map.Entry<?, ?> entry : map.entrySet()) {
             Object childKey = entry.getKey();
             Object childValue = entry.getValue();
             if (childValue instanceof Map && !lineage.contains(childValue)) {
                 verbosePrintInternal(
                     out,
                     (childKey == null ? "null" : childKey),
-                    (Map) childValue,
+                    (Map<?, ?>) childValue,
                     lineage,
                     debug);
             } else {
                 printIndent(out, lineage.size());
                 out.print(childKey);
                 out.print(" = ");
-                
+
                 final int lineageIndex = lineage.indexOf(childValue);
                 if (lineageIndex == -1) {
                     out.print(childValue);
                 } else if (lineage.size() - 1 == lineageIndex) {
-                    out.print("(this Map)");    
+                    out.print("(this Map)");
                 } else {
                     out.print(
                         "(ancestor["
                             + (lineage.size() - 1 - lineageIndex - 1)
                             + "] Map)");
                 }
-                
+
                 if (debug && childValue != null) {
                     out.print(' ');
                     out.println(childValue.getClass().getName());
@@ -1038,7 +1040,7 @@
                 }
             }
         }
-        
+
         lineage.pop();
 
         printIndent(out, lineage.size());
@@ -1055,7 +1057,7 @@
             out.print(INDENT_STRING);
         }
     }
-    
+
     // Misc
     //-----------------------------------------------------------------------
     /**
@@ -1064,22 +1066,22 @@
      * <p>
      * This operation assumes that the inverse mapping is well defined.
      * If the input map had multiple entries with the same value mapped to
-     * different keys, the returned map will map one of those keys to the 
+     * different keys, the returned map will map one of those keys to the
      * value, but the exact key which will be mapped is undefined.
      *
      * @param map  the map to invert, may not be null
      * @return a new HashMap containing the inverted data
      * @throws NullPointerException if the map is null
      */
-    public static Map invertMap(Map map) {
-        Map out = new HashMap(map.size());
-        for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
-            Map.Entry entry = (Map.Entry) it.next();
+    public static <K, V> Map<V, K> invertMap(Map<K, V> map) {
+        Map<V, K> out = new HashMap<V, K>(map.size());
+        for (Iterator<Map.Entry<K, V>> it = map.entrySet().iterator(); it.hasNext();) {
+            Map.Entry<K, V> entry = it.next();
             out.put(entry.getValue(), entry.getKey());
         }
         return out;
     }
-     
+
     //-----------------------------------------------------------------------
     /**
      * Protects against adding null values to a map.
@@ -1092,18 +1094,16 @@
      * which should be held in the same way in the map.
      * <p>
      * Keys are not validated.
-     * 
+     * Note that this method can be used to circumvent the map's
+     * value type at runtime.
+     *
      * @param map  the map to add to, may not be null
      * @param key  the key
      * @param value  the value, null converted to ""
      * @throws NullPointerException if the map is null
      */
-    public static void safeAddToMap(Map map, Object key, Object value) throws NullPointerException {
-        if (value == null) {
-            map.put(key, "");
-        } else {
-            map.put(key, value);
-        }
+    public static <K> void safeAddToMap(Map<? super K, Object> map, K key, Object value) throws NullPointerException {
+        map.put(key, value == null ? "" : value);
     }
 
     //-----------------------------------------------------------------------
@@ -1154,7 +1154,8 @@
      * @throws ClassCastException if the array contents is mixed
      * @since Commons Collections 3.2
      */
-    public static Map putAll(Map map, Object[] array) {
+    @SuppressWarnings("unchecked")
+    public static <K, V> Map<K, V> putAll(Map<K, V> map, Object[] array) {
         map.size();  // force NPE
         if (array == null || array.length == 0) {
             return map;
@@ -1162,12 +1163,12 @@
         Object obj = array[0];
         if (obj instanceof Map.Entry) {
             for (int i = 0; i < array.length; i++) {
-                Map.Entry entry = (Map.Entry) array[i];
+                Map.Entry<K, V> entry = (Map.Entry<K, V>) array[i];
                 map.put(entry.getKey(), entry.getValue());
             }
         } else if (obj instanceof KeyValue) {
             for (int i = 0; i < array.length; i++) {
-                KeyValue keyval = (KeyValue) array[i];
+                KeyValue<K, V> keyval = (KeyValue<K, V>) array[i];
                 map.put(keyval.getKey(), keyval.getValue());
             }
         } else if (obj instanceof Object[]) {
@@ -1176,11 +1177,11 @@
                 if (sub == null || sub.length < 2) {
                     throw new IllegalArgumentException("Invalid array element: " + i);
                 }
-                map.put(sub[0], sub[1]);
+                map.put((K) sub[0], (V) sub[1]);
             }
         } else {
             for (int i = 0; i < array.length - 1;) {
-                map.put(array[i++], array[i++]);
+                map.put((K) array[i++], (V) array[i++]);
             }
         }
         return map;
@@ -1191,11 +1192,12 @@
      * Null-safe check if the specified map is empty.
      * <p>
      * Null returns true.
-     * 
+     *
      * @param map  the map to check, may be null
      * @return true if empty or null
      * @since Commons Collections 3.2
      */
+    @SuppressWarnings("unchecked")
     public static boolean isEmpty(Map map) {
         return (map == null || map.isEmpty());
     }
@@ -1204,11 +1206,12 @@
      * Null-safe check if the specified map is not empty.
      * <p>
      * Null returns false.
-     * 
+     *
      * @param map  the map to check, may be null
      * @return true if non-null and non-empty
      * @since Commons Collections 3.2
      */
+    @SuppressWarnings("unchecked")
     public static boolean isNotEmpty(Map map) {
         return !MapUtils.isEmpty(map);
     }
@@ -1218,9 +1221,9 @@
     /**
      * Returns a synchronized map backed by the given map.
      * <p>
-     * You must manually synchronize on the returned buffer's iterator to 
+     * You must manually synchronize on the returned buffer's iterator to
      * avoid non-deterministic behavior:
-     *  
+     *
      * <pre>
      * Map m = MapUtils.synchronizedMap(myMap);
      * Set s = m.keySet();  // outside synchronized block
@@ -1231,14 +1234,14 @@
      *     }
      * }
      * </pre>
-     * 
+     *
      * This method uses the implementation in {@link java.util.Collections Collections}.
-     * 
+     *
      * @param map  the map to synchronize, must not be null
      * @return a synchronized map backed by the given map
      * @throws IllegalArgumentException  if the map is null
      */
-    public static Map synchronizedMap(Map map) {
+    public static <K, V> Map<K, V> synchronizedMap(Map<K, V> map) {
         return Collections.synchronizedMap(map);
     }
 
@@ -1251,7 +1254,7 @@
      * @return an unmodifiable map backed by the given map
      * @throws IllegalArgumentException  if the map is null
      */
-    public static Map unmodifiableMap(Map map) {
+    public static <K, V> Map<K, V> unmodifiableMap(Map<K, V> map) {
         return UnmodifiableMap.decorate(map);
     }
 
@@ -1270,26 +1273,11 @@
      * @return a predicated map backed by the given map
      * @throws IllegalArgumentException  if the Map is null
      */
-    public static Map predicatedMap(Map map, Predicate keyPred, Predicate valuePred) {
+    public static <K, V> IterableMap<K, V> predicatedMap(Map<K, V> map, Predicate<? super K> keyPred, Predicate<? super V> valuePred) {
         return PredicatedMap.decorate(map, keyPred, valuePred);
     }
 
     /**
-     * Returns a typed map backed by the given map.
-     * <p>
-     * Only keys and values of the specified types can be added to the map.
-     * 
-     * @param map  the map to limit to a specific type, must not be null
-     * @param keyType  the type of keys which may be added to the map, must not be null
-     * @param valueType  the type of values which may be added to the map, must not be null
-     * @return a typed map backed by the specified map
-     * @throws IllegalArgumentException  if the Map or Class is null
-     */
-    public static Map typedMap(Map map, Class keyType, Class valueType) {
-        return TypedMap.decorate(map, keyType, valueType);
-    }
-    
-    /**
      * Returns a transformed map backed by the given map.
      * <p>
      * This method returns a new map (decorating the specified map) that
@@ -1298,7 +1286,7 @@
      * If you want that behaviour, see {@link TransformedMap#decorateTransform}.
      * <p>
      * Each object is passed through the transformers as it is added to the
-     * Map. It is important not to use the original map after invoking this 
+     * Map. It is important not to use the original map after invoking this
      * method, as it is a backdoor for adding untransformed objects.
      * <p>
      * If there are any elements already in the map being decorated, they
@@ -1310,21 +1298,23 @@
      * @return a transformed map backed by the given map
      * @throws IllegalArgumentException  if the Map is null
      */
-    public static Map transformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
+    public static <K, V> IterableMap<K, V> transformedMap(Map<K, V> map,
+            Transformer<? super K, ? extends K> keyTransformer,
+            Transformer<? super V, ? extends V> valueTransformer) {
         return TransformedMap.decorate(map, keyTransformer, valueTransformer);
     }
-    
+
     /**
      * Returns a fixed-sized map backed by the given map.
-     * Elements may not be added or removed from the returned map, but 
-     * existing elements can be changed (for instance, via the 
+     * Elements may not be added or removed from the returned map, but
+     * existing elements can be changed (for instance, via the
      * {@link Map#put(Object,Object)} method).
      *
      * @param map  the map whose size to fix, must not be null
      * @return a fixed-size map backed by that map
      * @throws IllegalArgumentException  if the Map is null
      */
-    public static Map fixedSizeMap(Map map) {
+    public static <K, V> IterableMap<K, V> fixedSizeMap(Map<K, V> map) {
         return FixedSizeMap.decorate(map);
     }
 
@@ -1356,8 +1346,8 @@
      * @return a lazy map backed by the given map
      * @throws IllegalArgumentException  if the Map or Factory is null
      */
-    public static Map lazyMap(Map map, Factory factory) {
-        return LazyMap.decorate(map, factory);
+    public static <K, V> IterableMap<K, V> lazyMap(Map<K, V> map, Factory<? extends V> factory) {
+        return LazyMap.getLazyMap(map, factory);
     }
 
     /**
@@ -1395,8 +1385,8 @@
      * @return a lazy map backed by the given map
      * @throws IllegalArgumentException  if the Map or Transformer is null
      */
-    public static Map lazyMap(Map map, Transformer transformerFactory) {
-        return LazyMap.decorate(map, transformerFactory);
+    public static <K, V> IterableMap<K, V> lazyMap(Map<K, V> map, Transformer<? super K, ? extends V> transformerFactory) {
+        return LazyMap.getLazyMap(map, transformerFactory);
     }
 
     /**
@@ -1410,7 +1400,7 @@
      * @return an ordered map backed by the given map
      * @throws IllegalArgumentException  if the Map is null
      */
-    public static Map orderedMap(Map map) {
+    public static <K, V> OrderedMap<K, V> orderedMap(Map<K, V> map) {
         return ListOrderedMap.decorate(map);
     }
 
@@ -1423,8 +1413,8 @@
      * @see MultiValueMap
      * @since Commons Collections 3.2
      */
-    public static Map multiValueMap(Map map) {
-        return MultiValueMap.decorate(map);
+    public static <K, V> MultiValueMap<K, V> multiValueMap(Map<K, ? super Collection<V>> map) {
+        return MultiValueMap.<K, V>decorate(map);
     }
 
     /**
@@ -1438,7 +1428,7 @@
      * @see MultiValueMap
      * @since Commons Collections 3.2
      */
-    public static Map multiValueMap(Map map, Class collectionClass) {
+    public static <K, V, C extends Collection<V>> MultiValueMap<K, V> multiValueMap(Map<K, C> map, Class<C> collectionClass) {
         return MultiValueMap.decorate(map, collectionClass);
     }
 
@@ -1453,7 +1443,7 @@
      * @see MultiValueMap
      * @since Commons Collections 3.2
      */
-    public static Map multiValueMap(Map map, Factory collectionFactory) {
+    public static <K, V, C extends Collection<V>> MultiValueMap<K, V> multiValueMap(Map<K, C> map, Factory<C> collectionFactory) {
         return MultiValueMap.decorate(map, collectionFactory);
     }
 
@@ -1462,9 +1452,9 @@
     /**
      * Returns a synchronized sorted map backed by the given sorted map.
      * <p>
-     * You must manually synchronize on the returned buffer's iterator to 
+     * You must manually synchronize on the returned buffer's iterator to
      * avoid non-deterministic behavior:
-     *  
+     *
      * <pre>
      * Map m = MapUtils.synchronizedSortedMap(myMap);
      * Set s = m.keySet();  // outside synchronized block
@@ -1475,14 +1465,14 @@
      *     }
      * }
      * </pre>
-     * 
+     *
      * This method uses the implementation in {@link java.util.Collections Collections}.
-     * 
+     *
      * @param map  the map to synchronize, must not be null
      * @return a synchronized map backed by the given map
      * @throws IllegalArgumentException  if the map is null
      */
-    public static Map synchronizedSortedMap(SortedMap map) {
+    public static <K, V> SortedMap<K, V> synchronizedSortedMap(SortedMap<K, V> map) {
         return Collections.synchronizedSortedMap(map);
     }
 
@@ -1495,7 +1485,7 @@
      * @return an unmodifiable map backed by the given map
      * @throws IllegalArgumentException  if the map is null
      */
-    public static Map unmodifiableSortedMap(SortedMap map) {
+    public static <K, V> SortedMap<K, V> unmodifiableSortedMap(SortedMap<K, V> map) {
         return UnmodifiableSortedMap.decorate(map);
     }
 
@@ -1514,25 +1504,12 @@
      * @return a predicated map backed by the given map
      * @throws IllegalArgumentException  if the SortedMap is null
      */
-    public static SortedMap predicatedSortedMap(SortedMap map, Predicate keyPred, Predicate valuePred) {
+    public static <K, V> SortedMap<K, V> predicatedSortedMap(SortedMap<K, V> map,
+            Predicate<? super K> keyPred, Predicate<? super V> valuePred) {
         return PredicatedSortedMap.decorate(map, keyPred, valuePred);
     }
 
     /**
-     * Returns a typed sorted map backed by the given map.
-     * <p>
-     * Only keys and values of the specified types can be added to the map.
-     * 
-     * @param map  the map to limit to a specific type, must not be null
-     * @param keyType  the type of keys which may be added to the map, must not be null
-     * @param valueType  the type of values which may be added to the map, must not be null
-     * @return a typed map backed by the specified map
-     */
-    public static SortedMap typedSortedMap(SortedMap map, Class keyType, Class valueType) {
-        return TypedSortedMap.decorate(map, keyType, valueType);
-    }
-    
-    /**
      * Returns a transformed sorted map backed by the given map.
      * <p>
      * This method returns a new sorted map (decorating the specified map) that
@@ -1541,7 +1518,7 @@
      * If you want that behaviour, see {@link TransformedSortedMap#decorateTransform}.
      * <p>
      * Each object is passed through the transformers as it is added to the
-     * Map. It is important not to use the original map after invoking this 
+     * Map. It is important not to use the original map after invoking this
      * method, as it is a backdoor for adding untransformed objects.
      * <p>
      * If there are any elements already in the map being decorated, they
@@ -1553,21 +1530,23 @@
      * @return a transformed map backed by the given map
      * @throws IllegalArgumentException  if the SortedMap is null
      */
-    public static SortedMap transformedSortedMap(SortedMap map, Transformer keyTransformer, Transformer valueTransformer) {
+    public static <K, V> SortedMap<K, V> transformedSortedMap(SortedMap<K, V> map,
+            Transformer<? super K, ? extends K> keyTransformer,
+            Transformer<? super V, ? extends V> valueTransformer) {
         return TransformedSortedMap.decorate(map, keyTransformer, valueTransformer);
     }
-    
+
     /**
      * Returns a fixed-sized sorted map backed by the given sorted map.
-     * Elements may not be added or removed from the returned map, but 
-     * existing elements can be changed (for instance, via the 
+     * Elements may not be added or removed from the returned map, but
+     * existing elements can be changed (for instance, via the
      * {@link Map#put(Object,Object)} method).
      *
      * @param map  the map whose size to fix, must not be null
      * @return a fixed-size map backed by that map
      * @throws IllegalArgumentException  if the SortedMap is null
      */
-    public static SortedMap fixedSizeSortedMap(SortedMap map) {
+    public static <K, V> SortedMap<K, V> fixedSizeSortedMap(SortedMap<K, V> map) {
         return FixedSizeSortedMap.decorate(map);
     }
 
@@ -1600,10 +1579,11 @@
      * @return a lazy map backed by the given map
      * @throws IllegalArgumentException  if the SortedMap or Factory is null
      */
-    public static SortedMap lazySortedMap(SortedMap map, Factory factory) {
-        return LazySortedMap.decorate(map, factory);
+    public static <K, V> SortedMap<K, V> lazySortedMap(SortedMap<K, V> map,
+            Factory<? extends V> factory) {
+        return LazySortedMap.getLazySortedMap(map, factory);
     }
-    
+
     /**
      * Returns a "lazy" sorted map whose values will be created on demand.
      * <p>
@@ -1639,8 +1619,9 @@
      * @return a lazy map backed by the given map
      * @throws IllegalArgumentException  if the Map or Transformer is null
      */
-    public static SortedMap lazySortedMap(SortedMap map, Transformer transformerFactory) {
-        return LazySortedMap.decorate(map, transformerFactory);
+    public static <K, V> SortedMap<K, V> lazySortedMap(SortedMap<K, V> map,
+            Transformer<? super K, ? extends V> transformerFactory) {
+        return LazySortedMap.getLazySortedMap(map, transformerFactory);
     }
 
     /**
@@ -1653,6 +1634,7 @@
      * @param keyTransformer the <code>Transformer</code> used to transform the collection value into a key value
      * @throws NullPointerException if the map, collection or transformer are null
      */
+    // TODO: Generics
     public static void populateMap(Map map, Collection collection, Transformer keyTransformer) {
         populateMap(map, collection, keyTransformer, TransformerUtils.nopTransformer());
     }
@@ -1668,6 +1650,7 @@
      * @param valueTransformer the <code>Transformer</code> used to transform the collection value into a value
      * @throws NullPointerException if the map, collection or transformers are null
      */
+    // TODO: Generics
     public static void populateMap(Map map, Collection collection, Transformer keyTransformer, Transformer valueTransformer) {
         Iterator iter = collection.iterator();
         while (iter.hasNext()) {
@@ -1675,4 +1658,41 @@
             map.put(keyTransformer.transform(temp), valueTransformer.transform(temp));
         }
     }
+
+    /**
+     * Get the specified {@link Map} as an {@link IterableMap}.
+     * @param <K>
+     * @param <V>
+     * @param map to wrap if necessary.
+     * @return IterableMap<K, V>
+     * @since Commons Collections 5
+     * @TODO fix version
+     */
+    public static <K, V> IterableMap<K, V> iterableMap(Map<K, V> map) {
+        if (map == null) {
+            throw new IllegalArgumentException("Map must not be null");
+        }
+        return map instanceof IterableMap ? (IterableMap<K, V>) map
+                : new AbstractMapDecorator<K, V>(map) {
+                };
+    }
+
+    /**
+     * Get the specified {@link SortedMap} as an {@link IterableSortedMap}.
+     * @param <K>
+     * @param <V>
+     * @param sortedMap to wrap if necessary
+     * @return {@link IterableSortedMap}<K, V>
+     * @since Commons Collections 5
+     * @TODO fix version
+     */
+    public static <K, V> IterableSortedMap<K, V> iterableSortedMap(SortedMap<K, V> sortedMap) {
+        if (sortedMap == null) {
+            throw new IllegalArgumentException("Map must not be null");
+        }
+        return sortedMap instanceof IterableSortedMap ? (IterableSortedMap<K, V>) sortedMap
+                : new AbstractSortedMapDecorator<K, V>(sortedMap) {
+                };
+    }
+
 }