Fundamentals 27 min read

Powerful Collection Utility Classes: Guava Tools Not Covered by java.util.Collections

This article explains Guava's extensive collection utility classes that complement or replace java.util.Collections, covering static factory methods, Iterable utilities, and specialized tools for Lists, Sets, Maps, Multisets, Multimaps, and Tables, with code examples illustrating their usage and advantages.

Qunar Tech Salon
Qunar Tech Salon
Qunar Tech Salon
Powerful Collection Utility Classes: Guava Tools Not Covered by java.util.Collections

Powerful Collection Utility Classes: Guava Tools Not Covered by java.util.Collections

We summarize the relationship between collection interfaces and the corresponding utility classes in a clear way.

Collection Interface

Provided by JDK or Guava

Corresponding Guava Utility Class

Collection

JDK

Collections2

Do not confuse with java.util.Collections

List

JDK

Lists

Set

JDK

Sets

SortedSet

JDK

Sets

Map

JDK

Maps

SortedMap

JDK

Maps

Queue

JDK

Queues

Multiset

Guava

Multisets

Multimap

Guava

Multimaps

BiMap

Guava

Maps

Table

Guava

Tables

Static Factory Methods

Before JDK 7, creating a generic collection required repeating the generic type, which was cumbersome:

List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<TypeThatsTooLongForItsOwnGood>();

Guava provides static factory methods that infer the generic type, making code concise:

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

JDK 7’s diamond operator ( <> ) eliminates this problem, but Guava’s factories offer additional flexibility, such as initializing a collection with elements or specifying an initial capacity.

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);

Iterables

Guava prefers methods that accept Iterable rather than Collection , because some data sources (e.g., database streams) cannot provide a size without materializing all elements.

Most Iterables methods have a counterpart in Iterators for working directly with Iterator s.

Since Guava 1.2, Iterables is supplemented by FluentIterable , which offers a fluent (chainable) API.

Common Methods

concat(Iterable<Iterable>)

Lazily concatenates multiple iterables

concat(Iterable...)

frequency(Iterable, Object)

Counts occurrences of an element

Comparable to Collections.frequency(Collection, Object)

partition(Iterable, int)

Partitions the iterable into fixed‑size, unmodifiable sub‑lists

Lists.partition(List, int); paddedPartition(Iterable, int)

getFirst(Iterable, T default)

Returns the first element or a default value if empty

Comparable to Iterable.iterator().next(); FluentIterable.first()

getLast(Iterable)

Returns the last element or throws

NoSuchElementException

if empty

getLast(Iterable, T default); FluentIterable.last()

elementsEqual(Iterable, Iterable)

True if both iterables contain equal elements in the same order

Comparable to List.equals(Object)

unmodifiableIterable(Iterable)

Returns an unmodifiable view

Comparable to Collections.unmodifiableCollection(Collection)

limit(Iterable, int)

Limits the number of elements returned

FluentIterable.limit(int)

getOnlyElement(Iterable)

Returns the sole element, failing fast if none or more than one

getOnlyElement(Iterable, T default)

Lists

Beyond static factories and functional‑style methods, Lists offers several utilities for List objects.

Method

Description

partition(List, int)

Splits the list into sub‑lists of the given size

reverse(List)

Returns a view of the list in reverse order (use

ImmutableList.reverse()

for immutable lists)

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

Sets

Sets provides a rich set of set‑theoretic operations.

Method

union(Set, Set)

intersection(Set, Set)

difference(Set, Set)

symmetricDifference(Set, Set)

Example:

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"
ImmutableSet<String> result = intersection.immutableCopy();

Other Set Utilities

Method

Description

See Also

cartesianProduct(List<Set>)

Returns the Cartesian product of all sets

cartesianProduct(Set...)

powerSet(Set)

Returns all subsets of the given 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"}, …}
Set<Set<String>> animalSets = Sets.powerSet(animals);
// {{}, {"gerbil"}, {"hamster"}, {"gerbil","hamster"}}

Maps

Maps contains several noteworthy methods.

uniqueIndex

Maps.uniqueIndex(Iterable, Function) builds a map where the key is the value returned by the function and the value is the original element. It is useful when each element has a unique attribute.

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

If the index values are not unique, use Multimaps.index instead.

difference

Maps.difference(Map, Map) compares two maps and returns a MapDifference object with four views:

entriesInCommon() – entries present in both maps with identical values

entriesDiffering() – same keys with different values

entriesOnlyOnLeft() – entries only in the left map

entriesOnlyOnRight() – entries only in the right 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

BiMap is a special map with a one‑to‑one relationship. Guava provides:

synchronizedBiMap(BiMap) – thread‑safe wrapper (similar to Collections.synchronizedMap )

unmodifiableBiMap(BiMap) – read‑only view (similar to Collections.unmodifiableMap )

Static Factory Methods for Maps

Implementation

Factory Methods

HashMap

basic, from Map, with expected size

LinkedHashMap

basic, from Map

TreeMap

basic, from Comparator, from SortedMap

EnumMap

from Class, from Map

ConcurrentMap

basic (supports all operations)

IdentityHashMap

basic

Multisets

Standard collection operations ignore element multiplicities. Multisets offers methods that respect counts.

Method

Description

Difference from Collection

containsOccurrences(Multiset sup, Multiset sub)

True if for every element o, sub.count(o) ≤ sup.count(o)

Collection.containsAll ignores multiplicities

removeOccurrences(Multiset removeFrom, Multiset toRemove)

Removes from

removeFrom

the same number of occurrences as in

toRemove

Collection.removeAll removes all matching elements

retainOccurrences(Multiset removeFrom, Multiset toRetain)

Keeps at most the count of each element present in

toRetain

Collection.retainAll keeps all matching elements

intersection(Multiset, Multiset)

Returns the multiset intersection

No direct Collection equivalent

Multiset<String> multiset1 = HashMultiset.create();
multiset1.add("a", 2);
Multiset<String> multiset2 = HashMultiset.create();
multiset2.add("a", 5);
boolean containsAll = multiset1.containsAll(multiset2); // true (ignores counts)
boolean containsOccurrences = Multisets.containsOccurrences(multiset1, multiset2); // false
Multisets.removeOccurrences(multiset2, multiset1); // multiset2 now has 3 "a"
multiset2.removeAll(multiset1); // removes all "a", multiset2 becomes empty

Other useful methods:

copyHighestCountFirst(Multiset) – immutable copy sorted by descending count

unmodifiableMultiset(Multiset) – read‑only view

unmodifiableSortedMultiset(SortedMultiset) – read‑only view for sorted multisets

Multiset<String> multiset = HashMultiset.create();
multiset.add("a", 3);
multiset.add("b", 5);
multiset.add("c", 1);
ImmutableMultiset<String> highest = Multisets.copyHighestCountFirst(multiset); // order: b, a, c

Multimaps

Multimaps provides utilities for working with Multimap structures.

index

Similar to Maps.uniqueIndex but allows non‑unique keys. It groups elements by the value returned by a function.

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

invertFrom

Reverses a Multimap , turning values into keys. Choose the destination implementation to control ordering.

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.create());
// inverse: 1 → {"a"}, 2 → {"a","b","c"}, 3 → {"c"}, 4 → {"a","b"}, 5 → {"c"}, 6 → {"b"}

forMap

Wraps a regular Map as a SetMultimap , useful for treating a many‑to‑one map as a one‑to‑many multimap.

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

Custom Multimaps and Wrappers

Guava offers read‑only, synchronized, and custom implementations for Multimap , ListMultimap , SetMultimap , and SortedSetMultimap . Custom multimaps require a Supplier to create fresh collections for each key.

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

Tables

Tables offers utilities for two‑dimensional map structures.

Custom Table

Tables.newCustomTable(Map, Supplier<Map>) lets you choose the map implementation for rows and columns.

// Use LinkedHashMaps for deterministic ordering
Table<String,Character,Integer> table = Tables.newCustomTable(
    Maps.
>newLinkedHashMap(),
    new Supplier<Map
() {
        public Map
get() { return Maps.newLinkedHashMap(); }
    });

transpose

Tables.transpose(Table<R,C,V>) swaps rows and columns, useful for reversing a directed graph represented as a table.

Immutable and Wrapper Variants

Prefer ImmutableTable for safety. Wrapper classes include unmodifiable and synchronized versions for Table and RowSortedTable .

[Source: Concurrency Programming Network]

CollectionsIterablesMultimapsUtilityClasses
Qunar Tech Salon
Written by

Qunar Tech Salon

Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.