Guava Collection

Immutable Collections

public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
  "red",
  "orange",
  "yellow",
  "green",
  "blue",
  "purple");

class Foo {
  final ImmutableSet<Bar> bars;
  Foo(Set<Bar> bars) {
    this.bars = ImmutableSet.copyOf(bars); // defensive copy!
  }
}

Why?

Immutable objects have many advantages, including:
- Safe for use by untrusted libraries.
- Thread-safe: can be used by many threads with no risk of race conditions.
- Doesn’t need to support mutation, and can make time and space savings with that assumption. All immutable collection implementations are more memory-efficient than their mutable siblings.
- Can be used as a constant, with the expectation that it will remain fixed.

When you don’t expect to modify a collection, or expect a collection to remain constant, it’s a good practice to defensively copy it into an immutable collection.

How?

An ImmutableXXX collection can be created in several ways:
- using the copyOf method.
- using the of method.
- using a Builder.

ImmutableSet.copyOf(set);

ImmutableSet.of("a", "b", "c");
ImmutableMap.of("a", 1, "b", 2);

public static final ImmutableSet<Color> GOOGLE_COLORS = 
    ImmutableSet.<Color>builder()
        .addAll(WEBSAFE_COLORS)
        .add(new Color(0, 191, 255))
        .build();

copyOf is smarter than you think

ImmutableSet<String> foobar = ImmutableSet.of("foo", "bar", "baz");
thingamajig(foobar);

void thingamajig(Collection<String> collection) {
   ImmutableList<String> defensiveCopy = ImmutableList.copyOf(collection);
   ...
}

In this code, ImmutableList.copyOf(foobar) will be smart enough to just return foobar.asList(), which is a constant-time view of the ImmutableSet

asList

All immutable collections provide an ImmutableList view via asList()

Details

InterfaceJDK or Guava?Immutable Version
CollectionJDKImmutableCollection
ListJDKImmutableList
SetJDKImmutableSet
SortedSet/NavigableSetJDKImmutableSortedSet
MapJDKImmutableMap
SortedMapJDKImmutableSortedMap
MultisetGuavaImmutableMultiset
SortedMultisetGuavaImmutableSortedMultiset
MultimapGuavaImmutableMultimap
ListMultimapGuavaImmutableListMultimap
SetMultimapGuavaImmutableSetMultimap
BiMapGuavaImmutableBiMap
ClassToInstanceMapGuavaImmutableClassToInstanceMap
TableGuavaImmutableTable

New Collection Types

MultiSet

ounting how many times a word occurs in a document is something like:

Map<String, Integer> counts = new HashMap<String, Integer>();
for (String word : words) {
  Integer count = counts.get(word);
  if (count == null) {
    counts.put(word, 1);
  } else {
    counts.put(word, count + 1);
  }
}

MultiSethave two main ways:
- Like an ArrayList<E> without an ordering constraint.
- Like a Map<E, Integer>, with elements and counts.

Guava’s Multiset API combines both ways of thinking about a Multiset, as follows:
- like an unordered ArrayList
- add(E)
- iterator()
- size()
- like a Map<E, Integer>
- count(Object)
- entrySet()
- elementSet()

MethodDescription
count(E)Count the number of occurrences of an element that have been added to this multiset.
elementSet()View the distinct elements of a Multiset<E> as a Set<E>.
entrySet()Similar to Map.entrySet(), returns a Set<Multiset.Entry<E>>, containing entries supporting getElement() and getCount().
add(E, int)Adds the specified number of occurrences of the specified element.
remove(E, int)Removes the specified number of occurrences of the specified element.
setCount(E, int)Sets the occurrence count of the specified element to the specified nonnegative value.
size()Returns the total number of occurrences of all elements in the Multiset.

Multiset Is Not A Map

Note that Multiset<E> is not a Map<E, Integer>, though that might be part of a Multiset implementation.

Implementations

MapCorresponding MultisetSupports null elements
HashMapHashMultisetYes
TreeMapTreeMultisetYes
LinkedHashMapLinkedHashMultisetYes
ConcurrentHashMapConcurrentHashMultisetNo
ImmutableMapImmutableMultisetNo

SortedMultiset

SortedMultiset is a variation on the Multiset interface that supports efficiently taking sub-multisets on specified ranges.

TreeMultiset implements the SortedMultiset interface.

Multimap

implemented a Map<K, List<V>> or Map<K, Set<V>>

In general, the Multimap interface is best thought of in terms of the first view, but allows you to view it in either way with the asMap() view, which returns a Map<K, Collection<V>>.

You rarely use the Multimap interface directly, however; more often you’ll use ListMultimap or SetMultimap, which map keys to a List or a Set respectively.

Construction

  • using MultimapBuilder
  • use the create() methods
// creates a ListMultimap with tree keys and array list values
ListMultimap<String, Integer> treeListMultimap =
    MultimapBuilder.treeKeys().arrayListValues().build();

// creates a SetMultimap with hash keys and enum set values
SetMultimap<Integer, MyEnum> hashEnumMultimap =
    MultimapBuilder.hashKeys().enumSetValues(MyEnum.class).build();

Modifying

Multimap.get(key) returns a view of the values associated with the specified key, even if there are none currently. For a ListMultimap, it returns a List, for a SetMultimap, it returns a Set.

Set<Person> aliceChildren = childrenMultimap.get(alice);
aliceChildren.clear();
aliceChildren.add(bob);
aliceChildren.add(carol);
SignatureDescriptionEquivalent
put(K, V)Adds an association from the key to the value.multimap.get(key).add(value)
putAll(K, Iterable<V>)Adds associations from the key to each of the values in turn.Iterables.addAll(multimap.get(key), values)
remove(K, V)Removes one association from key to value and returns true if the multimap changed.multimap.get(key).remove(value)
removeAll(K)Removes and returns all the values associated with the specified key. The returned collection may or may not be modifiable, but modifying it will not affect the multimap. (Returns the appropriate collection type.)multimap.get(key).clear()
replaceValues(K, Iterable<V>)Clears all the values associated with key and sets key to be associated with each of values. Returns the values that were previously associated with the key.multimap.get(key).clear(); Iterables.addAll(multimap.get(key), values)

Views

Multimap also supports a number of powerful views:
- asMap views any Multimap<K, V> as a Map<K, Collection<V>>.
- entries views the Collection<Map.Entry<K, V>> of all entries in the Multimap.
- keySet views the distinct keys in the Multimap as a Set.
- keys views the keys of the Multimap as a Multiset.
- values() views all the values in the Multimap as a “flattened” Collection<V>, all as one collection.

Multimap Is Not A Map

A Multimap<K, V> is not a Map<K, Collection<V>>, though such a map might be used in a Multimap implementation. Notable differences include:
- Multimap.get(key) always returns a non-null, possibly empty collection.
- If you prefer the more Map-like behavior of returning null for keys that aren’t in the multimap, use the asMap() view to get a Map<K, Collection<V>>.
- Multimap.containsKey(key) is true if and only if there are any elements associated with the specified key.
- Multimap.entries() returns all entries for all keys in the Multimap.
- Multimap.size() returns the number of entries in the entire multimap, not the number of distinct keys.

Implementations

ImplementationKeys behave like…Values behave like..
ArrayListMultimapHashMapArrayList
HashMultimapHashMapHashSet
LinkedListMultimap *LinkedHashMap``*LinkedList``*
LinkedHashMultimap**LinkedHashMapLinkedHashSet
TreeMultimapTreeMapTreeSet
ImmutableListMultimapImmutableMapImmutableList
ImmutableSetMultimapImmutableMapImmutableSet

Each of these implementations, except the immutable ones, support null keys and values.

* LinkedListMultimap.entries() preserves iteration order across non-distinct key values. See the link for details.

** LinkedHashMultimap preserves insertion order of entries, as well as the insertion order of keys, and the set of values associated with any one key.

If you need more customization, use Multimaps.newMultimap(Map, Supplier<Collection>) or the list and set versions to use a custom collection, list, or set implementation to back your multimap.

BiMap

A BiMap<K, V> is a Map<K, V> that:
* allows you to view the “inverse” BiMap<V, K> with inverse()
* ensures that values are unique, making values() a Set

BiMap<String, Integer> userId = HashBiMap.create();
...

String userForId = userId.inverse().get(id);

Implementations

Key-Value Map ImplValue-Key Map ImplCorresponding BiMap
HashMapHashMapHashBiMap
ImmutableMapImmutableMapImmutableBiMap
EnumMapEnumMapEnumBiMap
EnumMapHashMapEnumHashBiMap

Table

Table<Vertex, Vertex, Double> weightedGraph = HashBasedTable.create();
weightedGraph.put(v1, v2, 4);
weightedGraph.put(v1, v3, 20);
weightedGraph.put(v2, v3, 5);

weightedGraph.row(v1); // returns a Map mapping v2 to 4, v3 to 20
weightedGraph.column(v3); // returns a Map mapping v1 to 20, v2 to 5

Table supports a number of views to let you use the data from any angle, including:
* rowMap(), which views a Table<R, C, V> as a Map<R, Map<C, V>>. Similarly, rowKeySet() returns a Set<R>.
* row(r) returns a non-null Map<C, V>. Writes to the Map will write through to the underlying Table.
* Analogous column methods are provided: columnMap(), columnKeySet(), and column(c). (Column-based access is somewhat less efficient than row-based access.)
* cellSet() returns a view of the Table as a set of ## ClassToInstanceMap
Table.Cell<R, C, V>. Cell is much like Map.Entry, but distinguishes the row and column keys.

Several Table implementations are provided, including:
- HashBasedTable, which is essentially backed by a HashMap<R, HashMap<C, V>>.
- TreeBasedTable, which is essentially backed by a TreeMap<R, TreeMap<C, V>>.
- ImmutableTable
- ArrayTable, which requires that the complete universe of rows and columns be specified at construction time, but is backed by a two-dimensional array to improve speed and memory efficiency when the table is dense.

ClassToInstanceMap

Sometimes, your map keys aren’t all of the same type: they are types, and you want to map them to values of that type. Guava provides ClassToInstanceMap for this purpose.

In addition to extending the Map interface, ClassToInstanceMap provides the methods T getInstance(Class<T>) and T putInstance(Class<T>, T), which eliminate the need for unpleasant casting while enforcing type safety.

ClassToInstanceMap<Number> numberDefaults = MutableClassToInstanceMap.create();
numberDefaults.putInstance(Integer.class, Integer.valueOf(0));

Guava provides implementations helpfully named MutableClassToInstanceMap and ImmutableClassToInstanceMap.

RangeSet

A RangeSet describes a set of disconnected, nonempty ranges.

 RangeSet<Integer> rangeSet = TreeRangeSet.create();
   rangeSet.add(Range.closed(1, 10)); // {[1, 10]}
   rangeSet.add(Range.closedOpen(11, 15)); // disconnected range: {[1, 10], [11, 15)}
   rangeSet.add(Range.closedOpen(15, 20)); // connected range; {[1, 10], [11, 20)}
   rangeSet.add(Range.openClosed(0, 0)); // empty range; {[1, 10], [11, 20)}
   rangeSet.remove(Range.open(5, 10)); // splits [1, 10]; {[1, 5], [10, 10], [11, 20)}

Views

RangeSet implementations support an extremely wide range of views, including:
- complement():views the complement of the RangeSet.
- subRangeSet(Range<C>): returns a view of the intersection of the RangeSet with the specified Range.
- asRanges(): views the RangeSet as a Set<Range<C>> which can be iterated over.
- asSet(DiscreteDomain<C>) (ImmutableRangeSet only): Views the RangeSet<C> as an ImmutableSortedSet<C>, viewing the elements in the ranges instead of the ranges themselves.

Queries

to operations on its views:
* contains(C): the most fundamental operation on a RangeSet, querying if any range in the RangeSet contains the specified element.
* rangeContaining(C): returns the Range which encloses the specified element, or null if there is none.
* encloses(Range<C>): straightforwardly enough, tests if any Range in the RangeSet encloses the specified range.
* span(): returns the minimal Range that encloses every range in this RangeSet.

RangeMap

RangeMap is a collection type describing a mapping from disjoint, nonempty ranges to values.

RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(1, 10), "foo"); // {[1, 10] => "foo"}
rangeMap.put(Range.open(3, 6), "bar"); // {[1, 3] => "foo", (3, 6) => "bar", [6, 10] => "foo"}
rangeMap.put(Range.open(10, 20), "foo"); // {[1, 3] => "foo", (3, 6) => "bar", [6, 10] => "foo", (10, 20) => "foo"}
rangeMap.remove(Range.closed(5, 11)); // {[1, 3] => "foo", (3, 5) => "bar", (11, 20) => "foo"}

Views

RangeMap provides two views:
* asMapOfRanges(): views the RangeMap as a Map<Range<K>, V>.
* subRangeMap(Range<K>) views the intersection of the RangeMap with the specified Range as a RangeMap.

Collection Utilities

InterfaceJDK or Guava?Corresponding Guava utility class
CollectionJDKCollections2
ListJDKLists
SetJDKSets
SortedSetJDKSets
MapJDKMaps
SortedMapJDKMaps
QueueJDKQueues
MultisetGuavaMultisets
MultimapGuavaMultimaps
BiMapGuavaMaps
TableGuavaTables

Static constructors

List<TypeThatsTooLongForItsOwnGood> list = Lists.newArrayList();
Map<KeyType, LongishValueType> map = Maps.newLinkedHashMap();

Set<Type> copySet = Sets.newHashSet(elements);
List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");

List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
List<Type> approx100 = Lists.newArrayListWithExpectedSize(100);
Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);

Multiset<String> multiset = HashMultiset.create();

Iterables

Guava prefers to provide utilities accepting an Iterable rather than a Collection.

As of Guava 12, Iterables is supplemented by the FluentIterable class, which wraps an Iterable and provides a “fluent” syntax for many of these operations.

General

MethodDescriptionSee Also
concat(Iterable<Iterable>)Returns a lazy view of the concatenation of several iterables.concat(Iterable...)
frequency(Iterable, Object)Returns the number of occurrences of the object.Compare Collections.frequency(Collection, Object); see Multiset
partition(Iterable, int)Returns an unmodifiable view of the iterable partitioned into chunks of the specified size.Lists.partition(List, int), paddedPartition(Iterable, int)
getFirst(Iterable, T default)Returns the first element of the iterable, or the default value if empty.Compare Iterable.iterator().next(), FluentIterable.first()
getLast(Iterable)Returns the last element of the iterable, or fails fast with a NoSuchElementException if it’s empty.getLast(Iterable, T default), FluentIterable.last()
elementsEqual(Iterable, Iterable)Returns true if the iterables have the same elements in the same order.Compare List.equals(Object)
unmodifiableIterable(Iterable)Returns an unmodifiable view of the iterable.Compare Collections.unmodifiableCollection(Collection)
limit(Iterable, int)Returns an Iterable returning at most the specified number of elements.FluentIterable.limit(int)
getOnlyElement(Iterable)Returns the only element in Iterable. Fails fast if the iterable is empty or has multiple elements.getOnlyElement(Iterable, T default)
Iterable<Integer> concatenated = Iterables.concat(
  Ints.asList(1, 2, 3),
  Ints.asList(4, 5, 6));
// concatenated has elements 1, 2, 3, 4, 5, 6

String lastAdded = Iterables.getLast(myLinkedHashSet);

String theElement = Iterables.getOnlyElement(thisSetIsDefinitelyASingleton);
  // if this set isn't a singleton, something is wrong!

Collection-Like

MethodAnalogous Collection methodFluentIterable equivalent
addAll(Collection addTo, Iterable toAdd)Collection.addAll(Collection)
contains(Iterable, Object)Collection.contains(Object)FluentIterable.contains(Object)
removeAll(Iterable removeFrom, Collection toRemove)Collection.removeAll(Collection)
retainAll(Iterable removeFrom, Collection toRetain)Collection.retainAll(Collection)
size(Iterable)Collection.size()FluentIterable.size()
toArray(Iterable, Class)Collection.toArray(T[])FluentIterable.toArray(Class)
isEmpty(Iterable)Collection.isEmpty()FluentIterable.isEmpty()
get(Iterable, int)List.get(int)FluentIterable.get(int)
toString(Iterable)Collection.toString()FluentIterable.toString()

FluentIterable

FluentIterable has a few convenient methods for copying into an immutable collection:

Result TypeMethod
ImmutableListtoImmutableList()
ImmutableSettoImmutableSet()
ImmutableSortedSettoImmutableSortedSet(Comparator)

Lists

MethodDescription
partition(List, int)Returns a view of the underlying list, partitioned into chunks of the specified size.
reverse(List)Returns a reversed view of the specified list. Note: if the list is immutable, consider ImmutableList.reverse() instead.
List<Integer> countUp = Ints.asList(1, 2, 3, 4, 5);
List<Integer> countDown = Lists.reverse(theList); // {5, 4, 3, 2, 1}

List<List<Integer>> parts = Lists.partition(countUp, 2); // {{1, 2}, {3, 4}, {5}}

Static Factories

Lists provides the following static factory methods:

ImplementationFactories
ArrayListbasic, with elements, from Iterable, with exact capacity, with expected size, from Iterator
LinkedListbasic, from Iterable

Sets

Set-Theoretic Operations

provide a number of standard set-theoretic operations, implemented as views over the argument sets. These return a SetView, which can be used:

  • as a Set directly, since it implements the Set interface
  • by copying it into another mutable collection with copyInto(Set)
  • by making an immutable copy with immutableCopy()
Method
union(Set, Set)
intersection(Set, Set)
difference(Set, Set)
symmetricDifference(Set, Set)
Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");

SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
// I can use intersection as a Set directly, but copying it can be more efficient if I use it a lot.
return intersection.immutableCopy();

Other Set Utilities

MethodDescriptionSee Also
cartesianProduct(List<Set>)Returns every possible list that can be obtained by choosing one element from each set.cartesianProduct(Set...)
powerSet(Set)Returns the set of subsets of the specified set.
Set<String> animals = ImmutableSet.of("gerbil", "hamster");
Set<String> fruits = ImmutableSet.of("apple", "orange", "banana");

Set<List<String>> product = Sets.cartesianProduct(animals, fruits);
// {{"gerbil", "apple"}, {"gerbil", "orange"}, {"gerbil", "banana"},
//  {"hamster", "apple"}, {"hamster", "orange"}, {"hamster", "banana"}}

Set<Set<String>> animalSets = Sets.powerSet(animals);
// {{}, {"gerbil"}, {"hamster"}, {"gerbil", "hamster"}}

Static Factories

Sets provides the following static factory methods:

ImplementationFactories
HashSetbasic, with elements, from Iterable, with expected size, from Iterator
LinkedHashSetbasic, from Iterable, with expected size
TreeSetbasic, with Comparator, from Iterable

Maps

uniqueIndex

Maps.uniqueIndex(Iterable, Function) addresses the common case of having a bunch of objects that each have some unique attribute, and wanting to be able to look up those objects based on that attribute.

ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(strings, new Function<String, Integer> () {
    public Integer apply(String string) {
      return string.length();
    }
  });

difference

Maps.difference(Map, Map) allows you to compare all the differences between two maps. It returns a MapDifference object, which breaks down the Venn diagram into:

MethodDescription
entriesInCommon()The entries which are in both maps, with both matching keys and values.
entriesDiffering()The entries with the same keys, but differing values. The values in this map are of type MapDifference.ValueDifference, which lets you look at the left and right values.
entriesOnlyOnLeft()Returns the entries whose keys are in the left but not in the right map.
entriesOnlyOnRight()Returns the entries whose keys are in the right but not in the left map.
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
Map<String, Integer> right = ImmutableMap.of("b", 2, "c", 4, "d", 5);
MapDifference<String, Integer> diff = Maps.difference(left, right);

diff.entriesInCommon(); // {"b" => 2}
diff.entriesDiffering(); // {"c" => (3, 4)}
diff.entriesOnlyOnLeft(); // {"a" => 1}
diff.entriesOnlyOnRight(); // {"d" => 5}

BiMap utilities

The Guava utilities on BiMap live in the Maps class, since a BiMap is also a Map.

BiMap utilityCorresponding Map utility
synchronizedBiMap(BiMap)Collections.synchronizedMap(Map)
unmodifiableBiMap(BiMap)Collections.unmodifiableMap(Map)
Static Factories

Maps provides the following static factory methods.

ImplementationFactories
HashMapbasic, from Map, with expected size
LinkedHashMapbasic, from Map
TreeMapbasic, from Comparator, from SortedMap
EnumMapfrom Class, from Map
ConcurrentMapbasic
IdentityHashMapbasic

Multisets

Multisets provides a number of operations that take into account element multiplicities in multisets.

MethodExplanationDifference from Collection method
containsOccurrences(Multiset sup, Multiset sub)Returns true if sub.count(o) <= super.count(o) for all o.Collection.containsAll ignores counts, and only tests whether elements are contained at all.
removeOccurrences(Multiset removeFrom, Multiset toRemove)Removes one occurrence in removeFrom for each occurrence of an element in toRemove.Collection.removeAll removes all occurences of any element that occurs even once in toRemove.
retainOccurrences(Multiset removeFrom, Multiset toRetain)Guarantees that removeFrom.count(o) <= toRetain.count(o) for all o.Collection.retainAll keeps all occurrences of elements that occur even once in toRetain.
intersection(Multiset, Multiset)Returns a view of the intersection of two multisets; a nondestructive alternative to retainOccurrences.Has no analogue.
Multiset<String> multiset1 = HashMultiset.create();
multiset1.add("a", 2);

Multiset<String> multiset2 = HashMultiset.create();
multiset2.add("a", 5);

multiset1.containsAll(multiset2); // returns true: all unique elements are contained,
  // even though multiset1.count("a") == 2 < multiset2.count("a") == 5
Multisets.containsOccurrences(multiset1, multiset2); // returns false

multiset2.removeOccurrences(multiset1); // multiset2 now contains 3 occurrences of "a"

multiset2.removeAll(multiset1); // removes all occurrences of "a" from multiset2, even though multiset1.count("a") == 2
multiset2.isEmpty(); // returns true

Other utilities in Multisets include:

MethodDescription
copyHighestCountFirst(Multiset)Returns an immutable copy of the multiset that iterates over elements in descending frequency order.
unmodifiableMultiset(Multiset)Returns an unmodifiable view of the multiset.
unmodifiableSortedMultiset(SortedMultiset)Returns an unmodifiable view of the sorted multiset.
Multiset<String> multiset = HashMultiset.create();
multiset.add("a", 3);
multiset.add("b", 5);
multiset.add("c", 1);

ImmutableMultiset<String> highestCountFirst = Multisets.copyHighestCountFirst(multiset);

// highestCountFirst, like its entrySet and elementSet, iterates over the elements in order {"b", "a", "c"}

Multimaps

index

The cousin to Maps.uniqueIndex, Multimaps.index(Iterable, Function) answers the case when you want to be able to look up all objects with some particular attribute in common, which is not necessarily unique.

ImmutableSet<String> digits = ImmutableSet.of(
    "zero", "one", "two", "three", "four",
    "five", "six", "seven", "eight", "nine");
Function<String, Integer> lengthFunction = new Function<String, Integer>() {
  public Integer apply(String string) {
    return string.length();
  }
};
ImmutableListMultimap<Integer, String> digitsByLength = Multimaps.index(digits, lengthFunction);
/*
 * digitsByLength maps:
 *  3 => {"one", "two", "six"}
 *  4 => {"zero", "four", "five", "nine"}
 *  5 => {"three", "seven", "eight"}
 */

invertFrom

Since Multimap can map many keys to one value, and one key to many values, it can be useful to invert a Multimap. Guava provides invertFrom(Multimap toInvert, Multimap dest) to let you do this, without choosing an implementation for you.

ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create();
multimap.putAll("b", Ints.asList(2, 4, 6));
multimap.putAll("a", Ints.asList(4, 2, 1));
multimap.putAll("c", Ints.asList(2, 5, 3));

TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, TreeMultimap.<String, Integer> create());
// note that we choose the implementation, so if we use a TreeMultimap, we get results in order
/*
 * inverse maps:
 *  1 => {"a"}
 *  2 => {"a", "b", "c"}
 *  3 => {"c"}
 *  4 => {"a", "b"}
 *  5 => {"c"}
 *  6 => {"b"}
 */

forMap

Need to use a Multimap method on a Map? forMap(Map)views a Map as a SetMultimap.

Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 1, "c", 2);
SetMultimap<String, Inte### Wrappersger> multimap = Multimaps.forMap(map);
// multimap maps ["a" => {1}, "b" => {1}, "c" => {2}]
Multimap<Integer, String> inverse = Multimaps.invertFrom(multimap, HashMultimap.<Integer, String> create());
// inverse maps [1 => {"a", "b"}, 2 => {"c"}]

Wrappers

Multimaps provides the traditional wrapper methods, as well as tools to get custom Multimap implementations based on Map and Collection implementations of your choice.

Multimap typeUnmodifiableSynchronizedCustom
MultimapunmodifiableMultimapsynchronizedMultimapnewMultimap
ListMultimapunmodifiableListMultimapsynchronizedListMultimapnewListMultimap
SetMultimapunmodifiableSetMultimapsynchronizedSetMultimapnewSetMultimap
SortedSetMultimapunmodifiableSortedSetMultimapsynchronizedSortedSetMultimapnewSortedSetMultimap

Note that the custom Multimap methods expect a Supplier argument to generate fresh new collections. Here is an example of writing a ListMultimap backed by a TreeMap mapping to LinkedList.

ListMultimap<String, Integer> myMultimap = Multimaps.newListMultimap(
  Maps.<String, Collection<Integer>>newTreeMap(),
  new Supplier<LinkedList<Integer>>() {
    public LinkedList<Integer> get() {
      return Lists.newLinkedList();
    }
  });

Tables

customTable

Comparable to the Multimaps.newXXXMultimap(Map, Supplier) utilities, Tables.newCustomTable(Map, Supplier<Map>) allows you to specify a Table implementation using whatever row or column map you like.

// use LinkedHashMaps instead of HashMaps
Table<String, Character, Integer> table = Tables.newCustomTable(
  Maps.<String, Map<Character, Integer>>newLinkedHashMap(),
  new Supplier<Map<Character, Integer>> () {
    public Map<Character, Integer> get() {
      return Maps.newLinkedHashMap();
    }
  });

transpose

The transpose(Table<R, C, V>) method allows you to view a Table<R, C, V> as a Table<C, R, V>.

Wrappers

using ImmutableTable instead in most cases.
* unmodifiableTable
* unmodifiableRowSortedTable

Collection Helpers

Forwarding Decorators

Guava provides Forwarding abstract classes to simplify using the decorator pattern.

The Forwarding classes define one abstract method, delegate(), which you should override to return the decorated object. Each of the other methods delegate directly to the delegate: so, for example, ForwardingList.get(int) is simply implemented as delegate().get(int).

class AddLoggingList<E> extends ForwardingList<E> {
  final List<E> delegate; // backing list
  @Override protected List<E> delegate() {
    return delegate;
  }
  @Override public void add(int index, E elem) {
    log(index, elem);
    super.add(index, elem);
  }
  @Override public boolean add(E elem) {
    return standardAdd(elem); // implements in terms of add(int, E)
  }
  @Override public boolean addAll(Collection<? extends E> c) {
    return standardAddAll(c); // implements in terms of add
  }
}
InterfaceForwarding Decorator
CollectionForwardingCollection
ListForwardingList
SetForwardingSet
SortedSetForwardingSortedSet
MapForwardingMap
SortedMapForwardingSortedMap
ConcurrentMapForwardingConcurrentMap
Map.EntryForwardingMapEntry
QueueForwardingQueue
IteratorForwardingIterator
ListIteratorForwardingListIterator
MultisetForwardingMultiset
MultimapForwardingMultimap
ListMultimapForwardingListMultimap
SetMultimapForwardingSetMultimap

PeekingIterator

Iterators supports the method Iterators.peekingIterator(Iterator), which wraps an Iterator and returns a PeekingIterator, a subtype of Iterator that lets you peek() at the element that will be returned by the next call to next().

List<E> result = Lists.newArrayList();
PeekingIterator<E> iter = Iterators.peekingIterator(source.iterator());
while (iter.hasNext()) {
  E current = iter.next();
  while (iter.hasNext() && iter.peek().equals(current)) {
    // skip this duplicate element
    iter.next();
  }
  result.add(current);
}

AbstractIterator

Implementing your own Iterator? AbstractIterator can make your life easier.

public static Iterator<String> skipNulls(final Iterator<String> in) {
  return new AbstractIterator<String>() {
    protected String computeNext() {
      while (in.hasNext()) {
        String s = in.next();
        if (s != null) {
          return s;
        }
      }
      return endOfData();
    }
  };
}

AbstractSequentialIterator

AbstractSequentialIterator provides another way of expressing an iteration.

Iterator<Integer> powersOfTwo = new AbstractSequentialIterator<Integer>(1) { // note the initial value!
  protected Integer computeNext(Integer previous) {
    return (previous == 1 << 30) ? null : previous * 2;
  }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值