This Java tutorial helps you understand and use the Collections utilty class for creating thread-safe collections using wrapper factory methods.

You know, in addition to generic algorithms and collections factories, the java.util.Collections class provides utility methods that return wrapper objects that modify the behavior of standard collection classes such as synchronizing them, making them unmodifiable and checking the type of elements being added to them. This article helps you explore and use these functionalities properly in your Java daily coding.

Let’s start with the synchronized wrappers.

 

1. Synchronized Collections Examples

By default, most of the classes in the Java Collections framework are not thead-safe to avoid the unnecessary overhead of synchronization (except the Vector and Hashtable are synchronized). However, when it comes to using collections in multi-threaded programs, you should use the synchronized wrappers provided by the Collections class. Below is the list of synchronizedXXX() methods that wraps a specified collection in a synchronized one:

  • Collection<T> synchronizedCollection(Collection<T> c)
  • List<T> synchronizedList(List<T> list)
  • Map<K,V> synchronizedMap(Map<K,V> m)
  • Set<T> synchronizedSet(Set<T> s)
  • SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
  • SortedSet<T> synchronizedSortedSet(SortedSet<T> s)

For example, the following code creates a synchronized List collection:

List<String> listBooks = Collections.synchronizedList(new ArrayList<String>());

listBooks.add("Core Java");	// synchronized call
listBooks.remove(0);	// synchronized call

Is it possible to synchronize an ArrayList using the synchronizedCollection() method? Yes, of course it is possible as ArrayList is a subtype of Collection. However, the List-specific methods are not synchronized. So the more concrete method, the better.

 

NOTE: All the returned wrappers do not synchronize the iterator() method so you should manually use a synchronized block when iterating the collection. For example:

Set<Integer> setNumbers = Collections.synchronizedSet(new HashSet<>());

setNumbers.add(2016);	// synchronized call
setNumbers.add(1800);	// synchronized call

// using iterator must be synchronized manually:
synchronized (setNumbers) {
	Iterator<Integer> iterator = setNumbers.iterator();

	while (iterator.hasNext()) {
		Integer num = iterator.next();
		System.out.println(num);
	}
}

 

2. Unmodifiable Collections Examples

Sometimes you want to prevent the client from changing a collection i.e. adding and removing elements are prohibited. The Collections class provides some useful methods that wrap a specified collection in an unmodifiable one, as shown in the following list:

  • Collection<T> unmodifiableCollection(Collection<? extends T> c)
  • List<T> unmodifiableList(List<? extends T> list)
  • Map<K,V> unmodifiableMap(Map<? extends K,? extends V> m)
  • Set<T> unmodifiableSet(Set<? extends T> s)
  • SortedMap<K,V> unmodifiableSortedMap(SortedMap<K,? extends V> m)
  • SortedSet<T> unmodifiableSortedSet(SortedSet<T> s)

Any attempts to modify the returned collection (either direct or via its iterator) result in UnsupportedOperationException. Here’s an example:

Map<Integer, String> mapErrors = new HashMap<>();

mapErrors.put(500, "Internal Server Error");
mapErrors.put(404, "Not Found");

Map<Integer, String> readOnlyMap = Collections.unmodifiableMap(mapErrors);

Iterator<Integer> iterator = readOnlyMap.keySet().iterator();

while (iterator.hasNext()) {
	Integer key = iterator.next();
	String value = readOnlyMap.get(key);
	System.out.println(key + " => " + value);
}

readOnlyMap.put(403, "Forbidden");	// throws UnsupportedOperationException

As you can see, these unmodifiableXXX() methods are useful when you want to allow clients read-only access to the internal data structure.

 

3. Checked Collections Examples

The Collections class also provides the checkedXXX() methods that returns a dynamically typesafe view of the specified collection. This can be useful when passing a typed collection reference to a third-party library method which is not generic, as the checked wrappers will test every element added to the collection to ensure the collection contains no incorrectly typed elements.

Checked wrappers can be created using the following methods:

  • Collection<E> checkedCollection(Collection<E> c, Class<E> type)
  • List<E> checkedList(List<E> list, Class<E> type)
  • Map<K,V> checkedMap(Map<K,V> m, Class<K> keyType, Class<V> valueType)
  • Set<E> checkedSet(Set<E> s, Class<E> type)
  • SortedMap<K,V> checkedSortedMap(SortedMap<K,V> m, Class<K> keyType, Class<V> valueType)
  • SortedSet<E> checkedSortedSet(SortedSet<E> s, Class<E> type)

Any attempt to insert an element of the wrong type will result in an immediate ClassCastException.

Consider an example. The following statements create a checked list and pass it to a third-party library method:

List<String> listNames = Collections.checkedList(new ArrayList<>(), String.class);

thirdpartyMethod(listNames);

Suppose that the third-party library method is written like this:

public void thirdpartyMethod(List list) {
	list.add("Tom");	// ok
	list.add("Tom");	// ok

	list.add(123);	// throws ClassCastException
}

Inside this method, if it attempts to add an element of any type other than String, a ClassCastException will be thrown.

 

References:

 

Related Collection Utility Classes Tutorials:

 

Other Java Collections Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (CollectionsWrapperExamples.java)CollectionsWrapperExamples.java[Java Collections Code Example]1 kB

Add comment