--- old/src/java.base/share/classes/java/util/List.java 2015-11-23 22:03:10.000000000 -0800 +++ new/src/java.base/share/classes/java/util/List.java 2015-11-23 22:03:10.000000000 -0800 @@ -87,6 +87,22 @@ * Such exceptions are marked as "optional" in the specification for this * interface. * + *

Immutable List Static Factory Methods

+ *

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

+ * *

This interface is a member of the * * Java Collections Framework. @@ -731,4 +747,312 @@ default Spliterator spliterator() { return Spliterators.spliterator(this, Spliterator.ORDERED); } + + /** + * Creates an immutable list containing zero elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @return the newly created list + * + * @since 9 + */ + static List of() { + return Collections.emptyList(); + } + + /** + * Creates an immutable list containing one element. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the single list element + * @return the newly created list + * @throws NullPointerException if the element is null + * + * @since 9 + */ + static List of(E e1) { + return Collections.singletonList(Objects.requireNonNull(e1)); + } + + /** + * Creates an immutable list containing two elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the first list element + * @param e2 the second list element + * @return the newly created list + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static List of(E e1, E e2) { + return Collections.unmodifiableList( + Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2))); + } + + /** + * Creates an immutable list containing three elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the first list element + * @param e2 the second list element + * @param e3 the third list element + * @return the newly created list + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static List of(E e1, E e2, E e3) { + return Collections.unmodifiableList( + Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3))); + } + + /** + * Creates an immutable list containing four elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the first list element + * @param e2 the second list element + * @param e3 the third list element + * @param e4 the fourth list element + * @return the newly created list + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4) { + return Collections.unmodifiableList( + Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4))); + } + + /** + * Creates an immutable list containing five elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the first list element + * @param e2 the second list element + * @param e3 the third list element + * @param e4 the fourth list element + * @param e5 the fifth list element + * @return the newly created list + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5) { + return Collections.unmodifiableList( + Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5))); + } + + /** + * Creates an immutable list containing six elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the first list element + * @param e2 the second list element + * @param e3 the third list element + * @param e4 the fourth list element + * @param e5 the fifth list element + * @param e6 the sixth list element + * @return the newly created list + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5, E e6) { + return Collections.unmodifiableList( + Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6))); + } + + /** + * Creates an immutable list containing seven elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the first list element + * @param e2 the second list element + * @param e3 the third list element + * @param e4 the fourth list element + * @param e5 the fifth list element + * @param e6 the sixth list element + * @param e7 the seventh list element + * @return the newly created list + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) { + return Collections.unmodifiableList( + Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6), + Objects.requireNonNull(e7))); + } + + /** + * Creates an immutable list containing eight elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the first list element + * @param e2 the second list element + * @param e3 the third list element + * @param e4 the fourth list element + * @param e5 the fifth list element + * @param e6 the sixth list element + * @param e7 the seventh list element + * @param e8 the eighth list element + * @return the newly created list + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { + return Collections.unmodifiableList( + Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6), + Objects.requireNonNull(e7), + Objects.requireNonNull(e8))); + } + + /** + * Creates an immutable list containing nine elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the first list element + * @param e2 the second list element + * @param e3 the third list element + * @param e4 the fourth list element + * @param e5 the fifth list element + * @param e6 the sixth list element + * @param e7 the seventh list element + * @param e8 the eighth list element + * @param e9 the ninth list element + * @return the newly created list + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { + return Collections.unmodifiableList( + Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6), + Objects.requireNonNull(e7), + Objects.requireNonNull(e8), + Objects.requireNonNull(e9))); + } + + /** + * Creates an immutable list containing ten elements. + * + * See Immutable List Static Factory Methods for details. + * + * @param the list's element type + * @param e1 the first list element + * @param e2 the second list element + * @param e3 the third list element + * @param e4 the fourth list element + * @param e5 the fifth list element + * @param e6 the sixth list element + * @param e7 the seventh list element + * @param e8 the eighth list element + * @param e9 the ninth list element + * @param e10 the tenth list element + * @return the newly created list + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static List of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) { + return Collections.unmodifiableList( + Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6), + Objects.requireNonNull(e7), + Objects.requireNonNull(e8), + Objects.requireNonNull(e9), + Objects.requireNonNull(e10))); + } + + /** + * Creates an immutable list containing an arbitrary number of elements. + * See Immutable List Static Factory Methods for details. + * + * @apiNote + * This method also accepts a single array as an argument. The element type of + * the resulting list will be the component type of the array, and the size of + * the list will be equal to the length of the array. To create a list with + * a single element that is an array, do the following: + * + *

{@code
+     *     String[] array = ... ;
+     *     List list = List.of(array);
+     * }
+ * + * This will cause the {@link List#of(Object) List.of(E)} method + * to be invoked instead. + * + * @param the list's element type + * @param es the elements to be contained in the list + * @return the newly created list + * @throws NullPointerException if an element is null or if the array is null + * + * @since 9 + */ + @SafeVarargs + @SuppressWarnings("varargs") + static List of(E... es) { + es = es.clone(); // throws NPE if es is null + for (E e : es) { + Objects.requireNonNull(e); + } + return Collections.unmodifiableList(Arrays.asList(es)); + } } --- old/src/java.base/share/classes/java/util/Map.java 2015-11-23 22:03:11.000000000 -0800 +++ new/src/java.base/share/classes/java/util/Map.java 2015-11-23 22:03:11.000000000 -0800 @@ -110,6 +110,25 @@ * 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: + * + *

    + *
  • They cannot be modified. Attempts to modify them result in + * an {@code UnsupportedOperationException}. + *
  • They are truly immutable only if the contained keys and values are themselves + * immutable. If a key or value is mutated, the behavior of the map is unspecified. + *
  • They disallow null keys and values. Attempts to create them with + * null keys or values result in {@code NullPointerException}. + *
  • They are serializable if all keys and values are serializable. + *
  • They reject duplicate keys at creation time. Duplicate keys + * passed to a static factory method result in {@code IllegalArgumentException}. + *
+ * *

This interface is a member of the * * Java Collections Framework. @@ -1233,4 +1252,454 @@ } return newValue; } + + /** + * Creates an immutable map containing zero mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the map's value type + * @return the newly created map + * + * @since 9 + */ + static Map of() { + return Collections.emptyMap(); + } + + /** + * Creates an immutable map containing a single mapping. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the map's value type + * @param k1 the mapping's key + * @param v1 the mapping's value + * @return the newly created map + * @throws NullPointerException if the key or the value is null + * + * @since 9 + */ + static Map of(K k1, V v1) { + return Collections.singletonMap(Objects.requireNonNull(k1), Objects.requireNonNull(v1)); + } + + /** + * Creates an immutable map containing two mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the 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 the newly created map + * @throws IllegalArgumentException if the keys are duplicates + * @throws NullPointerException if any key or value is null + * + * @since 9 + */ + static Map of(K k1, V v1, K k2, V v2) { + Map map = new HashMap<>(3); + 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); + } + + /** + * Creates an immutable map containing three mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the 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 the newly created map + * @throws IllegalArgumentException if any keys are duplicates + * @throws NullPointerException if any key or value is null + * + * @since 9 + */ + static Map of(K k1, V v1, K k2, V v2, K k3, V v3) { + Map map = new HashMap<>(5); + 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); + } + + /** + * Creates an immutable map containing four mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the 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 the newly created map + * @throws IllegalArgumentException if any keys are duplicates + * @throws NullPointerException if any key or value is 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); + 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); + } + + /** + * Creates an immutable map containing five mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the 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 the newly created map + * @throws IllegalArgumentException if any keys are duplicates + * @throws NullPointerException if any key or value is 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); + 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); + } + + /** + * Creates an immutable map containing six mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the 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 the newly created map + * @throws IllegalArgumentException if any keys are duplicates + * @throws NullPointerException if any key or value is 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); + 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); + } + + /** + * Creates an immutable map containing seven mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the 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 the newly created map + * @throws IllegalArgumentException if any keys are duplicates + * @throws NullPointerException if any key or value is 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); + 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); + } + + /** + * Creates an immutable map containing eight mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the 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 the newly created map + * @throws IllegalArgumentException if any keys are duplicates + * @throws NullPointerException if any key or value is 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); + 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); + } + + /** + * Creates an immutable map containing nine mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the 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 the newly created map + * @throws IllegalArgumentException if any keys are duplicates + * @throws NullPointerException if any key or value is 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); + 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); + } + + /** + * Creates an immutable map containing ten mappings. + * See Immutable Map Static Factory Methods for details. + * + * @param the map's key type + * @param the 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 the newly created map + * @throws IllegalArgumentException if any keys are duplicates + * @throws NullPointerException if any key or value is 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); + 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); + } + + /** + * Creates an immutable map containing keys and values from the given entries. + * 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 map's key type + * @param the map's value type + * @param entries the keys and values with which the map is populated + * @return the newly created {@code Map} + * @throws IllegalArgumentException if any keys are duplicates + * @throws NullPointerException if any entry, key, or value is null, or if + * the {@code entries} array is 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) { + Objects.requireNonNull(e); + map.put(Objects.requireNonNull(e.getKey()), Objects.requireNonNull(e.getValue())); + } + if (map.size() != entries.length) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableMap(map); + } + + /** + * Creates 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 key and the value must not be null. Calling {@link Entry#setValue Entry.setValue()} + * on the returned {@code Entry} results in an {@code UnsupportedOperationException} + * being thrown. The returned {@code Entry} is not guaranteed to be serializable. + * + *

The returned {@code Entry} is a value-based + * class; use of identity-sensitive operations (including reference equality + * ({@code ==}), identity hash code, or synchronization) on any returned values + * may have unpredictable results and should be avoided. + * + * @param the key's type + * @param the value's type + * @param k the key + * @param v the value + * @return the new {@code Entry} + * @throws NullPointerException if the key or value is null + * + * @see Map#ofEntries Map.ofEntries() + * @since 9 + */ + static Entry entry(K k, V v) { + // KeyValueHolder checks for nulls + return new KeyValueHolder<>(k, v); + } } --- old/src/java.base/share/classes/java/util/Set.java 2015-11-23 22:03:12.000000000 -0800 +++ new/src/java.base/share/classes/java/util/Set.java 2015-11-23 22:03:12.000000000 -0800 @@ -63,6 +63,23 @@ * Such exceptions are marked as "optional" in the specification for this * interface. * + *

Immutable Set Static Factory Methods

+ *

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

    + *
  • They cannot be modified. Attempts to modify them result in + * an {@code UnsupportedOperationException}. + *
  • They are truly immutable only if the contained elements are themselves + * immutable. If an element is mutated, the behavior of the set is unspecified. + *
  • They disallow null elements. Attempts to create them with + * null elements result in {@code NullPointerException}. + *
  • They are serializable if all elements are serializable. + *
  • They reject duplicate elements at creation time. Duplicate elements + * passed to a static factory method result in {@code IllegalArgumentException}. + *
+ * *

This interface is a member of the * * Java Collections Framework. @@ -410,4 +427,342 @@ default Spliterator spliterator() { return Spliterators.spliterator(this, Spliterator.DISTINCT); } + + /** + * Creates an immutable set containing zero elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @return the newly created set + * + * @since 9 + */ + static Set of() { + return Collections.emptySet(); + } + + /** + * Creates an immutable set containing one element. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the single set element + * @return the newly created set + * @throws NullPointerException if the element is null + * + * @since 9 + */ + static Set of(E e1) { + return Collections.singleton(Objects.requireNonNull(e1)); + } + + /** + * Creates an immutable set containing two elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the first set element + * @param e2 the second set element + * @return the newly created set + * @throws IllegalArgumentException if the elements are duplicates + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static Set of(E e1, E e2) { + Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2))); + if (set.size() != 2) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } + + /** + * Creates an immutable set containing three elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the first set element + * @param e2 the second set element + * @param e3 the third set element + * @return the newly created set + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static Set of(E e1, E e2, E e3) { + Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3))); + if (set.size() != 3) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } + + /** + * Creates an immutable set containing four elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the first set element + * @param e2 the second set element + * @param e3 the third set element + * @param e4 the fourth set element + * @return the newly created set + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4) { + Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4))); + if (set.size() != 4) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } + + /** + * Creates an immutable set containing five elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the first set element + * @param e2 the second set element + * @param e3 the third set element + * @param e4 the fourth set element + * @param e5 the fifth set element + * @return the newly created set + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5) { + Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5))); + if (set.size() != 5) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } + + /** + * Creates an immutable set containing six elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the first set element + * @param e2 the second set element + * @param e3 the third set element + * @param e4 the fourth set element + * @param e5 the fifth set element + * @param e6 the sixth set element + * @return the newly created set + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5, E e6) { + Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6))); + if (set.size() != 6) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } + + /** + * Creates an immutable set containing seven elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the first set element + * @param e2 the second set element + * @param e3 the third set element + * @param e4 the fourth set element + * @param e5 the fifth set element + * @param e6 the sixth set element + * @param e7 the seventh set element + * @return the newly created set + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) { + Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6), + Objects.requireNonNull(e7))); + if (set.size() != 7) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } + + /** + * Creates an immutable set containing eight elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the first set element + * @param e2 the second set element + * @param e3 the third set element + * @param e4 the fourth set element + * @param e5 the fifth set element + * @param e6 the sixth set element + * @param e7 the seventh set element + * @param e8 the eighth set element + * @return the newly created set + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) { + Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6), + Objects.requireNonNull(e7), + Objects.requireNonNull(e8))); + if (set.size() != 8) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } + + /** + * Creates an immutable set containing nine elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the first set element + * @param e2 the second set element + * @param e3 the third set element + * @param e4 the fourth set element + * @param e5 the fifth set element + * @param e6 the sixth set element + * @param e7 the seventh set element + * @param e8 the eighth set element + * @param e9 the ninth set element + * @return the newly created set + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) { + Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6), + Objects.requireNonNull(e7), + Objects.requireNonNull(e8), + Objects.requireNonNull(e9))); + if (set.size() != 9) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } + + /** + * Creates an immutable set containing ten elements. + * See Immutable Set Static Factory Methods for details. + * + * @param the set's element type + * @param e1 the first set element + * @param e2 the second set element + * @param e3 the third set element + * @param e4 the fourth set element + * @param e5 the fifth set element + * @param e6 the sixth set element + * @param e7 the seventh set element + * @param e8 the eighth set element + * @param e9 the ninth set element + * @param e10 the tenth set element + * @return the newly created set + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is null + * + * @since 9 + */ + static Set of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) { + Set set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1), + Objects.requireNonNull(e2), + Objects.requireNonNull(e3), + Objects.requireNonNull(e4), + Objects.requireNonNull(e5), + Objects.requireNonNull(e6), + Objects.requireNonNull(e7), + Objects.requireNonNull(e8), + Objects.requireNonNull(e9), + Objects.requireNonNull(e10))); + if (set.size() != 10) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } + + /** + * Creates an immutable set containing an arbitrary number of elements. + * See Immutable Set Static Factory Methods for details. + * + * @apiNote + * This method also accepts a single array as an argument. The element type of + * the resulting set will be the component type of the array, and the size of + * the set will be equal to the length of the array. To create a set with + * a single element that is an array, do the following: + * + *

{@code
+     *     String[] array = ... ;
+     *     Set list = Set.of(array);
+     * }
+ * + * This will cause the {@link Set#of(Object) Set.of(E)} method + * to be invoked instead. + * + * @param the set's element type + * @param es the elements to be contained in the set + * @return the newly created set + * @throws IllegalArgumentException if there are any duplicate elements + * @throws NullPointerException if an element is null or if the array is null + * + * @since 9 + */ + @SafeVarargs + @SuppressWarnings("varargs") + static Set of(E... es) { + for (E e : es) { // throws NPE if es is null + Objects.requireNonNull(e); + } + // NOTE: this can allow a null element to slip through + Set set = new HashSet<>(Arrays.asList(es)); + if (set.size() != es.length) { + throw new IllegalArgumentException("duplicate elements"); + } + return Collections.unmodifiableSet(set); + } } --- old/test/java/util/Collection/MOAT.java 2015-11-23 22:03:13.000000000 -0800 +++ new/test/java/util/Collection/MOAT.java 2015-11-23 22:03:13.000000000 -0800 @@ -58,6 +58,21 @@ import java.lang.reflect.*; public class MOAT { + // Collections under test must not be initialized to contain this value, + // and maps under test must not contain this value as a key. + // It's used as a sentinel for absent-element testing. + static final int ABSENT_VALUE = 778347983; + + static final Integer[] integerArray; + static { + Integer[] ia = new Integer[20]; + // fill with 1..20 inclusive + for (int i = 0; i < ia.length; i++) { + ia[i] = i + 1; + } + integerArray = ia; + } + public static void realMain(String[] args) { testCollection(new NewAbstractCollection()); @@ -178,6 +193,70 @@ equal(singletonMap.size(), 1); testMap(singletonMap); testImmutableMap(singletonMap); + + // Unmodifiable List + testEmptyList(List.of()); + for (List list : Arrays.asList( + List.of(), + List.of(1), + List.of(1, 2), + List.of(1, 2, 3), + List.of(1, 2, 3, 4), + List.of(1, 2, 3, 4, 5), + List.of(1, 2, 3, 4, 5, 6), + List.of(1, 2, 3, 4, 5, 6, 7), + List.of(1, 2, 3, 4, 5, 6, 7, 8), + List.of(1, 2, 3, 4, 5, 6, 7, 8, 9), + List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), + List.of(integerArray))) { + testCollection(list); + testImmutableList(list); + } + + // Unmodifiable Set + testEmptySet(Set.of()); + for (Set set : Arrays.asList( + Set.of(), + Set.of(1), + Set.of(1, 2), + Set.of(1, 2, 3), + Set.of(1, 2, 3, 4), + Set.of(1, 2, 3, 4, 5), + Set.of(1, 2, 3, 4, 5, 6), + Set.of(1, 2, 3, 4, 5, 6, 7), + Set.of(1, 2, 3, 4, 5, 6, 7, 8), + Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9), + Set.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), + Set.of(integerArray))) { + testCollection(set); + testImmutableSet(set); + } + + // Unmodifiable Map + + @SuppressWarnings("unchecked") + Map.Entry[] ea = (Map.Entry[])new Map.Entry[20]; + for (int i = 0; i < ea.length; i++) { + ea[i] = Map.entry(i+1, i+101); + } + + testEmptyMap(Map.of()); + for (Map map : Arrays.asList( + Map.of(), + Map.of(1, 101), + Map.of(1, 101, 2, 202), + Map.of(1, 101, 2, 202, 3, 303), + Map.of(1, 101, 2, 202, 3, 303, 4, 404), + Map.of(1, 101, 2, 202, 3, 303, 4, 404, 5, 505), + Map.of(1, 101, 2, 202, 3, 303, 4, 404, 5, 505, 6, 606), + Map.of(1, 101, 2, 202, 3, 303, 4, 404, 5, 505, 6, 606, 7, 707), + Map.of(1, 101, 2, 202, 3, 303, 4, 404, 5, 505, 6, 606, 7, 707, 8, 808), + Map.of(1, 101, 2, 202, 3, 303, 4, 404, 5, 505, 6, 606, 7, 707, 8, 808, 9, 909), + Map.of(1, 101, 2, 202, 3, 303, 4, 404, 5, 505, 6, 606, 7, 707, 8, 808, 9, 909, 10, 1010), + Map.ofEntries(ea))) { + testMap(map); + testImmutableMap(map); + } } private static void checkContainsSelf(Collection c) { @@ -190,6 +269,17 @@ check(c.containsAll(new ArrayList())); } + private static void checkUnique(Set s) { + for (Integer i : s) { + int count = 0; + for (Integer j : s) { + if (Objects.equals(i,j)) + ++count; + } + check(count == 1); + } + } + private static void testEmptyCollection(Collection c) { check(c.isEmpty()); equal(c.size(), 0); @@ -330,19 +420,19 @@ } private static boolean supportsAdd(Collection c) { - try { check(c.add(778347983)); } + try { check(c.add(ABSENT_VALUE)); } catch (UnsupportedOperationException t) { return false; } catch (Throwable t) { unexpected(t); } try { - check(c.contains(778347983)); - check(c.remove(778347983)); + check(c.contains(ABSENT_VALUE)); + check(c.remove(ABSENT_VALUE)); } catch (Throwable t) { unexpected(t); } return true; } private static boolean supportsRemove(Collection c) { - try { check(! c.remove(19134032)); } + try { check(! c.remove(ABSENT_VALUE)); } catch (UnsupportedOperationException t) { return false; } catch (Throwable t) { unexpected(t); } return true; @@ -359,6 +449,7 @@ checkContainsSelf(c); checkContainsEmpty(c); check(c.size() != 0 ^ c.isEmpty()); + check(! c.contains(ABSENT_VALUE)); { int size = 0; @@ -366,6 +457,10 @@ check(c.size() == size); } + if (c instanceof Set) { + checkUnique((Set)c); + } + check(c.toArray().length == c.size()); check(c.toArray().getClass() == Object[].class || @@ -861,6 +956,20 @@ checkFunctionalInvariants(m.keySet()); checkFunctionalInvariants(m.values()); check(m.size() != 0 ^ m.isEmpty()); + check(! m.containsKey(ABSENT_VALUE)); + + if (m instanceof Serializable) { + //System.out.printf("Serializing %s%n", m.getClass().getName()); + try { + Object clone = serialClone(m); + equal(m instanceof Serializable, + clone instanceof Serializable); + equal(m, clone); + } catch (Error xxx) { + if (! (xxx.getCause() instanceof NotSerializableException)) + throw xxx; + } + } } private static void testMap(Map m) { @@ -910,13 +1019,13 @@ // We're asking for .equals(...) semantics if (m instanceof IdentityHashMap) return false; - try { check(m.put(778347983,12735) == null); } + try { check(m.put(ABSENT_VALUE,12735) == null); } catch (UnsupportedOperationException t) { return false; } catch (Throwable t) { unexpected(t); } try { - check(m.containsKey(778347983)); - check(m.remove(778347983) != null); + check(m.containsKey(ABSENT_VALUE)); + check(m.remove(ABSENT_VALUE) != null); } catch (Throwable t) { unexpected(t); } return true; } --- /dev/null 2015-11-23 22:03:15.000000000 -0800 +++ new/src/java.base/share/classes/java/util/KeyValueHolder.java 2015-11-23 22:03:14.000000000 -0800 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +/** + * An immutable container for a key and a value, suitable for use + * in creating and populating {@code Map} instances. + * + *

This is a value-based + * class; use of identity-sensitive operations (including reference equality + * ({@code ==}), identity hash code, or synchronization) on instances of + * {@code KeyValueHolder} may have unpredictable results and should be avoided. + * + * @apiNote + * This class is not public. Instances can be created using the + * {@link Map#entry Map.entry(k, v)} factory method, which is public. + * + * This class differs from AbstractMap.SimpleImmutableEntry in the following ways: + * it is not serializable, it is final, and its key and value must be non-null. + * + * @param the key type + * @param the value type + * + * @see Map#ofEntries Map.ofEntries() + * @since 9 + */ +final class KeyValueHolder implements Map.Entry { + final K key; + final V value; + + KeyValueHolder(K k, V v) { + key = Objects.requireNonNull(k); + value = Objects.requireNonNull(v); + } + + /** + * Gets the key from this holder. + * + * @return the key + */ + @Override + public K getKey() { + return key; + } + + /** + * Gets the value from this holder. + * + * @return the value + */ + @Override + public V getValue() { + return value; + } + + /** + * Throws {@link UnsupportedOperationException}. + * + * @param value ignored + * @return never returns normally + */ + @Override + public V setValue(V value) { + throw new UnsupportedOperationException("not supported"); + } + + /** + * Compares the specified object with this entry for equality. + * Returns {@code true} if the given object is also a map entry and + * the two entries' keys and values are equal. Note that key and + * value are non-null, so equals() can be called safely on them. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Map.Entry)) + return false; + Map.Entry e = (Map.Entry)o; + return key.equals(e.getKey()) && value.equals(e.getValue()); + } + + /** + * Returns the hash code value for this map entry. The hash code + * is {@code key.hashCode() ^ value.hashCode()}. Note that key and + * value are non-null, so hashCode() can be called safely on them. + */ + @Override + public int hashCode() { + return key.hashCode() ^ value.hashCode(); + } + + /** + * Returns a String representation of this map entry. This + * implementation returns the string representation of this + * entry's key followed by the equals character ("{@code =}") + * followed by the string representation of this entry's value. + * + * @return a String representation of this map entry + */ + @Override + public String toString() { + return key + "=" + value; + } +} --- /dev/null 2015-11-23 22:03:16.000000000 -0800 +++ new/test/java/util/Collection/SetFactories.java 2015-11-23 22:03:15.000000000 -0800 @@ -0,0 +1,275 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +/* + * @test + * @bug 8048330 + * @summary Test convenience static factory methods on Set. + * @run testng SetFactories + */ + + +public class SetFactories { + + static final int NUM_STRINGS = 20; // should be larger than the largest fixed-arg overload + static final String[] stringArray; + static { + String[] sa = new String[NUM_STRINGS]; + for (int i = 0; i < NUM_STRINGS; i++) { + sa[i] = String.valueOf((char)('a' + i)); + } + stringArray = sa; + } + + static Object[] a(Set act, Set exp) { + return new Object[] { act, exp }; + } + + static Set hashSetOf(String... args) { + return new HashSet<>(Arrays.asList(args)); + } + + @DataProvider(name="empty") + public Iterator empty() { + return Collections.singletonList( + // actual, expected + a(Set.of(), Collections.emptySet()) + ).iterator(); + } + + @DataProvider(name="nonempty") + public Iterator nonempty() { + return Arrays.asList( + // actual, expected + a( Set.of("a"), + hashSetOf("a")), + a( Set.of("a", "b"), + hashSetOf("a", "b")), + a( Set.of("a", "b", "c"), + hashSetOf("a", "b", "c")), + a( Set.of("a", "b", "c", "d"), + hashSetOf("a", "b", "c", "d")), + a( Set.of("a", "b", "c", "d", "e"), + hashSetOf("a", "b", "c", "d", "e")), + a( Set.of("a", "b", "c", "d", "e", "f"), + hashSetOf("a", "b", "c", "d", "e", "f")), + a( Set.of("a", "b", "c", "d", "e", "f", "g"), + hashSetOf("a", "b", "c", "d", "e", "f", "g")), + a( Set.of("a", "b", "c", "d", "e", "f", "g", "h"), + hashSetOf("a", "b", "c", "d", "e", "f", "g", "h")), + a( Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i"), + hashSetOf("a", "b", "c", "d", "e", "f", "g", "h", "i")), + a( Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), + hashSetOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")), + a( Set.of(stringArray), + hashSetOf(stringArray)) + ).iterator(); + } + + @DataProvider(name="all") + public Iterator all() { + List all = new ArrayList<>(); + empty().forEachRemaining(all::add); + nonempty().forEachRemaining(all::add); + return all.iterator(); + } + + @Test(dataProvider="all", expectedExceptions=UnsupportedOperationException.class) + public void cannotAdd(Set act, Set exp) { + act.add("x"); + } + + @Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class) + public void cannotRemove(Set act, Set exp) { + act.remove(act.iterator().next()); + } + + @Test(dataProvider="all") + public void contentsMatch(Set act, Set exp) { + assertEquals(act, exp); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowed2() { + Set set = Set.of("a", "a"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowed3() { + Set set = Set.of("a", "b", "a"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowed4() { + Set set = Set.of("a", "b", "c", "a"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowed5() { + Set set = Set.of("a", "b", "c", "d", "a"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowed6() { + Set set = Set.of("a", "b", "c", "d", "e", "a"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowed7() { + Set set = Set.of("a", "b", "c", "d", "e", "f", "a"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowed8() { + Set set = Set.of("a", "b", "c", "d", "e", "f", "g", "a"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowed9() { + Set set = Set.of("a", "b", "c", "d", "e", "f", "g", "h", "a"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowed10() { + Set set = Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "a"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupsDisallowedN() { + String[] array = stringArray.clone(); + array[0] = array[1]; + Set set = Set.of(array); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed1() { + Set.of((String)null); // force one-arg overload + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed2a() { + Set.of("a", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed2b() { + Set.of(null, "b"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed3() { + Set.of("a", "b", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed4() { + Set.of("a", "b", "c", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed5() { + Set.of("a", "b", "c", "d", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed6() { + Set.of("a", "b", "c", "d", "e", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed7() { + Set.of("a", "b", "c", "d", "e", "f", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed8() { + Set.of("a", "b", "c", "d", "e", "f", "g", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed9() { + Set.of("a", "b", "c", "d", "e", "f", "g", "h", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed10() { + Set.of("a", "b", "c", "d", "e", "f", "g", "h", "i", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowedN() { + String[] array = stringArray.clone(); + array[0] = null; + Set.of(array); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullArrayDisallowed() { + Set.of((Object[])null); + } + + @Test(dataProvider="all") + public void serialEquality(Set act, Set exp) { + // assume that act.equals(exp) tested elsewhere + Set copy = serialClone(act); + assertEquals(act, copy); + assertEquals(copy, exp); + } + + @SuppressWarnings("unchecked") + static T serialClone(T obj) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(obj); + oos.close(); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + return (T) ois.readObject(); + } catch (IOException | ClassNotFoundException e) { + throw new AssertionError(e); + } + } +} --- /dev/null 2015-11-23 22:03:17.000000000 -0800 +++ new/test/java/util/List/ListFactories.java 2015-11-23 22:03:16.000000000 -0800 @@ -0,0 +1,234 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static java.util.Arrays.asList; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +/* + * @test + * @bug 8048330 + * @summary Test convenience static factory methods on List. + * @run testng ListFactories + */ + +public class ListFactories { + + static final int NUM_STRINGS = 20; // should be larger than the largest fixed-arg overload + static final String[] stringArray; + static { + String[] sa = new String[NUM_STRINGS]; + for (int i = 0; i < NUM_STRINGS; i++) { + sa[i] = String.valueOf((char)('a' + i)); + } + stringArray = sa; + } + + // returns array of [actual, expected] + static Object[] a(List act, List exp) { + return new Object[] { act, exp }; + } + + @DataProvider(name="empty") + public Iterator empty() { + return Collections.singletonList( + a(List.of(), Collections.emptyList()) + ).iterator(); + } + + @DataProvider(name="nonempty") + public Iterator nonempty() { + return asList( + a(List.of("a"), + asList("a")), + a(List.of("a", "b"), + asList("a", "b")), + a(List.of("a", "b", "c"), + asList("a", "b", "c")), + a(List.of("a", "b", "c", "d"), + asList("a", "b", "c", "d")), + a(List.of("a", "b", "c", "d", "e"), + asList("a", "b", "c", "d", "e")), + a(List.of("a", "b", "c", "d", "e", "f"), + asList("a", "b", "c", "d", "e", "f")), + a(List.of("a", "b", "c", "d", "e", "f", "g"), + asList("a", "b", "c", "d", "e", "f", "g")), + a(List.of("a", "b", "c", "d", "e", "f", "g", "h"), + asList("a", "b", "c", "d", "e", "f", "g", "h")), + a(List.of("a", "b", "c", "d", "e", "f", "g", "h", "i"), + asList("a", "b", "c", "d", "e", "f", "g", "h", "i")), + a(List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), + asList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")), + a(List.of(stringArray), + asList(stringArray)) + ).iterator(); + } + + @DataProvider(name="all") + public Iterator all() { + List all = new ArrayList<>(); + empty().forEachRemaining(all::add); + nonempty().forEachRemaining(all::add); + return all.iterator(); + } + + @Test(dataProvider="all", expectedExceptions=UnsupportedOperationException.class) + public void cannotAddLast(List act, List exp) { + act.add("x"); + } + + @Test(dataProvider="all", expectedExceptions=UnsupportedOperationException.class) + public void cannotAddFirst(List act, List exp) { + act.add(0, "x"); + } + + @Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class) + public void cannotRemove(List act, List exp) { + act.remove(0); + } + + @Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class) + public void cannotSet(List act, List exp) { + act.set(0, "x"); + } + + @Test(dataProvider="all") + public void contentsMatch(List act, List exp) { + assertEquals(act, exp); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed1() { + List.of((Object)null); // force one-arg overload + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed2a() { + List.of("a", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed2b() { + List.of(null, "b"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed3() { + List.of("a", "b", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed4() { + List.of("a", "b", "c", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed5() { + List.of("a", "b", "c", "d", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed6() { + List.of("a", "b", "c", "d", "e", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed7() { + List.of("a", "b", "c", "d", "e", "f", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed8() { + List.of("a", "b", "c", "d", "e", "f", "g", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed9() { + List.of("a", "b", "c", "d", "e", "f", "g", "h", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowed10() { + List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullDisallowedN() { + String[] array = stringArray.clone(); + array[0] = null; + List.of(array); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullArrayDisallowed() { + List.of((Object[])null); + } + + @Test + public void ensureArrayCannotModifyList() { + String[] array = stringArray.clone(); + List list = List.of(array); + array[0] = "xyzzy"; + assertEquals(list, Arrays.asList(stringArray)); + } + + @Test(dataProvider="all") + public void serialEquality(List act, List exp) { + // assume that act.equals(exp) tested elsewhere + List copy = serialClone(act); + assertEquals(act, copy); + assertEquals(copy, exp); + } + + @SuppressWarnings("unchecked") + static T serialClone(T obj) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(obj); + oos.close(); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + return (T) ois.readObject(); + } catch (IOException | ClassNotFoundException e) { + throw new AssertionError(e); + } + } +} --- /dev/null 2015-11-23 22:03:18.000000000 -0800 +++ new/test/java/util/Map/MapFactories.java 2015-11-23 22:03:18.000000000 -0800 @@ -0,0 +1,380 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +/* + * @test + * @bug 8048330 + * @summary Test convenience static factory methods on Map. + * @run testng MapFactories + */ + +public class MapFactories { + + static final int MAX_ENTRIES = 20; // should be larger than the largest fixed-arg overload + static String valueFor(int i) { + // the String literal below should be of length MAX_ENTRIES + return "abcdefghijklmnopqrst".substring(i, i+1); + } + + // for "expected" values + Map genMap(int n) { + Map result = new HashMap<>(); + for (int i = 0; i < n; i++) { + result.put(i, valueFor(i)); + } + return result; + } + + // for varargs Map.Entry methods + @SuppressWarnings("unchecked") + Map.Entry[] genEntries(int n) { + return IntStream.range(0, n) + .mapToObj(i -> Map.entry(i, valueFor(i))) + .toArray(len -> (Map.Entry[])(new Map.Entry[len])); + } + + // returns array of [actual, expected] + static Object[] a(Map act, Map exp) { + return new Object[] { act, exp }; + } + + @DataProvider(name="empty") + public Iterator empty() { + return Collections.singletonList( + a(Map.of(), genMap(0)) + ).iterator(); + } + + @DataProvider(name="nonempty") + @SuppressWarnings("unchecked") + public Iterator nonempty() { + return Arrays.asList( + a(Map.of(0, "a"), genMap(1)), + a(Map.of(0, "a", 1, "b"), genMap(2)), + a(Map.of(0, "a", 1, "b", 2, "c"), genMap(3)), + a(Map.of(0, "a", 1, "b", 2, "c", 3, "d"), genMap(4)), + a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e"), genMap(5)), + a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f"), genMap(6)), + a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g"), genMap(7)), + a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h"), genMap(8)), + a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i"), genMap(9)), + a(Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j"), genMap(10)), + a(Map.ofEntries(genEntries(MAX_ENTRIES)), genMap(MAX_ENTRIES)) + ).iterator(); + } + + @DataProvider(name="all") + public Iterator all() { + List all = new ArrayList<>(); + empty().forEachRemaining(all::add); + nonempty().forEachRemaining(all::add); + return all.iterator(); + } + + @Test(dataProvider="all", expectedExceptions=UnsupportedOperationException.class) + public void cannotPutNew(Map act, Map exp) { + act.put(-1, "xyzzy"); + } + + @Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class) + public void cannotPutOld(Map act, Map exp) { + act.put(0, "a"); + } + + @Test(dataProvider="nonempty", expectedExceptions=UnsupportedOperationException.class) + public void cannotRemove(Map act, Map exp) { + act.remove(act.keySet().iterator().next()); + } + + @Test(dataProvider="all") + public void contentsMatch(Map act, Map exp) { + assertEquals(act, exp); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowed2() { + Map map = Map.of(0, "a", 0, "b"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowed3() { + Map map = Map.of(0, "a", 1, "b", 0, "c"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowed4() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 0, "d"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowed5() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 0, "e"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowed6() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 0, "f"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowed7() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 0, "g"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowed8() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, "g", 0, "h"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowed9() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, "g", 7, "h", 0, "i"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowed10() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, "g", 7, "h", 8, "i", 0, "j"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void dupKeysDisallowedN() { + Map.Entry[] entries = genEntries(MAX_ENTRIES); + entries[MAX_ENTRIES-1] = Map.entry(0, "xxx"); + Map map = Map.ofEntries(entries); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed1() { + Map map = Map.of(null, "a"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed1() { + Map map = Map.of(0, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed2() { + Map map = Map.of(0, "a", null, "b"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed2() { + Map map = Map.of(0, "a", 1, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed3() { + Map map = Map.of(0, "a", 1, "b", null, "c"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed3() { + Map map = Map.of(0, "a", 1, "b", 2, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed4() { + Map map = Map.of(0, "a", 1, "b", 2, "c", null, "d"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed4() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed5() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", null, "e"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed5() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed6() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + null, "f"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed6() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed7() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", null, "g"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed7() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed8() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, "g", null, "h"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed8() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, "g", 7, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed9() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, "g", 7, "h", null, "i"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed9() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, "g", 7, "h", 8, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowed10() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, "g", 7, "h", 8, "i", null, "j"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowed10() { + Map map = Map.of(0, "a", 1, "b", 2, "c", 3, "d", 4, "e", + 5, "f", 6, "g", 7, "h", 8, "i", 9, null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullKeyDisallowedN() { + Map.Entry[] entries = genEntries(MAX_ENTRIES); + entries[0] = new AbstractMap.SimpleImmutableEntry(null, "a"); + Map map = Map.ofEntries(entries); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullValueDisallowedN() { + Map.Entry[] entries = genEntries(MAX_ENTRIES); + entries[0] = new AbstractMap.SimpleImmutableEntry(0, null); + Map map = Map.ofEntries(entries); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullEntryDisallowedN() { + Map.Entry[] entries = genEntries(MAX_ENTRIES); + entries[5] = null; + Map map = Map.ofEntries(entries); + } + + @Test(expectedExceptions=NullPointerException.class) + public void nullArrayDisallowed() { + Map.ofEntries(null); + } + + @Test(dataProvider="all") + public void serialEquality(Map act, Map exp) { + // assume that act.equals(exp) tested elsewhere + Map copy = serialClone(act); + assertEquals(act, copy); + assertEquals(copy, exp); + } + + @SuppressWarnings("unchecked") + static T serialClone(T obj) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(obj); + oos.close(); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + return (T) ois.readObject(); + } catch (IOException | ClassNotFoundException e) { + throw new AssertionError(e); + } + } + + // Map.entry() tests + + @Test(expectedExceptions=NullPointerException.class) + public void entryWithNullKeyDisallowed() { + Map.Entry e = Map.entry(null, "x"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void entryWithNullValueDisallowed() { + Map.Entry e = Map.entry(0, null); + } + + @Test + public void entryBasicTests() { + Map.Entry kvh1 = Map.entry("xyzzy", "plugh"); + Map.Entry kvh2 = Map.entry("foobar", "blurfl"); + Map.Entry sie = new AbstractMap.SimpleImmutableEntry("xyzzy", "plugh"); + + assertTrue(kvh1.equals(sie)); + assertTrue(sie.equals(kvh1)); + assertFalse(kvh2.equals(sie)); + assertFalse(sie.equals(kvh2)); + assertEquals(sie.hashCode(), kvh1.hashCode()); + assertEquals(sie.toString(), kvh1.toString()); + } + +}