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
This commit is contained in:
parent
6d82950756
commit
f4db9575d1
@ -54,19 +54,15 @@ import java.util.stream.StreamSupport;
|
||||
* constructors) but all of the general-purpose {@code Collection}
|
||||
* implementations in the Java platform libraries comply.
|
||||
*
|
||||
* <p>The "destructive" methods contained in this interface, that is, the
|
||||
* methods that modify the collection on which they operate, are specified to
|
||||
* throw {@code UnsupportedOperationException} if this collection does not
|
||||
* support the operation. If this is the case, these methods may, but are not
|
||||
* required to, throw an {@code UnsupportedOperationException} if the
|
||||
* invocation would have no effect on the collection. For example, invoking
|
||||
* the {@link #addAll(Collection)} method on an unmodifiable collection may,
|
||||
* but is not required to, throw the exception if the collection to be added
|
||||
* is empty.
|
||||
* <p>Certain methods are specified to be
|
||||
* <i>optional</i>. If a collection implementation doesn't implement a
|
||||
* particular operation, it should define the corresponding method to throw
|
||||
* {@code UnsupportedOperationException}. Such methods are marked "optional
|
||||
* operation" in method specifications of the collections interfaces.
|
||||
*
|
||||
* <p><a id="optional-restrictions">
|
||||
* Some collection implementations have restrictions on the elements that
|
||||
* they may contain.</a> For example, some implementations prohibit null elements,
|
||||
* <p><a id="optional-restrictions"></a>Some collection implementations
|
||||
* have restrictions on the elements that they may contain.
|
||||
* For example, some implementations prohibit null elements,
|
||||
* and some have restrictions on the types of their elements. Attempting to
|
||||
* add an ineligible element throws an unchecked exception, typically
|
||||
* {@code NullPointerException} or {@code ClassCastException}. Attempting
|
||||
@ -111,6 +107,86 @@ import java.util.stream.StreamSupport;
|
||||
* methods. Implementations may optionally handle the self-referential scenario,
|
||||
* however most current implementations do not do so.
|
||||
*
|
||||
* <h2><a id="view">View Collections</a></h2>
|
||||
*
|
||||
* <p>Most collections manage storage for elements they contain. By contrast, <i>view
|
||||
* collections</i> themselves do not store elements, but instead they rely on a
|
||||
* backing collection to store the actual elements. Operations that are not handled
|
||||
* by the view collection itself are delegated to the backing collection. Examples of
|
||||
* view collections include the wrapper collections returned by methods such as
|
||||
* {@link Collections#checkedCollection Collections.checkedCollection},
|
||||
* {@link Collections#synchronizedCollection Collections.synchronizedCollection}, and
|
||||
* {@link Collections#unmodifiableCollection Collections.unmodifiableCollection}.
|
||||
* Other examples of view collections include collections that provide a
|
||||
* different representation of the same elements, for example, as
|
||||
* provided by {@link List#subList List.subList},
|
||||
* {@link NavigableSet#subSet NavigableSet.subSet}, or
|
||||
* {@link Map#entrySet Map.entrySet}.
|
||||
* Any changes made to the backing collection are visible in the view collection.
|
||||
* Correspondingly, any changes made to the view collection — if changes
|
||||
* are permitted — are written through to the backing collection.
|
||||
* Although they technically aren't collections, instances of
|
||||
* {@link Iterator} and {@link ListIterator} can also allow modifications
|
||||
* to be written through to the backing collection, and in some cases,
|
||||
* modifications to the backing collection will be visible to the Iterator
|
||||
* during iteration.
|
||||
*
|
||||
* <h2><a id="unmodifiable">Unmodifiable Collections</a></h2>
|
||||
*
|
||||
* <p>Certain methods of this interface are considered "destructive" and are called
|
||||
* "mutator" methods in that they modify the group of objects contained within
|
||||
* the collection on which they operate. They can be specified to throw
|
||||
* {@code UnsupportedOperationException} if this collection implementation
|
||||
* does not support the operation. Such methods should (but are not required
|
||||
* to) throw an {@code UnsupportedOperationException} if the invocation would
|
||||
* have no effect on the collection. For example, consider a collection that
|
||||
* does not support the {@link #add add} operation. What will happen if the
|
||||
* {@link #addAll addAll} method is invoked on this collection, with an empty
|
||||
* collection as the argument? The addition of zero elements has no effect,
|
||||
* so it is permissible for this collection simply to do nothing and not to throw
|
||||
* an exception. However, it is recommended that such cases throw an exception
|
||||
* unconditionally, as throwing only in certain cases can lead to
|
||||
* programming errors.
|
||||
*
|
||||
* <p>An <i>unmodifiable collection</i> is a collection, all of whose
|
||||
* mutator methods (as defined above) are specified to throw
|
||||
* {@code UnsupportedOperationException}. Such a collection thus cannot be
|
||||
* modified by calling any methods on it. For a collection to be properly
|
||||
* unmodifiable, any view collections derived from it must also be unmodifiable.
|
||||
* For example, if a List is unmodifiable, the List returned by
|
||||
* {@link List#subList List.subList} is also unmodifiable.
|
||||
*
|
||||
* <p>An unmodifiable collection is not necessarily immutable. If the
|
||||
* contained elements are mutable, the entire collection is clearly
|
||||
* mutable, even though it might be unmodifiable. For example, consider
|
||||
* two unmodifiable lists containing mutable elements. The result of calling
|
||||
* {@code list1.equals(list2)} might differ from one call to the next if
|
||||
* the elements had been mutated, even though both lists are unmodifiable.
|
||||
* However, if an unmodifiable collection contains all immutable elements,
|
||||
* it can be considered effectively immutable.
|
||||
*
|
||||
* <h2><a id="unmodview">Unmodifiable View Collections</a></h2>
|
||||
*
|
||||
* <p>An <i>unmodifiable view collection</i> is a collection that is unmodifiable
|
||||
* and that is also a view onto a backing collection. Its mutator methods throw
|
||||
* {@code UnsupportedOperationException}, as described above, while
|
||||
* reading and querying methods are delegated to the backing collection.
|
||||
* The effect is to provide read-only access to the backing collection.
|
||||
* This is useful for a component to provide users with read access to
|
||||
* an internal collection, while preventing them from modifying such
|
||||
* collections unexpectedly. Examples of unmodifiable view collections
|
||||
* are those returned by the
|
||||
* {@link Collections#unmodifiableCollection Collections.unmodifiableCollection},
|
||||
* {@link Collections#unmodifiableList Collections.unmodifiableList}, and
|
||||
* related methods.
|
||||
*
|
||||
* <p>Note that changes to the backing collection might still be possible,
|
||||
* and if they occur, they are visible through the unmodifiable view. Thus,
|
||||
* an unmodifiable view collection is not necessarily immutable. However,
|
||||
* if the backing collection of an unmodifiable view is effectively immutable,
|
||||
* or if the only reference to the backing collection is through an
|
||||
* unmodifiable view, the view can be considered effectively immutable.
|
||||
*
|
||||
* <p>This interface is a member of the
|
||||
* <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
|
||||
* Java Collections Framework</a>.
|
||||
|
@ -989,9 +989,8 @@ public class Collections {
|
||||
// Unmodifiable Wrappers
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view of the specified collection. This method
|
||||
* allows modules to provide users with "read-only" access to internal
|
||||
* collections. Query operations on the returned collection "read through"
|
||||
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
|
||||
* specified collection. Query operations on the returned collection "read through"
|
||||
* to the specified collection, and attempts to modify the returned
|
||||
* collection, whether direct or via its iterator, result in an
|
||||
* {@code UnsupportedOperationException}.<p>
|
||||
@ -1102,9 +1101,8 @@ public class Collections {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view of the specified set. This method allows
|
||||
* modules to provide users with "read-only" access to internal sets.
|
||||
* Query operations on the returned set "read through" to the specified
|
||||
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
|
||||
* specified set. Query operations on the returned set "read through" to the specified
|
||||
* set, and attempts to modify the returned set, whether direct or via its
|
||||
* iterator, result in an {@code UnsupportedOperationException}.<p>
|
||||
*
|
||||
@ -1132,9 +1130,8 @@ public class Collections {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view of the specified sorted set. This method
|
||||
* allows modules to provide users with "read-only" access to internal
|
||||
* sorted sets. Query operations on the returned sorted set "read
|
||||
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
|
||||
* specified sorted set. Query operations on the returned sorted set "read
|
||||
* through" to the specified sorted set. Attempts to modify the returned
|
||||
* sorted set, whether direct, via its iterator, or via its
|
||||
* {@code subSet}, {@code headSet}, or {@code tailSet} views, result in
|
||||
@ -1180,9 +1177,8 @@ public class Collections {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view of the specified navigable set. This method
|
||||
* allows modules to provide users with "read-only" access to internal
|
||||
* navigable sets. Query operations on the returned navigable set "read
|
||||
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
|
||||
* specified navigable set. Query operations on the returned navigable set "read
|
||||
* through" to the specified navigable set. Attempts to modify the returned
|
||||
* navigable set, whether direct, via its iterator, or via its
|
||||
* {@code subSet}, {@code headSet}, or {@code tailSet} views, result in
|
||||
@ -1269,9 +1265,8 @@ public class Collections {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view of the specified list. This method allows
|
||||
* modules to provide users with "read-only" access to internal
|
||||
* lists. Query operations on the returned list "read through" to the
|
||||
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
|
||||
* specified list. Query operations on the returned list "read through" to the
|
||||
* specified list, and attempts to modify the returned list, whether
|
||||
* direct or via its iterator, result in an
|
||||
* {@code UnsupportedOperationException}.<p>
|
||||
@ -1415,9 +1410,8 @@ public class Collections {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view of the specified map. This method
|
||||
* allows modules to provide users with "read-only" access to internal
|
||||
* maps. Query operations on the returned map "read through"
|
||||
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
|
||||
* specified map. Query operations on the returned map "read through"
|
||||
* to the specified map, and attempts to modify the returned
|
||||
* map, whether direct or via its collection views, result in an
|
||||
* {@code UnsupportedOperationException}.<p>
|
||||
@ -1765,9 +1759,8 @@ public class Collections {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view of the specified sorted map. This method
|
||||
* allows modules to provide users with "read-only" access to internal
|
||||
* sorted maps. Query operations on the returned sorted map "read through"
|
||||
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
|
||||
* specified sorted map. Query operations on the returned sorted map "read through"
|
||||
* to the specified sorted map. Attempts to modify the returned
|
||||
* sorted map, whether direct, via its collection views, or via its
|
||||
* {@code subMap}, {@code headMap}, or {@code tailMap} views, result in
|
||||
@ -1809,9 +1802,8 @@ public class Collections {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable view of the specified navigable map. This method
|
||||
* allows modules to provide users with "read-only" access to internal
|
||||
* navigable maps. Query operations on the returned navigable map "read
|
||||
* Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
|
||||
* specified navigable map. Query operations on the returned navigable map "read
|
||||
* through" to the specified navigable map. Attempts to modify the returned
|
||||
* navigable map, whether direct, via its collection views, or via its
|
||||
* {@code subMap}, {@code headMap}, or {@code tailMap} views, result in
|
||||
|
@ -87,15 +87,16 @@ import java.util.function.UnaryOperator;
|
||||
* Such exceptions are marked as "optional" in the specification for this
|
||||
* interface.
|
||||
*
|
||||
* <h2><a id="immutable">Immutable List Static Factory Methods</a></h2>
|
||||
* <p>The {@link List#of(Object...) List.of()} static factory methods
|
||||
* provide a convenient way to create immutable lists. The {@code List}
|
||||
* <h2><a id="unmodifiable">Unmodifiable Lists</a></h2>
|
||||
* <p>The {@link List#of(Object...) List.of} and
|
||||
* {@link List#copyOf List.copyOf} static factory methods
|
||||
* provide a convenient way to create unmodifiable lists. The {@code List}
|
||||
* instances created by these methods have the following characteristics:
|
||||
*
|
||||
* <ul>
|
||||
* <li>They are <em>structurally immutable</em>. Elements cannot be added, removed,
|
||||
* or replaced. Calling any mutator method will always cause
|
||||
* {@code UnsupportedOperationException} to be thrown.
|
||||
* <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Elements cannot
|
||||
* be added, removed, or replaced. Calling any mutator method on the List
|
||||
* will always cause {@code UnsupportedOperationException} to be thrown.
|
||||
* However, if the contained elements are themselves mutable,
|
||||
* this may cause the List's contents to appear to change.
|
||||
* <li>They disallow {@code null} elements. Attempts to create them with
|
||||
@ -777,9 +778,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing zero elements.
|
||||
* Returns an unmodifiable list containing zero elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @return an empty {@code List}
|
||||
@ -791,9 +792,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing one element.
|
||||
* Returns an unmodifiable list containing one element.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the single element
|
||||
@ -807,9 +808,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing two elements.
|
||||
* Returns an unmodifiable list containing two elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the first element
|
||||
@ -824,9 +825,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing three elements.
|
||||
* Returns an unmodifiable list containing three elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the first element
|
||||
@ -842,9 +843,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing four elements.
|
||||
* Returns an unmodifiable list containing four elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the first element
|
||||
@ -861,9 +862,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing five elements.
|
||||
* Returns an unmodifiable list containing five elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the first element
|
||||
@ -881,9 +882,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing six elements.
|
||||
* Returns an unmodifiable list containing six elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the first element
|
||||
@ -903,9 +904,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing seven elements.
|
||||
* Returns an unmodifiable list containing seven elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the first element
|
||||
@ -926,9 +927,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing eight elements.
|
||||
* Returns an unmodifiable list containing eight elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the first element
|
||||
@ -950,9 +951,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing nine elements.
|
||||
* Returns an unmodifiable list containing nine elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the first element
|
||||
@ -975,9 +976,9 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing ten elements.
|
||||
* Returns an unmodifiable list containing ten elements.
|
||||
*
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param e1 the first element
|
||||
@ -1001,8 +1002,8 @@ public interface List<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable list containing an arbitrary number of elements.
|
||||
* See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable list containing an arbitrary number of elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
|
||||
*
|
||||
* @apiNote
|
||||
* This method also accepts a single array as an argument. The element type of
|
||||
@ -1039,4 +1040,29 @@ public interface List<E> extends Collection<E> {
|
||||
return new ImmutableCollections.ListN<>(elements);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <a href="#unmodifiable">unmodifiable List</a> containing the elements of
|
||||
* the given Collection, in its iteration order. The given Collection must not be null,
|
||||
* and it must not contain any null elements. If the given Collection is subsequently
|
||||
* modified, the returned List will not reflect such modifications.
|
||||
*
|
||||
* @implNote
|
||||
* If the given Collection is an <a href="#unmodifiable">unmodifiable List</a>,
|
||||
* calling copyOf will generally not create a copy.
|
||||
*
|
||||
* @param <E> the {@code List}'s element type
|
||||
* @param coll a {@code Collection} from which elements are drawn, must be non-null
|
||||
* @return a {@code List} containing the elements of the given {@code Collection}
|
||||
* @throws NullPointerException if coll is null, or if it contains any nulls
|
||||
* @since 10
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <E> List<E> copyOf(Collection<? extends E> coll) {
|
||||
if (coll instanceof ImmutableCollections.AbstractImmutableList) {
|
||||
return (List<E>)coll;
|
||||
} else {
|
||||
return (List<E>)List.of(coll.toArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,17 +110,18 @@ import java.io.Serializable;
|
||||
* 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.
|
||||
* <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 <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.
|
||||
* <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
|
||||
@ -1276,8 +1277,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing zero mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1290,8 +1291,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing a single mapping.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1307,8 +1308,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing two mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1327,8 +1328,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing three mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1349,8 +1350,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing four mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1373,8 +1374,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing five mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1399,8 +1400,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing six mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1429,8 +1430,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing seven mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1461,8 +1462,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing eight mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1495,8 +1496,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing nine mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1531,8 +1532,8 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing ten mappings.
|
||||
* See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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
|
||||
@ -1569,9 +1570,9 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable map containing keys and values extracted from the given entries.
|
||||
* 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="#immutable">Immutable Map Static Factory Methods</a> for details.
|
||||
* 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.
|
||||
@ -1602,15 +1603,17 @@ public interface Map<K, V> {
|
||||
@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
|
||||
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();
|
||||
}
|
||||
@ -1619,7 +1622,7 @@ public interface Map<K, V> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable {@link Entry} containing the given key and value.
|
||||
* 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:
|
||||
@ -1627,7 +1630,7 @@ public interface Map<K, V> {
|
||||
* <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()}
|
||||
* <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>.
|
||||
@ -1655,4 +1658,30 @@ public interface Map<K, 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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,15 +63,16 @@ package java.util;
|
||||
* Such exceptions are marked as "optional" in the specification for this
|
||||
* interface.
|
||||
*
|
||||
* <h2><a id="immutable">Immutable Set Static Factory Methods</a></h2>
|
||||
* <p>The {@link Set#of(Object...) Set.of()} static factory methods
|
||||
* provide a convenient way to create immutable sets. The {@code Set}
|
||||
* <h2><a id="unmodifiable">Unmodifiable Sets</a></h2>
|
||||
* <p>The {@link Set#of(Object...) Set.of} and
|
||||
* {@link Set#copyOf Set.copyOf} static factory methods
|
||||
* provide a convenient way to create unmodifiable sets. The {@code Set}
|
||||
* instances created by these methods have the following characteristics:
|
||||
*
|
||||
* <ul>
|
||||
* <li>They are <em>structurally immutable</em>. Elements cannot be added or
|
||||
* removed. Calling any mutator method will always cause
|
||||
* {@code UnsupportedOperationException} to be thrown.
|
||||
* <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Elements cannot
|
||||
* be added or removed. Calling any mutator method on the Set
|
||||
* will always cause {@code UnsupportedOperationException} to be thrown.
|
||||
* However, if the contained elements are themselves mutable, this may cause the
|
||||
* Set to behave inconsistently or its contents to appear to change.
|
||||
* <li>They disallow {@code null} elements. Attempts to create them with
|
||||
@ -439,8 +440,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing zero elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing zero elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @return an empty {@code Set}
|
||||
@ -452,8 +453,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing one element.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing one element.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the single element
|
||||
@ -467,8 +468,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing two elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing two elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the first element
|
||||
@ -484,8 +485,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing three elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing three elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the first element
|
||||
@ -502,8 +503,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing four elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing four elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the first element
|
||||
@ -521,8 +522,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing five elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing five elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the first element
|
||||
@ -541,8 +542,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing six elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing six elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the first element
|
||||
@ -563,8 +564,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing seven elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing seven elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the first element
|
||||
@ -586,8 +587,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing eight elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing eight elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the first element
|
||||
@ -610,8 +611,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing nine elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing nine elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the first element
|
||||
@ -635,8 +636,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing ten elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing ten elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param e1 the first element
|
||||
@ -661,8 +662,8 @@ public interface Set<E> extends Collection<E> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable set containing an arbitrary number of elements.
|
||||
* See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
|
||||
* Returns an unmodifiable set containing an arbitrary number of elements.
|
||||
* See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
|
||||
*
|
||||
* @apiNote
|
||||
* This method also accepts a single array as an argument. The element type of
|
||||
@ -700,4 +701,30 @@ public interface Set<E> extends Collection<E> {
|
||||
return new ImmutableCollections.SetN<>(elements);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <a href="#unmodifiable">unmodifiable Set</a> containing the elements
|
||||
* of the given Collection. The given Collection must not be null, and it must not
|
||||
* contain any null elements. If the given Collection contains duplicate elements,
|
||||
* an arbitrary element of the duplicates is preserved. If the given Collection is
|
||||
* subsequently modified, the returned Set will not reflect such modifications.
|
||||
*
|
||||
* @implNote
|
||||
* If the given Collection is an <a href="#unmodifiable">unmodifiable Set</a>,
|
||||
* calling copyOf will generally not create a copy.
|
||||
*
|
||||
* @param <E> the {@code Set}'s element type
|
||||
* @param coll a {@code Collection} from which elements are drawn, must be non-null
|
||||
* @return a {@code Set} containing the elements of the given {@code Collection}
|
||||
* @throws NullPointerException if coll is null, or if it contains any nulls
|
||||
* @since 10
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <E> Set<E> copyOf(Collection<? extends E> coll) {
|
||||
if (coll instanceof ImmutableCollections.AbstractImmutableSet) {
|
||||
return (Set<E>)coll;
|
||||
} else {
|
||||
return (Set<E>)Set.of(new HashSet<>(coll).toArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2017, 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
|
||||
@ -116,6 +116,8 @@ public final class Collectors {
|
||||
= Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
|
||||
Collector.Characteristics.IDENTITY_FINISH));
|
||||
static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
|
||||
static final Set<Collector.Characteristics> CH_UNORDERED_NOID
|
||||
= Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED));
|
||||
|
||||
private Collectors() { }
|
||||
|
||||
@ -278,6 +280,26 @@ public final class Collectors {
|
||||
CH_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Collector} that accumulates the input elements into an
|
||||
* <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter
|
||||
* order. The returned Collector disallows null values and will throw
|
||||
* {@code NullPointerException} if it is presented with a null value.
|
||||
*
|
||||
* @param <T> the type of the input elements
|
||||
* @return a {@code Collector} that accumulates the input elements into an
|
||||
* <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter order
|
||||
* @since 10
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T>
|
||||
Collector<T, ?, List<T>> toUnmodifiableList() {
|
||||
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
|
||||
(left, right) -> { left.addAll(right); return left; },
|
||||
list -> (List<T>)List.of(list.toArray()),
|
||||
CH_NOID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Collector} that accumulates the input elements into a
|
||||
* new {@code Set}. There are no guarantees on the type, mutability,
|
||||
@ -305,6 +327,36 @@ public final class Collectors {
|
||||
CH_UNORDERED_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Collector} that accumulates the input elements into an
|
||||
* <a href="../Set.html#unmodifiable">unmodifiable Set</a>. The returned
|
||||
* Collector disallows null values and will throw {@code NullPointerException}
|
||||
* if it is presented with a null value. If the input contains duplicate elements,
|
||||
* an arbitrary element of the duplicates is preserved.
|
||||
*
|
||||
* <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
|
||||
* Collector.
|
||||
*
|
||||
* @param <T> the type of the input elements
|
||||
* @return a {@code Collector} that accumulates the input elements into an
|
||||
* <a href="../Set.html#unmodifiable">unmodifiable Set</a>
|
||||
* @since 10
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T>
|
||||
Collector<T, ?, Set<T>> toUnmodifiableSet() {
|
||||
return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
|
||||
(left, right) -> {
|
||||
if (left.size() < right.size()) {
|
||||
right.addAll(left); return right;
|
||||
} else {
|
||||
left.addAll(right); return left;
|
||||
}
|
||||
},
|
||||
set -> (Set<T>)Set.of(set.toArray()),
|
||||
CH_UNORDERED_NOID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Collector} that concatenates the input elements into a
|
||||
* {@code String}, in encounter order.
|
||||
@ -1353,7 +1405,7 @@ public final class Collectors {
|
||||
* <p>If the mapped keys contain duplicates (according to
|
||||
* {@link Object#equals(Object)}), an {@code IllegalStateException} is
|
||||
* thrown when the collection operation is performed. If the mapped keys
|
||||
* may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
|
||||
* might have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
|
||||
* instead.
|
||||
*
|
||||
* <p>There are no guarantees on the type, mutability, serializability,
|
||||
@ -1410,6 +1462,45 @@ public final class Collectors {
|
||||
CH_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Collector} that accumulates the input elements into an
|
||||
* <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
|
||||
* whose keys and values are the result of applying the provided
|
||||
* mapping functions to the input elements.
|
||||
*
|
||||
* <p>If the mapped keys contain duplicates (according to
|
||||
* {@link Object#equals(Object)}), an {@code IllegalStateException} is
|
||||
* thrown when the collection operation is performed. If the mapped keys
|
||||
* might have duplicates, use {@link #toUnmodifiableMap(Function, Function, BinaryOperator)}
|
||||
* to handle merging of the values.
|
||||
*
|
||||
* <p>The returned Collector disallows null keys and values. If either mapping function
|
||||
* returns null, {@code NullPointerException} will be thrown.
|
||||
*
|
||||
* @param <T> the type of the input elements
|
||||
* @param <K> the output type of the key mapping function
|
||||
* @param <U> the output type of the value mapping function
|
||||
* @param keyMapper a mapping function to produce keys, must be non-null
|
||||
* @param valueMapper a mapping function to produce values, must be non-null
|
||||
* @return a {@code Collector} that accumulates the input elements into an
|
||||
* <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
|
||||
* are the result of applying the provided mapping functions to the input elements
|
||||
* @throws NullPointerException if either keyMapper or valueMapper is null
|
||||
*
|
||||
* @see #toUnmodifiableMap(Function, Function, BinaryOperator)
|
||||
* @since 10
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public static <T, K, U>
|
||||
Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
|
||||
Function<? super T, ? extends U> valueMapper) {
|
||||
Objects.requireNonNull(keyMapper, "keyMapper");
|
||||
Objects.requireNonNull(valueMapper, "valueMapper");
|
||||
return collectingAndThen(
|
||||
toMap(keyMapper, valueMapper),
|
||||
map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Collector} that accumulates elements into a
|
||||
* {@code Map} whose keys and values are the result of applying the provided
|
||||
@ -1473,6 +1564,51 @@ public final class Collectors {
|
||||
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a {@code Collector} that accumulates the input elements into an
|
||||
* <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
|
||||
* whose keys and values are the result of applying the provided
|
||||
* mapping functions to the input elements.
|
||||
*
|
||||
* <p>If the mapped
|
||||
* keys contain duplicates (according to {@link Object#equals(Object)}),
|
||||
* the value mapping function is applied to each equal element, and the
|
||||
* results are merged using the provided merging function.
|
||||
*
|
||||
* <p>The returned Collector disallows null keys and values. If either mapping function
|
||||
* returns null, {@code NullPointerException} will be thrown.
|
||||
*
|
||||
* @param <T> the type of the input elements
|
||||
* @param <K> the output type of the key mapping function
|
||||
* @param <U> the output type of the value mapping function
|
||||
* @param keyMapper a mapping function to produce keys, must be non-null
|
||||
* @param valueMapper a mapping function to produce values, must be non-null
|
||||
* @param mergeFunction a merge function, used to resolve collisions between
|
||||
* values associated with the same key, as supplied
|
||||
* to {@link Map#merge(Object, Object, BiFunction)},
|
||||
* must be non-null
|
||||
* @return a {@code Collector} that accumulates the input elements into an
|
||||
* <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
|
||||
* are the result of applying the provided mapping functions to the input elements
|
||||
* @throws NullPointerException if the keyMapper, valueMapper, or mergeFunction is null
|
||||
*
|
||||
* @see #toUnmodifiableMap(Function, Function)
|
||||
* @since 10
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public static <T, K, U>
|
||||
Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
|
||||
Function<? super T, ? extends U> valueMapper,
|
||||
BinaryOperator<U> mergeFunction) {
|
||||
Objects.requireNonNull(keyMapper, "keyMapper");
|
||||
Objects.requireNonNull(valueMapper, "valueMapper");
|
||||
Objects.requireNonNull(mergeFunction, "mergeFunction");
|
||||
return collectingAndThen(
|
||||
toMap(keyMapper, valueMapper, mergeFunction, HashMap::new),
|
||||
map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Collector} that accumulates elements into a
|
||||
* {@code Map} whose keys and values are the result of applying the provided
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2017, 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
|
||||
@ -57,6 +57,8 @@ import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import static java.util.Collections.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class MOAT {
|
||||
// Collections under test must not be initialized to contain this value,
|
||||
@ -230,6 +232,17 @@ public class MOAT {
|
||||
testListMutatorsAlwaysThrow(list);
|
||||
}
|
||||
|
||||
List<Integer> listCopy = List.copyOf(Arrays.asList(1, 2, 3));
|
||||
testCollection(listCopy);
|
||||
testImmutableList(listCopy);
|
||||
testListMutatorsAlwaysThrow(listCopy);
|
||||
|
||||
List<Integer> listCollected = Stream.of(1, 2, 3).collect(Collectors.toUnmodifiableList());
|
||||
equal(listCollected, List.of(1, 2, 3));
|
||||
testCollection(listCollected);
|
||||
testImmutableList(listCollected);
|
||||
testListMutatorsAlwaysThrow(listCollected);
|
||||
|
||||
// Immutable Set
|
||||
testEmptySet(Set.of());
|
||||
testCollMutatorsAlwaysThrow(Set.of());
|
||||
@ -252,6 +265,18 @@ public class MOAT {
|
||||
testCollMutatorsAlwaysThrow(set);
|
||||
}
|
||||
|
||||
Set<Integer> setCopy = Set.copyOf(Arrays.asList(1, 2, 3));
|
||||
testCollection(setCopy);
|
||||
testImmutableSet(setCopy);
|
||||
testCollMutatorsAlwaysThrow(setCopy);
|
||||
|
||||
Set<Integer> setCollected = Stream.of(1, 1, 2, 3, 2, 3)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
equal(setCollected, Set.of(1, 2, 3));
|
||||
testCollection(setCollected);
|
||||
testImmutableSet(setCollected);
|
||||
testCollMutatorsAlwaysThrow(setCollected);
|
||||
|
||||
// Immutable Map
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -280,6 +305,35 @@ public class MOAT {
|
||||
testImmutableMap(map);
|
||||
testMapMutatorsAlwaysThrow(map);
|
||||
}
|
||||
|
||||
Map<Integer,Integer> mapCopy = Map.copyOf(new HashMap<>(Map.of(1, 101, 2, 202, 3, 303)));
|
||||
testMap(mapCopy);
|
||||
testImmutableMap(mapCopy);
|
||||
testMapMutatorsAlwaysThrow(mapCopy);
|
||||
|
||||
Map<Integer,Integer> mapCollected1 =
|
||||
Stream.of(1, 2, 3)
|
||||
.collect(Collectors.toUnmodifiableMap(i -> i, i -> 101 * i));
|
||||
equal(mapCollected1, Map.of(1, 101, 2, 202, 3, 303));
|
||||
testMap(mapCollected1);
|
||||
testImmutableMap(mapCollected1);
|
||||
testMapMutatorsAlwaysThrow(mapCollected1);
|
||||
|
||||
try {
|
||||
Stream.of(1, 1, 2, 3, 2, 3)
|
||||
.collect(Collectors.toUnmodifiableMap(i -> i, i -> 101 * i));
|
||||
fail("duplicates should have thrown an exception");
|
||||
} catch (IllegalStateException ise) {
|
||||
pass();
|
||||
}
|
||||
|
||||
Map<Integer,Integer> mapCollected2 =
|
||||
Stream.of(1, 1, 2, 3, 2, 3)
|
||||
.collect(Collectors.toUnmodifiableMap(i -> i, i -> 101 * i, Integer::sum));
|
||||
equal(mapCollected2, Map.of(1, 202, 2, 404, 3, 606));
|
||||
testMap(mapCollected2);
|
||||
testImmutableMap(mapCollected2);
|
||||
testMapMutatorsAlwaysThrow(mapCollected2);
|
||||
}
|
||||
|
||||
private static void checkContainsSelf(Collection<Integer> c) {
|
||||
|
@ -40,6 +40,9 @@ import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNotEquals;
|
||||
import static org.testng.Assert.assertNotSame;
|
||||
import static org.testng.Assert.assertSame;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
@ -275,9 +278,9 @@ public class SetFactories {
|
||||
static <T> T serialClone(T obj) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(obj);
|
||||
oos.close();
|
||||
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
|
||||
oos.writeObject(obj);
|
||||
}
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
return (T) ois.readObject();
|
||||
@ -285,4 +288,53 @@ public class SetFactories {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
Set<Integer> genSet() {
|
||||
return new HashSet<>(Arrays.asList(1, 2, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfResultsEqual() {
|
||||
Set<Integer> orig = genSet();
|
||||
Set<Integer> copy = Set.copyOf(orig);
|
||||
|
||||
assertEquals(orig, copy);
|
||||
assertEquals(copy, orig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfModifiedUnequal() {
|
||||
Set<Integer> orig = genSet();
|
||||
Set<Integer> copy = Set.copyOf(orig);
|
||||
orig.add(4);
|
||||
|
||||
assertNotEquals(orig, copy);
|
||||
assertNotEquals(copy, orig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfIdentity() {
|
||||
Set<Integer> orig = genSet();
|
||||
Set<Integer> copy1 = Set.copyOf(orig);
|
||||
Set<Integer> copy2 = Set.copyOf(copy1);
|
||||
|
||||
assertNotSame(orig, copy1);
|
||||
assertSame(copy1, copy2);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void copyOfRejectsNullCollection() {
|
||||
Set<Integer> set = Set.copyOf(null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void copyOfRejectsNullElements() {
|
||||
Set<Integer> set = Set.copyOf(Arrays.asList(1, null, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfAcceptsDuplicates() {
|
||||
Set<Integer> set = Set.copyOf(Arrays.asList(1, 1, 2, 3, 3, 3));
|
||||
assertEquals(set, Set.of(1, 2, 3));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2017, 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
|
||||
@ -39,6 +39,9 @@ import static java.util.Arrays.asList;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNotEquals;
|
||||
import static org.testng.Assert.assertNotSame;
|
||||
import static org.testng.Assert.assertSame;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
@ -221,9 +224,9 @@ public class ListFactories {
|
||||
static <T> T serialClone(T obj) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(obj);
|
||||
oos.close();
|
||||
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
|
||||
oos.writeObject(obj);
|
||||
}
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
return (T) ois.readObject();
|
||||
@ -231,4 +234,47 @@ public class ListFactories {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
List<Integer> genList() {
|
||||
return new ArrayList<>(Arrays.asList(1, 2, 3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfResultsEqual() {
|
||||
List<Integer> orig = genList();
|
||||
List<Integer> copy = List.copyOf(orig);
|
||||
|
||||
assertEquals(orig, copy);
|
||||
assertEquals(copy, orig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfModifiedUnequal() {
|
||||
List<Integer> orig = genList();
|
||||
List<Integer> copy = List.copyOf(orig);
|
||||
orig.add(4);
|
||||
|
||||
assertNotEquals(orig, copy);
|
||||
assertNotEquals(copy, orig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfIdentity() {
|
||||
List<Integer> orig = genList();
|
||||
List<Integer> copy1 = List.copyOf(orig);
|
||||
List<Integer> copy2 = List.copyOf(copy1);
|
||||
|
||||
assertNotSame(orig, copy1);
|
||||
assertSame(copy1, copy2);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void copyOfRejectsNullCollection() {
|
||||
List<Integer> list = List.copyOf(null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void copyOfRejectsNullElements() {
|
||||
List<Integer> list = List.copyOf(Arrays.asList(1, null, 3));
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,9 @@ import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNotEquals;
|
||||
import static org.testng.Assert.assertNotSame;
|
||||
import static org.testng.Assert.assertSame;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
@ -70,6 +73,12 @@ public class MapFactories {
|
||||
}
|
||||
|
||||
// for varargs Map.Entry methods
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map.Entry<Integer,String>[] genEmptyEntryArray1() {
|
||||
return (Map.Entry<Integer,String>[])new Map.Entry<?,?>[1];
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map.Entry<Integer,String>[] genEntries(int n) {
|
||||
return IntStream.range(0, n)
|
||||
@ -322,21 +331,41 @@ public class MapFactories {
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void nullKeyDisallowedN() {
|
||||
Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
|
||||
entries[0] = new AbstractMap.SimpleImmutableEntry(null, "a");
|
||||
public void nullKeyDisallowedVar1() {
|
||||
Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
|
||||
entries[0] = new AbstractMap.SimpleImmutableEntry<>(null, "a");
|
||||
Map<Integer, String> map = Map.ofEntries(entries);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void nullValueDisallowedN() {
|
||||
Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
|
||||
entries[0] = new AbstractMap.SimpleImmutableEntry(0, null);
|
||||
public void nullValueDisallowedVar1() {
|
||||
Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
|
||||
entries[0] = new AbstractMap.SimpleImmutableEntry<>(0, null);
|
||||
Map<Integer, String> map = Map.ofEntries(entries);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void nullEntryDisallowedN() {
|
||||
public void nullEntryDisallowedVar1() {
|
||||
Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
|
||||
Map<Integer, String> map = Map.ofEntries(entries);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void nullKeyDisallowedVarN() {
|
||||
Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
|
||||
entries[0] = new AbstractMap.SimpleImmutableEntry<>(null, "a");
|
||||
Map<Integer, String> map = Map.ofEntries(entries);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void nullValueDisallowedVarN() {
|
||||
Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
|
||||
entries[0] = new AbstractMap.SimpleImmutableEntry<>(0, null);
|
||||
Map<Integer, String> map = Map.ofEntries(entries);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void nullEntryDisallowedVarN() {
|
||||
Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
|
||||
entries[5] = null;
|
||||
Map<Integer, String> map = Map.ofEntries(entries);
|
||||
@ -344,7 +373,7 @@ public class MapFactories {
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void nullArrayDisallowed() {
|
||||
Map.ofEntries(null);
|
||||
Map.ofEntries((Map.Entry<?,?>[])null);
|
||||
}
|
||||
|
||||
@Test(dataProvider="all")
|
||||
@ -359,9 +388,9 @@ public class MapFactories {
|
||||
static <T> T serialClone(T obj) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(obj);
|
||||
oos.close();
|
||||
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
|
||||
oos.writeObject(obj);
|
||||
}
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
return (T) ois.readObject();
|
||||
@ -370,6 +399,62 @@ public class MapFactories {
|
||||
}
|
||||
}
|
||||
|
||||
Map<Integer, String> genMap() {
|
||||
Map<Integer, String> map = new HashMap<>();
|
||||
map.put(1, "a");
|
||||
map.put(2, "b");
|
||||
map.put(3, "c");
|
||||
return map;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfResultsEqual() {
|
||||
Map<Integer, String> orig = genMap();
|
||||
Map<Integer, String> copy = Map.copyOf(orig);
|
||||
|
||||
assertEquals(orig, copy);
|
||||
assertEquals(copy, orig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfModifiedUnequal() {
|
||||
Map<Integer, String> orig = genMap();
|
||||
Map<Integer, String> copy = Map.copyOf(orig);
|
||||
orig.put(4, "d");
|
||||
|
||||
assertNotEquals(orig, copy);
|
||||
assertNotEquals(copy, orig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void copyOfIdentity() {
|
||||
Map<Integer, String> orig = genMap();
|
||||
Map<Integer, String> copy1 = Map.copyOf(orig);
|
||||
Map<Integer, String> copy2 = Map.copyOf(copy1);
|
||||
|
||||
assertNotSame(orig, copy1);
|
||||
assertSame(copy1, copy2);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void copyOfRejectsNullMap() {
|
||||
Map<Integer, String> map = Map.copyOf(null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void copyOfRejectsNullKey() {
|
||||
Map<Integer, String> map = genMap();
|
||||
map.put(null, "x");
|
||||
Map<Integer, String> copy = Map.copyOf(map);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
public void copyOfRejectsNullValue() {
|
||||
Map<Integer, String> map = genMap();
|
||||
map.put(-1, null);
|
||||
Map<Integer, String> copy = Map.copyOf(map);
|
||||
}
|
||||
|
||||
// Map.entry() tests
|
||||
|
||||
@Test(expectedExceptions=NullPointerException.class)
|
||||
@ -386,7 +471,7 @@ public class MapFactories {
|
||||
public void entryBasicTests() {
|
||||
Map.Entry<String,String> kvh1 = Map.entry("xyzzy", "plugh");
|
||||
Map.Entry<String,String> kvh2 = Map.entry("foobar", "blurfl");
|
||||
Map.Entry<String,String> sie = new AbstractMap.SimpleImmutableEntry("xyzzy", "plugh");
|
||||
Map.Entry<String,String> sie = new AbstractMap.SimpleImmutableEntry<>("xyzzy", "plugh");
|
||||
|
||||
assertTrue(kvh1.equals(sie));
|
||||
assertTrue(sie.equals(kvh1));
|
||||
@ -404,5 +489,4 @@ public class MapFactories {
|
||||
Map<Number,Number> map = Map.ofEntries(e1, e2);
|
||||
assertEquals(map.size(), 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user