Commons Collections is a vast topic that could take up an entire article by itself. This article provides only a high-level understanding of the APIs and provides real-world examples for the most commonly used.
You may wonder why you need Commons Collections at all when the Java Collections Framework is available in the JDK. Well, Collections extends and enhances the Java Collections Framework's classes and interfaces. In fact, I strongly feel that it also should be part of JDK itself.
The following are some of the features that I particularly like:
- The bag interface
- The fixed size, dual, and LRU maps
- Iterator for an object array and map
- MultiKey for a map
- The numerous utility classes, which provide convenient methods for using the APIs
- The decorators, which provide customized behavior for most of the classes
The Collections classes are organized in the following listed packages:
The org.apache.commons.collections package contains interfaces, which are implemented in rest of the packages, and utility classes, which each act as a factory to instantiate a collection class or a decorated version of a collection class. Some of the interesting classes in this package are ArrayStack, BeanMap, ExtendedProperties, FastArrayList, FastHashMap, and FastTreeMap. The javadoc
for these classes contains all the details, but Table 1 provides a quick note to explain each class' real-world usage.
||ArrayStack is a Stack implementation backed by an ArrayList for use in a single threaded environment. For instance, if you want to use Stack for some processing but only within a method, this implementation performs better than the Stack implemented using a Vector in JDK-1.4.2.
||Like the Swing GUI widget JButton, using this class, you can treat even a map as a Java Bean. A map can be dragged and dropped on the screen while designing a GUI to represent a data source or a set of configuration properties for the application.
||This is my favorite class in this package. It is similar to java.util.Properties, which has a load method for loading configuration properties, but this implementation has the following benefits:
You can have multiple values for the same property key.The value may be separated in different lines.It offers convenient helper methods for fetching non-string values. For example, the getFloat method fetches a property of type float. You no longer need to write wrapper methods to parse the configuration property values.
|FastArrayList, FastHashMap, FastTreeMap
||These classes can be used in a multi-threaded environment if the majority of the operations are read-only. These classes are backed by ArrayList, HashMap, and TreeMap, respectively.
|Table 1. Some Interesting Classes in the org.apache.commons.collections Package|
The org.apache.commons.collections.bag class is very useful if your applications require you to add multiple copies of an object to a List. In these situations, I normally see developers add the objects to an ArrayList and iterate every time to determine the number of objects added for a given type. An online shopping cart is a good candidate for this requirement. The disadvantage of this approach is poor performance in terms memory and speed.
A good design to address this requirement would be keeping one copy of the object and incrementing the count whenever a new entry of the same type is added. The HashBag and TreeBag classes in Commons Collections (backed by HashMap and TreeMap, respectively) address this requirement.
The in.co.narayanan.commons.collections.bag package in the source code illustrates a real-world usage of a bag. The example processes the order for the software licenses of various operating systems and represents the ordered products in a bag.
More specific versions or decorators are available for these classes as well. The javadoc offers a more detailed explanation.
Most Java developers have fetched a key by writing two HashMaps and passing a value as the key to the second map. Normally, you need to use this technique if you want to treat the name and value equally. Even the value could be a key in this case.
The org.apache.commons.collections.bidimap example is a prototype adapter that integrates PeopleSoft and Siebel command-processing engines, assuming that every command in one has an equivalent in the other. You'll find the relevant classes in the package in.co.narayanan.commons.collections.bidimap. You can start reading the code from the class SiebelPeopleSoftConnector, which acts as the adapter and holds the command mapping in a BidiMap. When a request arrives to process a Siebel command, the corresponding PeopleSoft command is retrieved from the BidiMap and passed to the PeopleSoft command engine. The reverse happens for PeopleSoft commands. The example contains only a skeleton of the application.
The unmodifiable version of this class is handy if you want to design by contract, thereby prohibiting developers from altering the contents. This would greatly reduce the mistakes developers encounter while processing the contents.
If you want to remove objects from a collection in a specific order, you can use implementations of the buffer interface. Some of its interesting classes are CircularFifoBuffer, PriorityBuffer, BoundedFifoBuffer, and BlockingBuffer. Decorated versions of each are available.
You'll find the buffer example in the package in.co.narayanan.commons.collections.buffer. It demonstrates the CircularFifoBuffer class, which you can think of as a moving window. The size of the collection is fixed, and the objects get removed in a first-in, first-out (FIFO) manner when it becomes full.
The objective of the application is to report performance data to a remote server. Since the performance data is used only for monitoring, data loss is acceptable. A client application that wants to report performance data will need to instantiate class ReportPerformanceData and call method reportPerformance. The performance data will be added to the circular buffer.
The class ReportTask removes the performance data object and sends it to the performance server. The concurrent utility class ThreadPoolExecutor in Java 1.5 is used to start the reporting task asynchronously, so that the data is reported as and when the buffer has some data to report.
The org.apache.commons.collections.collection package contains decorator classes, which implement the java.util.Collection
interface directly. Therefore, any class that implements the Collection
interface can make use of the decorators available here. Some of the commonly used classes are PredicatedCollection, CompositeCollection, SynchronizedCollection, TransformedCollection, TypedCollection, and UnmodifiableCollection. Table 2 provides a quick note on when to use each of these decorators.
||When to Use
||You want to restrict the addition of objects to a collection with a condition like "amount >= $15000". To instantiate this class, you can define the condition as a separate object, which is called as a predicate and passed as an argument to the decorate factory method.
||You want to create collections of collections and have a unified view while adding or removing objects.
||You want to make an existing collection thread-safe.
||You want to convert an object from one form to another (such as String to an Integer object) whenever adding to a collection.
||You want to restrict the object type being added to a collection. This is similar to Java 1.5 generics.
||You want to restrict modification to an existing collection reference.
|Table 2. Some Commonly Used Classes in the org.apache.commons.collections.collection Package|
This package contains various reusable classes, which you can use while sorting objects in a collection. The classes NullComparator
are most interesting (see Table 3).
||Moves null entries towards the bottom while sorting entries in an array or a list
||Restores the order in a collection to a predefined list
|Table 3. The NullComparator and FixedOrderComparator Classes|
Un upcoming section discusses the org.apache.commons.collections.functors package in detail.
Various classes in the org.apache.commons.collections.iterators package implement the java.util.Iterator
interface. Some of the most useful are MapIterator
, and IteratorUtils
. You might want to go through the methods in the IteratorUtils
class to make use of the classes in this package.
class in the org.apache.commons.collections.keyvalue package is very useful. If you want to create domain objects in an application and store them in a map based on a composite primary key, you can create an instance of MultiKey
by passing values of the primary key for that record. You can pass this instance to the map for storing the domain object.
The other common use for this package is storing locale-specific entries in a map. In this case, the actual key and the locale name together will constitute the key.
, and PredicatedList
classes in the org.apache.commons.collections.list package are interesting. The javadoc
for these classes is self-explanatory.
, and StaticBucketMap
classes in the org.apache.commons.collections.map package are interesting. The javadoc
for the classes are self-explanatory.
, and UnmodifiableSet
classes in the org.apache.commons.collections.set package are interesting. The javadoc
for the classes are self-explanatory.