These implementations are anonymous; rather than providing a public class,
the library provides a static factory method. All these implementations
are found in the
Collections
class, which consists solely of static methods.
Collection
,
Set
,
List
,
Map
,
SortedSet
, and
SortedMap
— has one static factory method.
public static <T> Collection<T> synchronizedCollection(Collection<T> c); public static <T> Set<T> synchronizedSet(Set<T> s); public static <T> List<T> synchronizedList(List<T> list); public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m); public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s); public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);
Collection
backed up by the specified collection.
To guarantee serial access, all access to
the backing collection must be accomplished through the returned
collection. The easy way to guarantee this is not to keep a reference
to the backing collection. Create the synchronized collection with the following trick.
List<Type> list = Collections.synchronizedList(new ArrayList<Type>());
Vector
.
In the face of concurrent access, it is imperative that the user manually synchronize on the returned collection when iterating over it. The reason is that iteration is accomplished via multiple calls into the collection, which must be composed into a single atomic operation. The following is the idiom to iterate over a wrapper-synchronized collection.
Collection<Type> c = Collections.synchronizedCollection(myCollection); synchronized(c) { for (Type e : c) foo(e); }
iterator
method must be called
from within the synchronized
block. Failure to follow
this advice may result in nondeterministic behavior.
The idiom for iterating over a Collection
view of a synchronized
Map
is similar. It is imperative that the user synchronize
on the synchronized Map
when iterating over any of its
Collection
views rather than synchronizing on the
Collection
view itself, as shown in the following example.
Map<KeyType, ValType> m = Collections.synchronizedMap(new HashMap<KeyType, ValType>()); ... Set<KeyType> s = m.keySet(); ... synchronized(m) { // Synchronizing on m, not s! while (KeyType k : s) foo(k); }
List
example, you cannot call
ArrayList
's
ensureCapacity
operation on the wrapped ArrayList
.
UnsupportedOperationException
.
Unmodifiable wrappers have two main uses, as follows:
Collection
interfaces has one static factory method.
public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c); public static <T> Set<T> unmodifiableSet(Set<? extends T> s); public static <T> List<T> unmodifiableList(List<? extends T> list); public static <K,V> Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m); public static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<? extends T> s); public static <K,V> SortedMap<K, V> unmodifiableSortedMap(SortedMap<K, ? extends V> m);
Collections.checked
interface wrappers
are provided for use with generic collections. These implementations
return a dynamically type-safe view of the specified collection,
which throws a ClassCastException
if a client attempts to
add an element of the wrong type. The generics mechanism in the
language provides compile-time (static) type-checking, but it is
possible to defeat this mechanism. Dynamically type-safe views
eliminate this possibility entirely.