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.
@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.
@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.)
@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>>.
@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.
// 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.
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.
// 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.
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.
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:
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.