Version 1.0 of the Google Collections library was officially released December 30, 2009. I have been using the library for the past 6 months or so on a variety of Java projects, with great success. Today I gave a brown-bag talk to share with some interested Atoms.
I have included below the sample code I used as presentation material, in case others are interested.
Note: As I was putting this post together I read that Google Collections is now part of Google’s guava-libraries project, which has not been officially released yet.
package com.atomicobject.misc;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.ForwardingMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import org.junit.Test;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static junit.framework.Assert.assertEquals;
/**
* Google Collections Library
*
* A better way to write Java code. The library guides you towards using
* a number of functional concepts and techniques like immutable
* collections and first class functions. The convenience methods for
* creating collections are EXTREMELY useful in unit tests.
*/
@SuppressWarnings({"UnusedDeclaration"})
public class DemoGoogleCollectionsTest {
/**
* Easy to make new collections
*/
public void makeNewCollectionsInline() {
{
// Don't need to specify generic types on right hand side
List names = Lists.newArrayList();
names.add("Joe");
}
{
// Empty immutable list
List names = ImmutableList.of();
}
{
// Immutable list built in one line of code
List names = ImmutableList.of("Joe", "Tom");
}
{
// Convenient map creation
Map<Integer, String> people = ImmutableMap.of(1, "Joe",
2, "Tom");
}
}
/**
* Builders for more complicated collections. Good for building static
* final collections.
*/
@Test
public void buildersForNewCollections() {
{
List otherNames = ImmutableList.of("Tom", "Jerry");
List names = new ImmutableList.Builder()
.add("Joe")
.addAll(otherNames)
.build();
assertEquals(ImmutableList.of("Joe", "Tom", "Jerry"), names);
}
{
new ImmutableMap.Builder<String, String>()
.put("Joe", "100 Michigan St.")
.put("Frank", "1010 Fulton St.")
.build();
}
{
// Sometimes need to iterate over something to build up a map.
List names = ImmutableList.of("Joe", "Henry");
ImmutableMap.Builder<String, Integer> mapBuilder =
new ImmutableMap.Builder<String, Integer>();
for (String name : names) {
mapBuilder.put(name, name.length());
}
// Return an immutable map that was built during the iteration
Map<String, Integer> result = mapBuilder.build();
assertEquals(ImmutableMap.of("Joe", 3, "Henry", 5), result);
}
}
/**
* Transforming a collection. Transformation is lazy - only happens when
* an item in the list is accessed. The transformation will take place
* every time
* an item is accessed from the new list though.
*/
@Test
public void transformation() {
// Transform list
{
List names = ImmutableList.of("Joe", "Frank");
List nameLengths =
Lists.transform(names, new Function<String, Integer>() {
public Integer apply(String name) {
return name.length();
}
});
assertEquals(ImmutableList.of(3, 5), nameLengths);
}
// Transform Collection
{
Collection numbers = ImmutableSet.of(1, 2, 3, 4);
Collection strings =
Collections2.transform(numbers, new Function<Integer, String>() {
public String apply(Integer number) {
return String.valueOf(number);
}
});
// NOTE: due to laziness, sometimes need to force the transformation in
// in assertions by using copyOf.
assertEquals(ImmutableList.of("1", "2", "3", "4"),
ImmutableList.copyOf(strings));
}
}
/**
* Filter collections using a predicate
*/
@Test
public void filtering() {
{
List names = ImmutableList.of("Joe", "Frank", "Henry");
Iterable threeLetterNames =
Iterables.filter(names, new Predicate() {
public boolean apply(String name) {
return name.length() == 3;
}
});
// Want to compare the result to a list so make
// Immutablelist copy for assertEquals to use
assertEquals(ImmutableList.of("Joe"),
ImmutableList.copyOf(threeLetterNames));
}
}
/**
* Join strings together
*/
@Test
public void joinStrings() {
{
List names = ImmutableList.of("Joe", "Frank", "Henry");
String combined = Joiner.on(", ").skipNulls().join(names);
assertEquals("Joe, Frank, Henry", combined);
}
}
/**
* Sorting collections
*/
@Test
public void sortTheStrings() {
List names = ImmutableList.of("Joe", "Frank", "Henry");
// Sort by natural sorting order of object
{
List sortedNames = Ordering.natural().sortedCopy(names);
assertEquals(ImmutableList.of("Frank", "Henry", "Joe"), sortedNames);
}
// Custom sort order
{
Ordering secondLetterOrdering = new Ordering() {
public int compare(String s1, String s2) {
return s1.substring(1).compareTo(s2.substring(1));
}
};
List sortedNames = secondLetterOrdering.sortedCopy(names);
assertEquals(ImmutableList.of("Henry", "Joe", "Frank"), sortedNames);
}
}
/**
* Multimaps can hold multiple values for the same key.
*/
@Test
public void multimaps() {
Multimap<String, String> cars = LinkedHashMultimap.create();
cars.put("Toyota", "Corolla");
cars.put("Toyota", "Prius");
cars.put("Jeep", "Grand Cherokee");
assertEquals(ImmutableSet.of("Corolla", "Prius"), cars.get("Toyota"));
assertEquals(ImmutableSet.of("Grand Cherokee"), cars.get("Jeep"));
}
/**
* Forwarding base classes. Very useful when you want a collection
* class with special functionality. You just need to implement
* a delegate function, and then override only the other methods
* you need.
*/
private static class EmptyMap<K,V> extends ForwardingMap<K,V> {
@Override
protected Map<K,V> delegate() {
return ImmutableMap.of();
}
}
/**
* Miscellaneous stuff
*/
@Test
public void miscellaneous() {
// Setup
Predicate predicate = Predicates.alwaysTrue();
List names = ImmutableList.of("Joe", "Henry", "Frank");
// Sometimes Java isn't smart enough, so have to specify type
formatString(ImmutableList.of());
// Returns true if all items match the predicate
Iterables.all(names, predicate);
// Returns true if any items match the predicate
Iterables.any(names, predicate);
// Combine multiple Iterables
Iterables.concat(names, names, names);
// True if contains item
Iterables.contains(names, "Joe");
// Partition an iterable into specified size chunks
Iterable<List> chunks = Iterables.partition(names, 2);
Iterables.reverse(names);
Iterables.toString(names);
}
private void formatString(List strings) { }
}