Intro to Guava


Google's Guava tools offer Java developers a wide range of useful Collection utilities. To introduce yourself to these tools, start with the methods that let you quickly create and initialize your garden variety Java collections. Here I'll give a quick introduction to this aspect of Guava. See the sidebar for other ways Guava will make your Java programming easier.

Summary: Creating and Initializing Basic Lists, Sets and Maps

Let's jump right in. The first example below shows the way I most often use Guava—to initialize an ArrayList. In this and most other examples, I use unit test assertions to illustrate the state of the collection after initialization.

Listing 1: Instantiating and Initializing an ArrayList with Guava

@Test
public void initializeArrayList()   {
    List<String> diveForms = Lists.newArrayList("dive", "dives", "dived", "dived");
    
    assertEquals(4, diveForms.size());
}

The next listing shows how Guava lets you create and instantiate a new HashSet just as easily. Note that, unlike Listing 1, in Listing 2 the assertEquals( ) method expects three elements rather than four because we are dealing with a set rather than a list.

Listing 2: Instantiating and Initializing a HashSet with Guava

@Test
public void initializeHashSet() {
    Set<String> diveForms = Sets.newHashSet("dive", "dives", "dived", "dived");
    
    assertEquals(3, diveForms.size());
}

Guava's Map creation can be almost as convenient as that of the List and Set implementations. If you want to initialize in a single line—rather than loading your Map with a number of "put" statements—you must first instantiate another Guava collection called an ImmutableMap. (Note that this does not make your map immutable; you are simply creating a temporary ImmutableMap to initialize your map.)

Listing 3: Instantiating and Initializing a HashMap with Guava

@Test
public void initializeHashMap() {
    Map<String, Integer> map = Maps.newHashMap(ImmutableMap.of("one", new Integer(1), "two", 
            new Integer(2), "three", new Integer(3), "four", new Integer(4)));

    assertEquals(4, map.size());
    
    assertEquals(1, map.get("one").intValue());
    assertEquals(2, map.get("two").intValue());
    assertEquals(3, map.get("three").intValue());
    assertEquals(4, map.get("four").intValue());
}

You can leverage single-line Set creation to make loading a Map<X, HashSet<Y>> very easy. Check out the listing below, and keep in mind that the same could be done with a Map<X, ArrayList<Y>>.

Listing 4: Instantiating and Initializing a Map<X, HashSet<Y>> with Guava

@Test
public void initializeMapToHashSet() {
    Map<String, HashSet<String>> map2 = Maps.newHashMap();
    map2.put("city", Sets.newHashSet("London", "Tokyo"));
    map2.put("country", Sets.newHashSet("Great Britain", "Japan"));
    
    assertEquals(2, map2.size());
}

Nota bene, though: in the case of Map<X, HashSet<Y>>, you may be better off with a Multimap. See the internal link in the sidebar.


Why the Guava Way is the One True Way

This section is for those who need a little more persuading that Guava really is the one true way. To make the argument crystal clear, I will repeat some of the examples already given above.

Let's first compare ArrayList initialization under Java 1.6 with and without Guava.

Listing 5: Initializing an ArrayList under Java 1.6 without and with Guava

// Without Guava
List<String> noGuavaList = new ArrayList<String>();
noGuavaList.add("dive");
noGuavaList.add("dives");
noGuavaList.add("dived");    
    
// With Guava
List<String> guavaList = Lists.newArrayList("dive", "dives", "dived");   
assertEquals(3, guavaList.size());
    

You see that the Guava approach is much more succinct, without sacrificing readablity or clarity.

Java 1.7 saves you the "<String>," letting you get away with "<>," but you still have to initialize the ArrayList one element at a time.

Listing 6: Instantiating and Initializing an ArrayList under Java 1.7

List<String> list_Java_1_7 = new ArrayList<>();
list_Java_1_7.add("dive");
list_Java_1_7.add("dives");
list_Java_1_7.add("dived");

Creating a HashSet without and with Guava follows the same pattern as ArrayList.

Now let's create a Map<String, HashSet<String>>, both without and with.

Listing 7: Instantiating a Map<String, HashSet<String>> without and with Guava

// Without Guava
Map<String, Set<String>> map1 = new HashMap<String, Set<String>>();
Set<String> set1 = new HashSet<String>();
set1.add("London");
set1.add("Tokyo");
map1.put("city", set1);
set1 = new HashSet<String>();
set1.add("Great Britain");
set1.add("Japan");
map1.put("country", set1);

// With Guava
Map<String, HashSet<String>> map2 = Maps.newHashMap();
map2.put("city", Sets.newHashSet("London", "Tokyo"));
map2.put("country", Sets.newHashSet("Great Britain", "Japan"));

As convenent as this may be, even better is Guava's Multimap interface. See the internal link in the sidebar, and perhaps you'll never again use Map<String, Set<String>> or Map<String, List<String>>.

Less Common, but Still Useful Implementations

Lists. ArrayList suits most of my List needs, but in case your needs are different, Guava lets you create other types of List implementations—for example a LinkedList. A linked list lets you insert items into, and remove items from, the middle of your list with less cost than an ArrayList. In the somewhat silly example below, I'm imagining you have a linked list of body parts.

Listing 8: Instantiating and Initializing a LinkedList with Guava, ver. 1

public class Part   {
@Test
public void initializeLinkedList()  {
    List<String> partList = Lists.newLinkedList();
    partList.add("body");
    partList.add("head");
    partList.add("nostril");
    
    partList.add(2, "nose");
    
    List<String> expected = Lists.newArrayList("body", "head", "nose", "nostril");      
    assertEquals(expected, partList);
}

Unlike newArrayList( ), Lists.newLinkedList( ) does not let you pass a parameter to the constructor to initialize your list. The listing above illustrates this by adding each element to the LinkedList separately. But the constructor does let you pass in a collection, as the next listing makes clear.

Listing 9: Instantiating and Initializing a LinkedList with Guava, ver. 2

List<String> tempList = Lists.newArrayList("body", "head", "nose", "nostril");
List<String> partList = Lists.newLinkedList(tempList);
    
assertEquals(4, partList.size());

You could, of course, make this code even more succinct by collapsing the first two lines above into one, thus:

Listing 10: Instantiating and Initializing a LinkedList with Guava, ver. 3

List<String> partList = 
	Lists.newLinkedList(Lists.newArrayList("body", "head", "nose", "nostril"))
    
assertEquals(4, partList.size());

Sets. Guava offers alternate Set implementations as well. For instance, Sets.newTreeSet( ) and Sets.newConcurrentHashSet( ) create a TreeSet and a ConcurrentHashSet, respectively.

Maps. In the same vein, Maps.newTreeMap() will create a TreeMap, rather than a HashMap, if you want an iteration through the key/value pairs to be both sorted and economical.