The com.google.common.collect Package
This section details some of the enhancements to the Java Collections Framework that the com.google.common.collect
BiMap and ClassToInstance
The BiMap interface in the Library is analogous to the BidiMap interface in Commons Collections. It allows you to map a key to a value and vice versa. Therefore, both the key and value entries should be unique.
The code download compares the performances of both implementations. I found HashBiMap from the Library and DualTreeBidiMap from Commons Collections to be very similar in their insertion and seek times. However, Commons Collections TreeBidiMap takes a little longer to insert but saves memory space because it does not use dual map to represent value mapping to the key.
If you use Enum types for keys and values, you can use the EnumBiMap class in the com.google.common.collect package to create a bi-directional map. But I haven't seen a good use for this class yet. Why would someone want to map Enum types to Enum types? (Click here for a sampling of small programs that demonstrate the usage of some Library classes.)
The Library has no substitute for Commons Collections' ClassToInstance, which is useful for mapping an object instance to its class type. (Refer to the code download for a sample that illustrates this usage.)
Constraint and MapConstraint
You can restrict object additions to a collection object by setting constraints. Suppose you want to treat a negative value added to a list as a fatal error. You could define a constraint and use it in all the places wherever Integer is added to a List or Map. The Constraints or MapConstraints class contains a lot of utility methods for working with Constraint and MapConstraint in the Library. PredicatedCollections in the Java Collections Framework is similar to this.
Commons Collections has no direct equivalent for this feature, but it contains predefined, constraint-enforced classes using the decorator pattern. A couple of the classes are:
- org.apache.commons.collections.list.FixedSizeList This class posts a restriction on the add or remove operation.
- org.apache.commons.collections.map.LRUMap This class removes the least recently used entry if the map is full.
The Library's implementation of Multimap has two variants:
- HashMultimap allows you to override an existing entry if the key and value are identical.
- ArrayListMultimap allows duplicates for both keys and values.
Commons Collections has only one implementation, MultiValueMap, and it behaves similarly to HashMultimap. The code download includes an example, which I used to evaluate these classes.
The Multiset interface is similar to the Bag interface in Commons Collections. (Refer to my previous article to learn about Bag.) Basically, Multiset allows you to keep track of similar objects added to a Set. If the object you're adding already exists in the Set, the count is incremented instead of the object being added again.
I did not find a match for ConcurrentMultiset in Commons Collections.
The Library's implementation of ConcurrentMultiset uses JDK 5 ConcurrentMap to achieve better performance when using this class in a multi-threaded environment. Commons Collections has HashBag and Synchronized Bag, but they are not equal; the former is not thread safe and the latter locks the object for all method calls.
Both the Library and Commons Collections enable you to create a Comparator implementation for use with a collection. If you have to use Comparator extensively in an application, read the JavaDoc of the com.google.common.collect.Comparators class. It contains static utility methods to facilitate Comparator and Function usage.
If you have two comparators and want to use both to get a compound result, the method Comparators.compound(list of comparators) is handy. This method returns a Comparator that will invoke other comparators until it finds a non-zero result.
The org.apache.commons.collections.comparators package contains seven predefined comparators. One, org.apache.commons.collections.ComparatorUtils, is very similar to the Library's com.google.common.collect.Comparators.
Unlike Commons Collections, the Library defines all the methods as utility methods in one class, Comparators. This class contains methods for primitives comparison and natural-order comparison, as well as for using Function to transform the object before comparing.
To perform an operation before the backing data structure is modified, you can use the classes prefixed with "Forwarding" under the com.google.common.collect package to decorate maps, lists, and sets. For example, the method Constraints.constrainedList(..) decorates a List to use a Constraint implementation whenever an add operation is performed. This allows you to use collection classes, such as the classes in the java.io.* package. You can create multiple decorators and wrap one inside the other to perform a series of operations before the actual call is delegated to the ultimate collection class.
Commons Collections also contains decorator classes, but they are located in the respective packages of the collection types. For instance, FixedSizeMap, LazyMap, ListOrderedMap, MultiValueMap, and UnmodifiableMap are located under the org.apache.commons.collections.map package.
Iterables and Iterator
Iterables contains a bunch of utility methods to create numerous Iterator types for various purposes. For example, the Iterators.cycle method allows you to iterate infinitely until the list becomes empty. Commons Collections has similar behavior in the class org.apache.commons.collections.iterators.LoopingIterator.
In Commons Collections, all the Iterator types are found under the package org.apache.commons.collections.iterators and the utility methods are found in the class org.apache.commons.collections.IteratorUtils.
Maps, Lists, and Sets
The Maps, Lists, and Sets classes respectively allow you to create map, list, and set objects easily, without having to call the constructor. For instance, you can replace Map m = new HashMap() with Map m = Maps.newHashMap().
Apart from creating collection objects, these factory classes have numerous utility methods, including these notable ones:
- Maps.immutableMap(..) lets you to create an immutable Map for a given hard-coded key value pair. You no longer need to write four or five lines to populate some hard-coded key value pair to a Map.
- List.newArrayList(Iterator itr) creates an ArrayList object and populates it by iterating argument Iterator instances.
Similar utility classes, such as MapUtils, ListUtils, and SetUtils, can be found in the Commons Collections package org.apache.commons.collections.
The Library also contains the utility classes PrimitiveArrays and ObjectArrays to simplify the use of primitive data types. PrimitiveArrays contains utility methods to convert List to primitive types and vice versa. This is really helpful for reducing repeated code for these kinds of operations.