March 3, 2021
Hot Topics:

The Google Collections Library

  • By Dick Wall
  • Send Email »
  • More Articles »


Multiset is perhaps a little less commonly used than Multimap, but very useful for histograms and counting purposes:

Multiset<String> histogram =

histogram.add("World", 3);

int count;
count = histogram.count("Hello");    // 2
count = histogram.count("World");    // 3
count = histogram.count("!");        // 1
count = histogram.count("Fred");     // 0

Internally, Multiset implementations use an efficient counter implementation, giving much better performance for most operations than using a Map or List. Implementations are provided based on Enums, Hashes, LinkedHashes, Trees, and more, and there's even a ConcurrentMultiset that allows fully concurrent updates with very little locking required.


BiMap provides bi-directional map functionality. In a bidirectional map, both keys and values are unique, and looking up a key from a value is possible. For example:

BiMap<Integer, String> numbers = Maps.newHashBiMap();
numbers.put(1, "one");
numbers.put(2, "two");
numbers.put(3, "three");
numbers.put(4, "four");
numbers.put(5, "five");

String one = numbers.get(1);                     // one
int three = numbers.inverse().get("three");      // three
Integer nine = numbers.inverse().get("nine");    // null
// NullPointerException
int oops = numbers.inverse().get("nine");

Although it's certainly not unique to using the Google Collections Library, watch out for that unboxing gotcha! Even though the get("three") call here works fine, the get("nine") line will give a null pointer exception. It is valid to ask a BiMap for a key or value it doesn't have (just like with a normal map), and it will return null. The NullPointerException occurs when the compiler tries to unbox that Integer for you into an int.


Java supports primitive types as well as object-oriented hierarchies descending from Object. This is another one of those oft-argued features of Java, the argument being that primitives were put in for reasons of efficiency. Collections, on the other hand, deal only in Objects.

Because auto-boxing and unboxing were added to Java 5, it is possible to make it appear that a collection is actually taking and returning primitives (as long as you are aware of some of the issues, like the NullPointerException on unboxing demonstrated above), but, in fact, behind the scenes, each primitive added to a collection is being boxed before being added. This means that the internal representation is less than optimal in some circumstances.

Say that you have a million primitives in an array, but you want to access it as a collection (perhaps to use it as a parameter to a method that requires a collection and not an array). Also, suppose that you know the data is only going to be access sparsely; perhaps only a dozen elements will be pulled out of the collection randomly, but you don't know which dozen will be chosen.

Creating a collection out of the primitive array would work, but it will be slow and very wasteful of memory:

int[] intArray = new int[1000000];

// Assume it has some data put in it here...

List<Integer> intList = Lists.newArrayList(1000000);
for (int i : intArray) {


It works, but yuk!

How about:

int[] intArray = new int[1000000];
List<Integer> intList =

In this case, intList holds an implementation that holds on to the original array and only boxes the values when they are retrieved. Values can be set in the collection as well, but it does have the restriction that the value passed in cannot be null (as is possible with an object array).

The PrimitiveArrays are an easy win if you have a large primitive array and access it only sparsely, but should not be used if you have a small array with many accesses, because the autoboxing overhead is paid on each access.

Page 3 of 6

This article was originally published on March 20, 2008

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date