--- jsr166/src/main/java/util/Map.java 2015/12/14 21:15:46 1.2 +++ jsr166/src/main/java/util/Map.java 2015/12/16 03:15:28 1.3 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,6 +110,31 @@ import java.io.Serializable; * Implementations may optionally handle the self-referential scenario, however * most current implementations do not do so. * + *

Immutable Map Static Factory Methods

+ *

The {@link Map#of() Map.of()} and + * {@link Map#ofEntries(Map.Entry...) Map.ofEntries()} + * static factory methods provide a convenient way to create immutable maps. + * The {@code Map} + * instances created by these methods have the following characteristics: + * + *

+ * *

This interface is a member of the * * Java Collections Framework. @@ -126,7 +151,7 @@ import java.io.Serializable; * @see Set * @since 1.2 */ -public interface Map { +public interface Map { // Query Operations /** @@ -157,10 +182,10 @@ public interface Map { * key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) */ boolean containsKey(Object key); @@ -177,10 +202,10 @@ public interface Map { * specified value * @throws ClassCastException if the value is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified value is null and this * map does not permit null values - * (optional) + * (optional) */ boolean containsValue(Object value); @@ -205,10 +230,10 @@ public interface Map { * {@code null} if this map contains no mapping for the key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) */ V get(Object key); @@ -265,10 +290,10 @@ public interface Map { * is not supported by this map * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this * map does not permit null keys - * (optional) + * (optional) */ V remove(Object key); @@ -373,7 +398,7 @@ public interface Map { * @see Map#entrySet() * @since 1.2 */ - interface Entry { + interface Entry { /** * Returns the key corresponding to this entry. * @@ -468,7 +493,7 @@ public interface Map { * @see Comparable * @since 1.8 */ - public static , V> Comparator> comparingByKey() { + public static , V> Comparator> comparingByKey() { return (Comparator> & Serializable) (c1, c2) -> c1.getKey().compareTo(c2.getKey()); } @@ -485,7 +510,7 @@ public interface Map { * @see Comparable * @since 1.8 */ - public static > Comparator> comparingByValue() { + public static > Comparator> comparingByValue() { return (Comparator> & Serializable) (c1, c2) -> c1.getValue().compareTo(c2.getValue()); } @@ -578,10 +603,10 @@ public interface Map { * {@code defaultValue} if this map contains no mapping for the key * @throws ClassCastException if the key is of an inappropriate type for * this map - * (optional) + * (optional) * @throws NullPointerException if the specified key is null and this map * does not permit null keys - * (optional) + * (optional) * @since 1.8 */ default V getOrDefault(Object key, V defaultValue) { @@ -660,13 +685,13 @@ public interface Map { * values * @throws ClassCastException if a replacement value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if function or a replacement value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of a replacement value * prevents it from being stored in this map - * (optional) + * (optional) * @throws ConcurrentModificationException if an entry is found to be * removed during iteration * @since 1.8 @@ -727,16 +752,16 @@ public interface Map { * if the implementation supports null values.) * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the key or value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V putIfAbsent(K key, V value) { @@ -773,13 +798,13 @@ public interface Map { * @return {@code true} if the value was removed * @throws UnsupportedOperationException if the {@code remove} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the key or value is of an inappropriate * type for this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values - * (optional) + * (optional) * @since 1.8 */ default boolean remove(Object key, Object value) { @@ -822,14 +847,14 @@ public interface Map { * @return {@code true} if the value was replaced * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of a specified key or value * prevents it from being stored in this map * @throws NullPointerException if a specified key or newValue is null, * and this map does not permit null keys or values * @throws NullPointerException if oldValue is null and this map does not * permit null values - * (optional) + * (optional) * @throws IllegalArgumentException if some property of a specified key * or value prevents it from being stored in this map * @since 1.8 @@ -872,10 +897,10 @@ public interface Map { * if the implementation supports null values.) * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws NullPointerException if the specified key or value is null, * and this map does not permit null keys or values * @throws IllegalArgumentException if some property of the specified key @@ -955,13 +980,13 @@ public interface Map { * is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V computeIfAbsent(K key, @@ -1032,13 +1057,13 @@ public interface Map { * remappingFunction is null * @throws UnsupportedOperationException if the {@code put} operation * is not supported by this map - * (optional) + * (optional) * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map - * (optional) + * (optional) * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * (optional) + * (optional) * @since 1.8 */ default V computeIfPresent(K key, @@ -1084,7 +1109,7 @@ public interface Map { *

 {@code
      * V oldValue = map.get(key);
      * V newValue = remappingFunction.apply(key, oldValue);
-     * if (oldValue != null ) {
+     * if (oldValue != null) {
      *    if (newValue != null)
      *       map.put(key, newValue);
      *    else
@@ -1124,13 +1149,13 @@ public interface Map {
      *         remappingFunction is null
      * @throws UnsupportedOperationException if the {@code put} operation
      *         is not supported by this map
-     *         (optional)
+     *         (optional)
      * @throws ClassCastException if the class of the specified key or value
      *         prevents it from being stored in this map
-     *         (optional)
+     *         (optional)
      * @throws IllegalArgumentException if some property of the specified key
      *         or value prevents it from being stored in this map
-     *         (optional)
+     *         (optional)
      * @since 1.8
      */
     default V compute(K key,
@@ -1219,16 +1244,16 @@ public interface Map {
      *         value is associated with the key
      * @throws UnsupportedOperationException if the {@code put} operation
      *         is not supported by this map
-     *         (optional)
+     *         (optional)
      * @throws ClassCastException if the class of the specified key or value
      *         prevents it from being stored in this map
-     *         (optional)
+     *         (optional)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (optional)
      * @throws NullPointerException if the specified key is null and this map
      *         does not support null keys or the value or remappingFunction is
      *         null
-     * @throws IllegalArgumentException if some property of the specified key
-     *         or value prevents it from being stored in this map
-     *         (optional)
      * @since 1.8
      */
     default V merge(K key, V value,
@@ -1245,4 +1270,465 @@ public interface Map {
         }
         return newValue;
     }
+
+    /**
+     * Returns an immutable map containing zero mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @return an empty {@code Map}
+     *
+     * @since 9
+     */
+    static  Map of() {
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Returns an immutable map containing a single mapping.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the mapping's key
+     * @param v1 the mapping's value
+     * @return a {@code Map} containing the specified mapping
+     * @throws NullPointerException if the key or the value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1) {
+        return Collections.singletonMap(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+    }
+
+    /**
+     * Returns an immutable map containing two mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if the keys are duplicates
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1, K k2, V v2) {
+        Map map = new HashMap<>(3); // specify number of buckets to avoid resizing
+        map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+        map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
+        if (map.size() != 2) {
+            throw new IllegalArgumentException("duplicate keys");
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns an immutable map containing three mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1, K k2, V v2, K k3, V v3) {
+        Map map = new HashMap<>(5); // specify number of buckets to avoid resizing
+        map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+        map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
+        map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
+        if (map.size() != 3) {
+            throw new IllegalArgumentException("duplicate keys");
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns an immutable map containing four mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+        Map map = new HashMap<>(6); // specify number of buckets to avoid resizing
+        map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+        map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
+        map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
+        map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
+        if (map.size() != 4) {
+            throw new IllegalArgumentException("duplicate keys");
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns an immutable map containing five mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+        Map map = new HashMap<>(7); // specify number of buckets to avoid resizing
+        map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+        map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
+        map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
+        map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
+        map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
+        if (map.size() != 5) {
+            throw new IllegalArgumentException("duplicate keys");
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns an immutable map containing six mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6) {
+        Map map = new HashMap<>(9); // specify number of buckets to avoid resizing
+        map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+        map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
+        map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
+        map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
+        map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
+        map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
+        if (map.size() != 6) {
+            throw new IllegalArgumentException("duplicate keys");
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns an immutable map containing seven mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7) {
+        Map map = new HashMap<>(10); // specify number of buckets to avoid resizing
+        map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+        map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
+        map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
+        map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
+        map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
+        map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
+        map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7));
+        if (map.size() != 7) {
+            throw new IllegalArgumentException("duplicate keys");
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns an immutable map containing eight mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8) {
+        Map map = new HashMap<>(11); // specify number of buckets to avoid resizing
+        map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+        map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
+        map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
+        map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
+        map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
+        map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
+        map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7));
+        map.put(Objects.requireNonNull(k8), Objects.requireNonNull(v8));
+        if (map.size() != 8) {
+            throw new IllegalArgumentException("duplicate keys");
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns an immutable map containing nine mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
+        Map map = new HashMap<>(13); // specify number of buckets to avoid resizing
+        map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+        map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
+        map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
+        map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
+        map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
+        map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
+        map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7));
+        map.put(Objects.requireNonNull(k8), Objects.requireNonNull(v8));
+        map.put(Objects.requireNonNull(k9), Objects.requireNonNull(v9));
+        if (map.size() != 9) {
+            throw new IllegalArgumentException("duplicate keys");
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns an immutable map containing ten mappings.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @param  the {@code Map}'s key type
+     * @param  the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @param k10 the tenth mapping's key
+     * @param v10 the tenth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static  Map of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
+        Map map = new HashMap<>(14); // specify number of buckets to avoid resizing
+        map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
+        map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
+        map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
+        map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
+        map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
+        map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
+        map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7));
+        map.put(Objects.requireNonNull(k8), Objects.requireNonNull(v8));
+        map.put(Objects.requireNonNull(k9), Objects.requireNonNull(v9));
+        map.put(Objects.requireNonNull(k10), Objects.requireNonNull(v10));
+        if (map.size() != 10) {
+            throw new IllegalArgumentException("duplicate keys");
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Returns an immutable map containing keys and values extracted from the given entries.
+     * The entries themselves are not stored in the map.
+     * See Immutable Map Static Factory Methods for details.
+     *
+     * @apiNote
+     * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method.
+     * For example,
+     *
+     * 
{@code
+     *     import static java.util.Map.entry;
+     *
+     *     Map map = Map.ofEntries(
+     *         entry(1, "a"),
+     *         entry(2, "b"),
+     *         entry(3, "c"),
+     *         ...
+     *         entry(26, "z"));
+     * }
+ * + * @param the {@code Map}'s key type + * @param the {@code Map}'s value type + * @param entries {@code Map.Entry}s containing the keys and values from which the map is populated + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException if there are any duplicate keys + * @throws NullPointerException if any entry, key, or value is {@code null}, or if + * the {@code entries} array is {@code null} + * + * @see Map#entry Map.entry() + * @since 9 + */ + @SafeVarargs + @SuppressWarnings("varargs") + static Map ofEntries(Entry... entries) { + Map map = new HashMap<>(entries.length * 4 / 3 + 1); // throws NPE if entries is null + for (Entry e : entries) { + // next line throws NPE if e is null + map.put(Objects.requireNonNull(e.getKey()), Objects.requireNonNull(e.getValue())); + } + if (map.size() != entries.length) { + throw new IllegalArgumentException("duplicate keys"); + } + return Collections.unmodifiableMap(map); + } + + /** + * Returns an immutable {@link Entry} containing the given key and value. + * These entries are suitable for populating {@code Map} instances using the + * {@link Map#ofEntries Map.ofEntries()} method. + * The {@code Entry} instances created by this method have the following characteristics: + * + *
    + *
  • They disallow {@code null} keys and values. Attempts to create them using a {@code null} + * key or value result in {@code NullPointerException}. + *
  • They are immutable. Calls to {@link Entry#setValue Entry.setValue()} + * on a returned {@code Entry} result in {@code UnsupportedOperationException}. + *
  • They are not serializable. + *
  • They are value-based. + * Callers should make no assumptions about the identity of the returned instances. + * This method is free to create new instances or reuse existing ones. Therefore, + * identity-sensitive operations on these instances (reference equality ({@code ==}), + * identity hash code, and synchronization) are unreliable and should be avoided. + *
+ * + * @apiNote + * For a serializable {@code Entry}, see {@link AbstractMap.SimpleEntry} or + * {@link AbstractMap.SimpleImmutableEntry}. + * + * @param the key's type + * @param the value's type + * @param k the key + * @param v the value + * @return an {@code Entry} containing the specified key and value + * @throws NullPointerException if the key or value is {@code null} + * + * @see Map#ofEntries Map.ofEntries() + * @since 9 + */ + static Entry entry(K k, V v) { + // KeyValueHolder checks for nulls + return new KeyValueHolder<>(k, v); + } }