October 21, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

The Google Collections Library

  • March 20, 2008
  • By Dick Wall
  • Send Email »
  • More Articles »

Easy Wins

Let me start with some of the simple features, which are nonetheless among my favorites in the library. The primary one is Convenience Creators.

Now, go back to that example of the Map of things to List of things, using generics:

Map<String, List<String>> mapOfLists =
   new HashMap<String, List<String>>();

I believe this will be a pretty common sight to a lot of developers. Indeed, I have written far more complicated collection declaration and initialization type signatures than this, almost always repeating the signature on both the left and right side of the =.

For Java 7, there is a type inference proposal that would take the above and change it to something like this:

Map<String, List<String>> mapOfLists =
   new HashMap<>();

Certainly an improvement, and clearly the compiler can still get enough information from this to make some common sense assumptions and set up the new HashMap generic type signature accordingly. You will have to wait and see whether it does make it in to the language.

In the meantime, though, the Google collections library offers another alternative to save some of that verbosity:

Map<String, List<String>> mapOfLists =
   Maps.newHashMap();

The Maps.newHashMap() is a static method on a utility class called Maps from the collections library. It exploits a loophole in the way generics are implemented in Java so that the convenience creator newHashMap does not actually need to have the type signature passed in to it. These convenience creators are provided for all of the standard Java collections, and all of the new Google collections as well. It's amazing how much cleaner and more readable this simple idea can make your code.

For example:

List<String> listOfStrings =
   new ArrayList<String>();

can be replaced by:

List<String>
listOfStrings = Lists.newArrayList();

Not really related to collections per-se, but still convenient, is the join method from the Join class. Anyone who has used a scripting language with join (like Python) will get this straight away. You can create a string of items joined together from an array, collection, iterable, or varargs list. The first parameter is a delimiter that will be placed between the joined items. For example, to create a file path from a collection of subdirectories, you could just use:

String[] subdirs = new String[] {"usr", "local", "lib"};
String directory = Join.join(PATH_SEPARATOR, subdirs);

Certainly, this is not a radical new feature, but it is probably the only join method you will ever need and it saves you writing your own.

New Collections

As you would expect from a collections library, there are a number of new collections:

Multimap

Let me go back to that first example again, the map of things to a list of things, but this time I'll mix up the types a bit:

Map<Integer, List<String>> mapOfLists =
   Maps.newHashMap();

Chances are you have written something like this before. Maps of things to lists of things is a really common pattern, making it easy to collect items into identifiable buckets. If you have written this, you probably know the sort of code you have to write when you want to add a new entry into the map:

List<String> list = mapOfLists.get(key);
if (list == null) {
   list = new ArrayList<String>();
   mapOfLists.put(key, list);
}
list.add(value);

In other words, you have to ensure there is a list to receive the new value when adding that value to the map. If you are doing things correctly, you probably should also check for empty lists when removing items, and if the list is emptied, remove that as well to save resources. It's not uncommon to see a lot of this kind of boilerplate.

Multimap is an implementation (or actually a set of implementations) of this for you. In fact, there are implementations of Multimap based on ArrayLists, LinkedLists, Trees, and more.

Multimap<Integer, String> numbers =
   Multimaps.newArrayListMultiMap();
numbers.put(1, "One");
numbers.put(1, "Uno");
numbers.put(2, "Two");
numbers.put(2, "Dos");
numbers.remove(1,"One");
numbers.removeAll(2);

As you dig further into Multimap, you will find it has lots of power, and this introduction only scratches the surface. For example, if you had a map of lists and wanted to find the maximum of any of the values held in the lists, it would require a lot of iteration and comparison code. With Multimap, you could simply use Collections.max(numbers.values()). There are plenty of other ways like this where using Multimap can save you time and effort.





Page 2 of 6



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel