Guava Collection Utilities
Goals
- Get an overview of Google's Guava collection utilities.
- Learn how to use Guava's immutable ADT implementations.
- Explore Guava's additional ADTs.
Concepts
- bag
- bimap
- builder pattern
- concatenate
- lazy
- multimap
- multiset
- predicate
- table
Library
java.util.Collections
java.util.function.Predicate<T>
com.google.common.base.Predicate<T>
com.google.common.collect
com.google.common.collect.ArrayListMultimap<K, V>
com.google.common.collect.BiMap<K, V>
com.google.common.collect.BiMap.inverse()
com.google.common.collect.Collections2
com.google.common.collect.EnumBiMap<K, V>
com.google.common.collect.EnumHashBiMap<K, V>
com.google.common.collect.HashBasedTable<R, C, V>
com.google.common.collect.HashBiMap<K, V>
com.google.common.collect.HashMultimap<K, V>
com.google.common.collect.HashMultiset<E>
com.google.common.collect.HashMultiset.create()
com.google.common.collect.ImmutableBiMap<K, V>
com.google.common.collect.ImmutableList
com.google.common.collect.ImmutableList.of()
com.google.common.collect.ImmutableListMultimap<K, V>
com.google.common.collect.ImmutableMultimap<K, V>
com.google.common.collect.ImmutableMultiset<E>
com.google.common.collect.ImmutableSet
com.google.common.collect.ImmutableSet.builder()
com.google.common.collect.ImmutableSetMultimap<K, V>
com.google.common.collect.ImmutableTable<R, C, V>
com.google.common.collect.Iterables
com.google.common.collect.Iterables.concat(Iterable<? extends T>... inputs)
com.google.common.collect.Iterables.filter(Iterable<T> unfiltered, Predicate<? super T> predicate)
com.google.common.collect.Iterators
com.google.common.collect.Iterators.concat(Iterator<? extends T>... inputs)
com.google.common.collect.Iterators.filter(Iterator<T> unfiltered, Predicate<? super T> predicate)
com.google.common.collect.LinkedHashMultimap<K, V>
com.google.common.collect.LinkedHashMultiset<E>
com.google.common.collect.LinkedListMultimap<K, V>
com.google.common.collect.Multimap<K, V>
com.google.common.collect.Multimap.asMap()
com.google.common.collect.Multimap.get(K key)
com.google.common.collect.Multimap.put(K key, V value)
com.google.common.collect.Multimap.size()
com.google.common.collect.Multimap.values()
com.google.common.collect.Multimaps
com.google.common.collect.Multiset<E>
com.google.common.collect.Multiset.add(E element, int occurrences)
com.google.common.collect.Multiset.count(Object element)
com.google.common.collect.Multiset.setCount(E element, int count)
com.google.common.collect.Multisets
com.google.common.collect.Table<R, C, V>
com.google.common.collect.Table.cellSet()
com.google.common.collect.Table.column(C columnKey)
com.google.common.collect.Table.contains(Object rowKey, Object columnKey)
com.google.common.collect.Table.get(Object rowKey, Object columnKey)
com.google.common.collect.Table.isEmpty()
com.google.common.collect.Table.row(R rowKey)
com.google.common.collect.Table.size()
com.google.common.collect.Table.Cell<R,C,V>
com.google.common.collect.TreeMultimap<K, V>
com.google.common.collect.TreeBasedTable<R, C, V>
Dependencies
Lesson
Java's collection interfaces have proved so popular that third parties have created utilities for working with collections, and even new implementations of the ADT interfaces. Notably Google's Guava library contains a wealth of collection utilities that are useful in day-to-day programming, bringing a level of convenience beyond that found in the standard Java collection utilities. The Guava collection utilities are found in the com.google.common.collect
package. Some of the most important collection utilities in Guava are examined here, but there are just too many to cover in one lesson. You are encouraged to review the articles in the See Also section below for more complete coverage.
Guava Collection Utilities
Similar to Java's java.util.Collections
class, Guava offers a com.google.common.collect.Collections2
class (so named to avoid conflicts with the Java version, even though they are in different packages) containing a few extra collection utilities. Most of Guava's utilities are found in separate classes, though. Some utilities are collected especially for lists, maps, sets, etc. (found in classes with just such those names). Many of the utilities consist of new ADT interfaces and their implementations.
Iterators and Iterables
The com.google.common.collect.Iterators
and com.google.common.collect.Iterables
classes are collections of utilities for working with Iterator<E>
and Iterable<T>
. Here are just a two examples:
- concatenation
- Guava provides
Iterators.concat(Iterator<? extends T>... inputs)
andIterables.concat(Iterable<? extends T>... inputs)
to concatenate (i.e. join the contents) of multiple iterators or iterables, respectively. For example, if you concatenate to iterators, it gives back and iterator that will iterate over the first iterable, and when the first is finished it will continue iterating over the second! The concatenation is lazy in that the concatenation happens in real time, as you iterate over the items. (The items from both iterators are not collected together up front in e.g. some collection.) - filtering
- Methods
Iterators.filter(Iterator<T> unfiltered, Predicate<? super T> predicate)
andIterables.filter(Iterable<T> unfiltered, Predicate<? super T> predicate)
filter the results based upon the result of some predicate, or functional definition of what should be filtered. The Guavacom.google.common.base.Predicate<T>
interface is a strategy for determining whether each item should be included or filtered out, based upon theapply(T input)
method. Java comes with its ownjava.util.function.Predicate<T>
interface, which you will learn about in an upcoming lesson, so try not to use the Guava one unless you have to in order to work with Guava utilities.
Immutable Collections
You already know that you can make any of your collections immutable by using e.g. java.util.Collections.unmodifiableList(…)
, which wraps a mutable collection with an immutable decorator instance. Guava goes further by providing a an extensive group of collection classes that are already mutable. They provide additional static factory methods that make creating immutable collections a breeze. Here's an example of creating an immutable List<E>
.
Builders
Many of Guava's collection classes come with builders
. These are intermediate classes that accumulate the items you want to appear in a collection. The builder is mutable, allowing you to add items at will, until you finally call the build()
method to produce the immutable set. Normally you will ask the immutable collection class itself for a builder via its builder()
method, such as ImmutableSet.builder()
.
Multiset<E>
Guava adds a new collection type—a multiset. Similar to a set, a com.google.common.collect.MultiSet<E>
doesn't keep track of order or indexes. But unlike a set, a multiset is able to keep track of multiple occurrences of equal items. Utilities are provided in com.google.common.collect.Multisets
.
Although a Multiset<E>
is not a Set<E>
, it is a Collection<E>
and as such allows adding elements via add(E)
and checking for elements via contains(Object)
. Its additional methods relate primarily to determining the number or occurrences or count
of each item in the multiset, as that is its primary distinction from Set<E>
.
add(E element, int occurrences)
- Adds a specific number of occurrences of a single element; equivalent to calling
add(E)
multiple times. count(Object element)
- Returns the number occurrences of a single element.
setCount(E element, int count)
- Adds or removes occurrences of the given element to attain the indicated count.
Implementations
com.google.common.collect.HashMultiset<E>
- A multiset based upon a hash table.
com.google.common.collect.LinkedHashMultiset<E>
- Equivalent to a
HashMultiset<E>
, except that it also maintains a linked list to maintain iteration order. com.google.common.collect.EnumMultiset<E>
- Efficient and compact multiset implementation for enums.
com.google.common.collect.ImmutableMultiset<E>
- An immutable multiset based upon a hash table.
Multimap<K, V>
A multimap is another new abstract data type, similar to a map except that each key can be associated with more than one value. A com.google.common.collect.MultiMap<K, V>
is not a subinterface of java.util.Map<K, V>
, although you can retrieve a view of the multiset as a map using the Multimap.asMap()
method as explained below. Utilities are provided in com.google.common.collect.Multimaps
.
asMap()
- Returns a view of the multiset as a
Map<K, Collection<V>>
. This map is a live view; modifying it will modifying the underlying multimap. get(K key)
- Returns a view of all the values associated with the indicated key as
Collection<V>
. This collection is a live view; modifying it will modifying the underlying multimap. put(K key, V value)
- Stores a key-value pair in the multimap. If a key already contains a value, this method may result in multiple values being associated with the same key.
size()
- Returns the number of key-value pairs, including the values for keys with multiple values. Note that this is not necessarily the same as the number of keys.
values()
- Returns a collection containing all the combined individual values, including any duplicates, that would be returned for each key. The number of values returned will be equal to
size()
.
Implementations
com.google.common.collect.ArrayListMultimap<K, V>
- A hash table-based map that uses an array-based list to store items associated with each key. This allows duplicate values to be associated with a key.
com.google.common.collect.HashMultimap<K, V>
- A hash table-based map that uses a hash table for values. This prevents duplicate values from being associated with a single key. A more appropriate name might have been
HashSetMultimap<K, V>
. com.google.common.collect.LinkedHashMultimap<K, V>
- A hash table-based map that uses a hash table for values, but retains the insertion order.
com.google.common.collect.LinkedListMultimap<K, V>
- A hash table-based map that uses a linked-list-based list to store items associated with each key. This allows duplicate values to be associated with a key.
com.google.common.collect.TreeMultimap<K, V>
- A tree-based map that also uses a tree to store items associated with each key. Ordering is natural ordering or based on a supplied comparator.
com.google.common.collect.ImmutableMultimap<K, V>
- An immutable multimap copy of data.
com.google.common.collect.ImmutableListMultimap<K, V>
- An immutable multimap copy of data that stores values in a list.
com.google.common.collect.ImmutableSetMultimap<K, V>
- An immutable multimap copy of data that stores values in a set.
BiMap<K, V>
A bimap, represented by the Guava interface com.google.common.collect.BiMap<K, V>
is a Map<K, V>
that allows you not only to look up a value from a key, but also a key from a value in the opposite direction! The main method that allows this is BiMap.inverse()
, which returns a Map<K, V>
of the value-to-key mapping.
inverse()
- Returns a
Map<K, V>
view of the value-to-key mapping—thereverse
mapping of the original map. This map is a live view; modifying it will modifying the underlying bimap.
Implementations
com.google.common.collect.HashBiMap<K, V>
- An unmodifiable
BiMap<K, V>
. com.google.common.collect.EnumBiMap<K, V>
- A bimap for enums as both keys and values, backed by two
EnumMap<K, V>
instances. com.google.common.collect.EnumHashBiMap<K, V>
- A bimap with an
EnumMap<K, V>
for the keys and a hash table for the values. - A bimap backed by two hash tables.
com.google.common.collect.ImmutableBiMap<K, V>
Table<R, C, V>
The com.google.common.collect.Table<R, C, V>
interface represents a table abstract data type, and is a way essentially to associate values with two keys instead of with a single key as in a Map<K, V>
. Thus rather than a single key, a Table<R, C, V>
uses a separate row and a column. Analogous to a Map.Entry<K, V>
, each value in a table is stored in a Table.Cell<R, C, V>
instance. Here are some of the most useful table methods:
cellSet()
- Returns a live set of all the cells in the table.
column(C columnKey)
- Returns a view all the row-value mappings for a column.
contains(Object rowKey, Object columnKey)
- Indicates whether the table has a cell value for the specified row and column.
get(Object rowKey, Object columnKey)
- Retrieves the cell value for the given row and column, or
null
if there is no such mapping. isEmpty()
- A convenience method logically equivalent to checking
size() == 0
. CallingisEmpty()
is preferred over checking the size, because the underlying implementation may have a more efficient way than retrieving the number of key-column-value associations. row(R rowKey)
- Retrieves a view of all the column-value mappings for a row.
size()
- Returns the number of table cells
Implementations
com.google.common.collect.HashBasedTable<R, C, V>
- A table implemented using hash tables.
com.google.common.collect.ImmutableTable<R, C, V>
- An immutable table with builder.
com.google.common.collect.TreeBasedTable<R, C, V>
- A table implemented using trees. Ordering is natural ordering or based on supplied comparators.
Review
In the Real World
- Use the Guava immutable collections as much as you can. Immutability makes your code safer, and the Guava implementations are easier to read and provide builders.
Self Evaluation
- Why does the
Multimap.asMap()
method return typeMap<K, Collection<V>>
instead of typeMap<K, V>
?
Task
In your booker
project, you should have already created an immutable collection of publications by first creating a mutable collection and wrapping it in an unmodifiable collection using Javas Collection
utilities. Convert this immutable collection to instead use one of the Guava immutable ADT implementations, using that implementation's builder to fill the collection with publications before assigning it to your variable.