< prev index next >

## src/java.base/share/classes/java/util/Map.java

Print this page

    rev 47953 : 8177290: add copy factory methods for unmodifiable List, Set, Map
    8184690: add Collectors for collecting into unmodifiable List, Set, and Map
    Reviewed-by: alanb, briangoetz, dholmes, jrose, rriggs, scolebourne

    *** 108,128 ****
       * indirectly contains itself. This includes the {@code clone()},
       * {@code equals()}, {@code hashCode()} and {@code toString()} methods.
       * Implementations may optionally handle the self-referential scenario, however
       * most current implementations do not do so.
       *
    !  * <h2><a id="immutable">Immutable Map Static Factory Methods</a></h2>
    !  * <p>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:
       *
       * <ul>
    !  * <li>They are <em>structurally immutable</em>. Keys and values cannot be added,
    !  * removed, or updated. Calling any mutator method will always cause
    !  * {@code UnsupportedOperationException} to be thrown.
       * However, if the contained keys or values are themselves mutable, this may cause the
       * Map to behave inconsistently or its contents to appear to change.
       * <li>They disallow {@code null} keys and values. Attempts to create them with
       * {@code null} keys or values result in {@code NullPointerException}.
       * <li>They are serializable if all keys and values are serializable.
    --- 108,129 ----
       * indirectly contains itself. This includes the {@code clone()},
       * {@code equals()}, {@code hashCode()} and {@code toString()} methods.
       * Implementations may optionally handle the self-referential scenario, however
       * most current implementations do not do so.
       *
    !  * <h2><a id="unmodifiable">Unmodifiable Maps</a></h2>
    !  * <p>The {@link Map#of() Map.of},
    !  * {@link Map#ofEntries(Map.Entry...) Map.ofEntries}, and
    !  * {@link Map#copyOf Map.copyOf}
    !  * static factory methods provide a convenient way to create unmodifiable maps.
       * The {@code Map}
       * instances created by these methods have the following characteristics:
       *
       * <ul>
    !  * <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Keys and values
    !  * cannot be added, removed, or updated. Calling any mutator method on the Map
    !  * will always cause {@code UnsupportedOperationException} to be thrown.
       * However, if the contained keys or values are themselves mutable, this may cause the
       * Map to behave inconsistently or its contents to appear to change.
       * <li>They disallow {@code null} keys and values. Attempts to create them with
       * {@code null} keys or values result in {@code NullPointerException}.
       * <li>They are serializable if all keys and values are serializable.
    *** 1274,1285 ****
              }
              return newValue;
          }

          /**
    !      * Returns an immutable map containing zero mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @return an empty {@code Map}
           *
    --- 1275,1286 ----
              }
              return newValue;
          }

          /**
    !      * Returns an unmodifiable map containing zero mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @return an empty {@code Map}
           *
    *** 1288,1299 ****
          static <K, V> Map<K, V> of() {
              return ImmutableCollections.Map0.instance();
          }

          /**
    !      * Returns an immutable map containing a single mapping.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the mapping's key
           * @param v1 the mapping's value
    --- 1289,1300 ----
          static <K, V> Map<K, V> of() {
              return ImmutableCollections.Map0.instance();
          }

          /**
    !      * Returns an unmodifiable map containing a single mapping.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the mapping's key
           * @param v1 the mapping's value
    *** 1305,1316 ****
          static <K, V> Map<K, V> of(K k1, V v1) {
              return new ImmutableCollections.Map1<>(k1, v1);
          }

          /**
    !      * Returns an immutable map containing two mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    --- 1306,1317 ----
          static <K, V> Map<K, V> of(K k1, V v1) {
              return new ImmutableCollections.Map1<>(k1, v1);
          }

          /**
    !      * Returns an unmodifiable map containing two mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    *** 1325,1336 ****
          static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
          }

          /**
    !      * Returns an immutable map containing three mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    --- 1326,1337 ----
          static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
          }

          /**
    !      * Returns an unmodifiable map containing three mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    *** 1347,1358 ****
          static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
          }

          /**
    !      * Returns an immutable map containing four mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    --- 1348,1359 ----
          static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
          }

          /**
    !      * Returns an unmodifiable map containing four mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    *** 1371,1382 ****
          static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
          }

          /**
    !      * Returns an immutable map containing five mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    --- 1372,1383 ----
          static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
          }

          /**
    !      * Returns an unmodifiable map containing five mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    *** 1397,1408 ****
          static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
          }

          /**
    !      * Returns an immutable map containing six mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    --- 1398,1409 ----
          static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
          }

          /**
    !      * Returns an unmodifiable map containing six mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    *** 1427,1438 ****
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6);
          }

          /**
    !      * Returns an immutable map containing seven mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    --- 1428,1439 ----
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6);
          }

          /**
    !      * Returns an unmodifiable map containing seven mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    *** 1459,1470 ****
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6, k7, v7);
          }

          /**
    !      * Returns an immutable map containing eight mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    --- 1460,1471 ----
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6, k7, v7);
          }

          /**
    !      * Returns an unmodifiable map containing eight mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    *** 1493,1504 ****
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6, k7, v7, k8, v8);
          }

          /**
    !      * Returns an immutable map containing nine mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    --- 1494,1505 ----
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6, k7, v7, k8, v8);
          }

          /**
    !      * Returns an unmodifiable map containing nine mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    *** 1529,1540 ****
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6, k7, v7, k8, v8, k9, v9);
          }

          /**
    !      * Returns an immutable map containing ten mappings.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    --- 1530,1541 ----
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6, k7, v7, k8, v8, k9, v9);
          }

          /**
    !      * Returns an unmodifiable map containing ten mappings.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @param <K> the {@code Map}'s key type
           * @param <V> the {@code Map}'s value type
           * @param k1 the first mapping's key
           * @param v1 the first mapping's value
    *** 1567,1579 ****
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
          }

          /**
    !      * Returns an immutable map containing keys and values extracted from the given entries.
           * The entries themselves are not stored in the map.
    !      * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
           *
           * @apiNote
           * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method.
           * For example,
           *
    --- 1568,1580 ----
              return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                                     k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
          }

          /**
    !      * Returns an unmodifiable map containing keys and values extracted from the given entries.
           * The entries themselves are not stored in the map.
    !      * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
           *
           * @apiNote
           * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method.
           * For example,
           *
    *** 1600,1635 ****
           * @since 9
           */
          @SafeVarargs
          @SuppressWarnings("varargs")
          static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
    !         if (entries.length == 0) { // implicit null check of entries
                  return ImmutableCollections.Map0.instance();
              } else if (entries.length == 1) {
                  return new ImmutableCollections.Map1<>(entries[0].getKey(),
                                                         entries[0].getValue());
              } else {
                  Object[] kva = new Object[entries.length << 1];
                  int a = 0;
                  for (Entry<? extends K, ? extends V> entry : entries) {
                      kva[a++] = entry.getKey();
                      kva[a++] = entry.getValue();
                  }
                  return new ImmutableCollections.MapN<>(kva);
              }
          }

          /**
    !      * 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:
           *
           * <ul>
           * <li>They disallow {@code null} keys and values. Attempts to create them using a {@code null}
           * key or value result in {@code NullPointerException}.
    !      * <li>They are immutable. Calls to {@link Entry#setValue Entry.setValue()}
           * on a returned {@code Entry} result in {@code UnsupportedOperationException}.
           * <li>They are not serializable.
           * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
           * 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,
    --- 1601,1638 ----
           * @since 9
           */
          @SafeVarargs
          @SuppressWarnings("varargs")
          static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
    !         if (entries.length == 0) { // implicit null check of entries array
                  return ImmutableCollections.Map0.instance();
              } else if (entries.length == 1) {
    +             // implicit null check of the array slot
                  return new ImmutableCollections.Map1<>(entries[0].getKey(),
                                                         entries[0].getValue());
              } else {
                  Object[] kva = new Object[entries.length << 1];
                  int a = 0;
                  for (Entry<? extends K, ? extends V> entry : entries) {
    +                 // implicit null checks of each array slot
                      kva[a++] = entry.getKey();
                      kva[a++] = entry.getValue();
                  }
                  return new ImmutableCollections.MapN<>(kva);
              }
          }

          /**
    !      * Returns an unmodifiable {@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:
           *
           * <ul>
           * <li>They disallow {@code null} keys and values. Attempts to create them using a {@code null}
           * key or value result in {@code NullPointerException}.
    !      * <li>They are unmodifiable. Calls to {@link Entry#setValue Entry.setValue()}
           * on a returned {@code Entry} result in {@code UnsupportedOperationException}.
           * <li>They are not serializable.
           * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
           * 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,
    *** 1653,1658 ****
    --- 1656,1687 ----
           */
          static <K, V> Entry<K, V> entry(K k, V v) {
              // KeyValueHolder checks for nulls
              return new KeyValueHolder<>(k, v);
          }
    +
    +     /**
    +      * Returns an <a href="#unmodifiable">unmodifiable Map</a> containing the entries
    +      * of the given Map. The given Map must not be null, and it must not contain any
    +      * null keys or values. If the given Map is subsequently modified, the returned
    +      * Map will not reflect such modifications.
    +      *
    +      * @implNote
    +      * If the given Map is an <a href="#unmodifiable">unmodifiable Map</a>,
    +      * calling copyOf will generally not create a copy.
    +      *
    +      * @param <K> the {@code Map}'s key type
    +      * @param <V> the {@code Map}'s value type
    +      * @param map a {@code Map} from which entries are drawn, must be non-null
    +      * @return a {@code Map} containing the entries of the given {@code Map}
    +      * @throws NullPointerException if map is null, or if it contains any null keys or values
    +      * @since 10
    +      */
    +     @SuppressWarnings({"rawtypes","unchecked"})
    +     static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map) {
    +         if (map instanceof ImmutableCollections.AbstractImmutableMap) {
    +             return (Map<K,V>)map;
    +         } else {
    +             return (Map<K,V>)Map.ofEntries(map.entrySet().toArray(new Entry[0]));
    +         }
    +     }
      }

< prev index next >