Google Collections

Why should we leave apache common collection?
There are several reasons to change the collections framework.
Since the apache collections should be backward compatible it would not be possible to change to a actual Java version. It would be necessary to change to another collection framework (or write all the stuff by yourself).
There are several projects which created a collections framework by themselves or took the apache collection library and upgraded it with generics.
Guava is a project like the apache commons. Since a few weeks the Google collection project is now in the guava project integrated.
I just will take a view to the collection package in the guava library.
What is in the guava-collection?
Helper classes for:

  • Lists, Sets Maps
  • New collection types
  • New immutables
  • Helpers for Iterator
  • Helper for lists

    Factory methods:
    Just create a list with Lists.newArrayList(). You will think there is no big different between new ArrayList(). Hmm… well, another example:

    List<String> stringList = Lists.newArrayList();
    List<String> stringList = new ArrayList<String>();
    

    You see. No more duplication of the generic declaration. And after static import of Lists it’s quite shorter ;).
    Another one would be the creation of a list with elements:

    List<String> stringList = Lists.newArrayList("foo","bar");
    

    It is also possible to create a list with an Iterator or an Iterable. Sure, the creation of a list based on an array is there.
    Two other very useful methods are partition. With this it’s possible to split a list into n other lists with the wished size. And the transform which transforms a List with a given Function. For example a List of Strings into a List of Integers:

    ArrayList<String> strings = Lists.newArrayList("1", "2");
    List<Integer> ints = Lists.transform(strings, new Function<String, Integer>() {
        public Integer apply(String from) {
            return Integer.valueOf(from);
        }
    });
    assertTrue(ints.contains(Integer.valueOf(1)));
    assertTrue(ints.contains(Integer.valueOf(2)));
    

    Helper for sets

    The Sets class contains as the Lists some factory methods for Sets, like HashSet, LinkedHashSet ans TreeSet.
    Some powerful methods would be Sets.intersection which calculates intersections between two sets and difference.
    One big difference between the old apache collections framework is the Sets.filter.

    Set<String> filtered = Sets.filter(Sets.newHashSet("foo", "bar"), new Predicate<String>() {
        public boolean apply(String input) {
            return input.contains("o");
        }
    });
    assertEquals(1, filtered.size());
    assertTrue(filtered.contains("foo"));
    

    As I told. The big improvement are the generics. The filter methods are the best sample and in my opinion the most used.

    Helper for maps

    The factory methods on Maps are very simple, there are just the methods to create an empty map of whished type. More useful on this class would be the methods for filtering. It is possible to filter by values, keys, and the full entry.
    In this context you should have a look to the MapMaker it will help to create maps with special fuctions and behavior.

    New collection types

    Multimap

    Very useful and often implemented by many different persons. A map which can contains more than one value for a key.

    ArrayListMultimap<String, String> listMultimap = ArrayListMultimap.create();
    listMultimap.put("foo", "bar");
    listMultimap.put("foo", "Bar");
    List<String> list = listMultimap.get("foo");
    assertEquals(2, list.size());
    

    There are also Set based implementations.

    Multiset

    The multiset is like the multimap but I think not as often implemented. 😉 I think a small sample will tell more than a lot of words.

    HashMultiset<String> multiset = HashMultiset.create();
    multiset.add("foo");
    multiset.add("foo");
    multiset.remove("foo");
    assertTrue(multiset.contains("foo"));
    

    Yes, you have seen right. The set knows how often a value was added and removed.

    BiMap

    The BiMap is a bidirectional implementation of a map.

    HashBiMap<String, Integer> biMap = HashBiMap.create();
    biMap.put("one", Integer.valueOf(1));
    BiMap<Integer, String> inverse = biMap.inverse();
    assertEquals("one", inverse.get(Integer.valueOf(1)););
    

    If you put a key/value pair after invoking inverse. The following pairs will be present in your representation of the inverse BiMap. So this code will work fine:

    HashBiMap<String, Integer> biMap = HashBiMap.create();
    biMap.put("one", Integer.valueOf(1));
    
    BiMap<Integer, String> inverse = biMap.inverse();
    // After inversing put more key/value pairs
    biMap.put("two", Integer.valueOf(2));
    assertEquals("two", inverse.get(Integer.valueOf(2)));
    

    Instead of a “regular” HashMap it will not be allowed to put the same value to more than one key. There would be a problem if the map will be inverted.

    New immutables

    Google collections comes with it’s own immutable collection types. They are different to the ones of java as they are implementations and not only wrappers. So the are much more performant.
    For the immutable collections just call the whished factory method. For example on ImmutableList.
    Instead of the classical unmodifiables on java.util.Collections there are factory methods to create an immutable list with values. So it is no longer necessary to take the long way over creating a list and wrap this with the unmodifiable proxy. Just do following:
    List immutableList = ImmutableList.of(“foo”, “bar”);
    Easy isn’t it? 🙂
    As usual you will receive an UnsupportedOperationException if you do something on the list.

    Following populare immutable collections are in the lib:

  • ImmutableList
  • EmtyImmutableList
  • ImmutableMultiset
  • EmtyImmutableMultiset
  • EmptyImmutableSet
  • ImmutableEnumSet
  • ImmutableSortedSet
  • EmptyImmutableSortedSet
  • there are still more, if you want to see them just have a look to the implementations of ImmutableCollection.

    Helpers for Iterator

    On the helper class Iterators are for example following methods:
    A short way to change from iterator to enumeration. Like this:

    Iterator<String> iterator = Lists.newArrayList("foo","bar").iterator();
    Enumeration<String> enumeration = Iterators.asEnumeration(iterator);
    

    Or a consuming iterator. This will do a remove on the based iterator every time you call the next() method.

    List<String> stringList = Lists.newArrayList("foo","bar");
    Iterator<String> consumingIterator = Iterators.consumingIterator(stringList.iterator());
    consumingIterator.next();
    assertEquals(1, stringList.size());
    

    The other cool method is filter. So it is possible to filter on an iterator. BUT, take care where the original iterater stands by. All next operation you will do on the filtered iterator will be performed on the original. See the following two examples:

    List<String> stringList = Lists.newArrayList("foo","bar");
    Iterator<String> fullIterator = stringList.iterator();
    UnmodifiableIterator<String> filteredIterator = Iterators.filter(fullIterator, Predicates.equalTo("bar"));
    filteredIterator.next();
    assertFalse(fullIterator.hasNext());
    

    and

    List<String> stringList = Lists.newArrayList("foo","bar");
    Iterator<String> fullIterator = stringList.iterator();
    UnmodifiableIterator<String> filteredIterator = Iterators.filter(fullIterator, Predicates.equalTo("foo"));
    filteredIterator.next();
    assertTrue(fullIterator.hasNext());
    

    The only difference is, that in the first sample all elements must be passed to receive a element that fits.

    So far the technical details.
    In my opinion they did and do a good job with the collections. There is just one thing I dislike.
    The version system they choosed.
    Why? They don’t have a principle to tell the users if there are big changes in this version. If it is just a bugfix version or a major release. They just mark methods with the @Deprecated or their @Beta annotation and every version will be a major release on methods with this annotations.
    You can find the jar on the Guava project site or in the maven repository :

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>r06</version>
    </dependency>
    

    Just have a look at it and enjoy.

    About the author

    Adrian Elsener

    Add comment

    By Adrian Elsener

    Recent Posts