0
# Collections
1
2
Enhanced collection types and utilities including multimaps, multisets, tables, and powerful collection transformation operations. These utilities extend Java's collection framework with additional data structures and convenient operations.
3
4
## Package: com.google.common.collect
5
6
### Collection Utilities
7
8
Static utility methods for creating and manipulating collections.
9
10
```java { .api }
11
import com.google.common.collect.Lists;
12
import com.google.common.collect.Sets;
13
import com.google.common.collect.Maps;
14
15
// Creating lists
16
List<String> arrayList = Lists.newArrayList("a", "b", "c");
17
List<String> linkedList = Lists.newLinkedList();
18
List<String> withCapacity = Lists.newArrayListWithCapacity(100);
19
20
// List operations
21
List<String> reversed = Lists.reverse(originalList);
22
List<List<String>> partitioned = Lists.partition(list, 3); // Split into chunks of 3
23
List<Character> chars = Lists.charactersOf("hello"); // ['h', 'e', 'l', 'l', 'o']
24
25
// Creating sets
26
Set<String> hashSet = Sets.newHashSet("a", "b", "c");
27
Set<String> linkedHashSet = Sets.newLinkedHashSet();
28
SortedSet<String> treeSet = Sets.newTreeSet();
29
30
// Set operations
31
Set<String> union = Sets.union(set1, set2);
32
Set<String> intersection = Sets.intersection(set1, set2);
33
Set<String> difference = Sets.difference(set1, set2);
34
Set<String> symmetricDifference = Sets.symmetricDifference(set1, set2);
35
36
// Power set (all possible subsets)
37
Set<Set<String>> powerSet = Sets.powerSet(ImmutableSet.of("a", "b", "c"));
38
39
// Creating maps
40
Map<String, Integer> hashMap = Maps.newHashMap();
41
Map<String, Integer> linkedHashMap = Maps.newLinkedHashMap();
42
SortedMap<String, Integer> treeMap = Maps.newTreeMap();
43
ConcurrentMap<String, Integer> concurrentMap = Maps.newConcurrentMap();
44
```
45
46
### Iterables
47
48
Static utility methods for working with Iterable instances. Provides functional-style operations and convenient methods for common iterable manipulations.
49
50
```java { .api }
51
import com.google.common.collect.Iterables;
52
import com.google.common.base.Predicate;
53
import com.google.common.base.Function;
54
55
// Size and containment
56
int size = Iterables.size(iterable);
57
boolean contains = Iterables.contains(iterable, element);
58
int frequency = Iterables.frequency(iterable, element);
59
boolean isEmpty = Iterables.isEmpty(iterable);
60
61
// Element access
62
String first = Iterables.getFirst(iterable, "default");
63
String last = Iterables.getLast(iterable);
64
String element = Iterables.get(iterable, 2); // Get element at index 2
65
String only = Iterables.getOnlyElement(iterable); // Expects exactly one element
66
67
// Filtering and transformation
68
Iterable<String> filtered = Iterables.filter(iterable, new Predicate<String>() {
69
public boolean apply(String s) { return s.startsWith("A"); }
70
});
71
72
Iterable<String> byType = Iterables.filter(objects, String.class);
73
74
Iterable<Integer> transformed = Iterables.transform(strings, new Function<String, Integer>() {
75
public boolean apply(String s) { return s.length(); }
76
});
77
78
// Finding elements
79
String found = Iterables.find(iterable, predicate);
80
String foundOrNull = Iterables.find(iterable, predicate, null);
81
Optional<String> tryFind = Iterables.tryFind(iterable, predicate);
82
int index = Iterables.indexOf(iterable, predicate);
83
84
// Predicates
85
boolean any = Iterables.any(iterable, predicate);
86
boolean all = Iterables.all(iterable, predicate);
87
88
// Combining and partitioning
89
Iterable<String> concatenated = Iterables.concat(iterable1, iterable2, iterable3);
90
Iterable<String> cycled = Iterables.cycle("A", "B", "C"); // Infinite cycle
91
Iterable<List<String>> partitioned = Iterables.partition(iterable, 3);
92
93
// Skipping and limiting
94
Iterable<String> skipped = Iterables.skip(iterable, 5);
95
Iterable<String> limited = Iterables.limit(iterable, 10);
96
97
// Conversion
98
String[] array = Iterables.toArray(iterable, String.class);
99
boolean added = Iterables.addAll(collection, iterable);
100
101
// Comparison and equality
102
boolean equal = Iterables.elementsEqual(iterable1, iterable2);
103
String string = Iterables.toString(iterable);
104
105
// Collection modification
106
boolean removed = Iterables.removeAll(iterable, elementsToRemove);
107
boolean retained = Iterables.retainAll(iterable, elementsToRetain);
108
boolean removedIf = Iterables.removeIf(iterable, predicate);
109
```
110
111
**Key Methods:**
112
- `size(Iterable)` - Returns number of elements
113
- `contains(Iterable, Object)` - Tests if element is present
114
- `getFirst(Iterable, T)` / `getLast(Iterable)` - Get first/last elements
115
- `get(Iterable, int)` - Get element at specific position
116
- `getOnlyElement(Iterable)` - Get single element (throws if not exactly one)
117
- `filter(Iterable, Predicate)` - Filter elements by predicate
118
- `filter(Iterable, Class)` - Filter by type
119
- `transform(Iterable, Function)` - Transform elements
120
- `find(Iterable, Predicate)` - Find first matching element
121
- `tryFind(Iterable, Predicate)` - Find first matching element as Optional
122
- `any(Iterable, Predicate)` / `all(Iterable, Predicate)` - Test predicates
123
- `concat(Iterable...)` - Concatenate multiple iterables
124
- `cycle(T...)` / `cycle(Iterable)` - Create cyclic iterable
125
- `partition(Iterable, int)` - Split into fixed-size chunks
126
- `skip(Iterable, int)` - Skip first N elements
127
- `limit(Iterable, int)` - Limit to first N elements
128
- `elementsEqual(Iterable, Iterable)` - Compare element-wise equality
129
130
### Iterators
131
132
Static utility methods for working with Iterator instances. Companion to Iterables with iterator-specific operations.
133
134
```java { .api }
135
import com.google.common.collect.Iterators;
136
137
// Size and advancement
138
int size = Iterators.size(iterator);
139
boolean advanced = Iterators.advance(iterator, 5); // Skip 5 elements
140
Iterator<T> consumed = Iterators.consumingIterator(iterator);
141
142
// Element access
143
T next = Iterators.getNext(iterator, defaultValue);
144
T last = Iterators.getLast(iterator);
145
T only = Iterators.getOnlyElement(iterator);
146
147
// Filtering and transformation
148
Iterator<String> filtered = Iterators.filter(iterator, predicate);
149
Iterator<String> byType = Iterators.filter(objects, String.class);
150
Iterator<Integer> transformed = Iterators.transform(strings, function);
151
152
// Finding
153
T found = Iterators.find(iterator, predicate);
154
Optional<T> tryFind = Iterators.tryFind(iterator, predicate);
155
int index = Iterators.indexOf(iterator, predicate);
156
157
// Predicates
158
boolean any = Iterators.any(iterator, predicate);
159
boolean all = Iterators.all(iterator, predicate);
160
161
// Combining
162
Iterator<T> concatenated = Iterators.concat(iter1, iter2, iter3);
163
Iterator<T> cycled = Iterators.cycle(list); // Infinite cycle over list
164
Iterator<List<T>> partitioned = Iterators.partition(iterator, batchSize);
165
166
// Limiting and peeking
167
Iterator<T> limited = Iterators.limit(iterator, maxElements);
168
PeekingIterator<T> peeking = Iterators.peekingIterator(iterator);
169
T peeked = peeking.peek(); // Look at next without consuming
170
171
// Conversion
172
List<T> list = Iterators.toList(iterator);
173
T[] array = Iterators.toArray(iterator, clazz);
174
boolean added = Iterators.addAll(collection, iterator);
175
176
// Unmodifiable wrappers
177
Iterator<T> unmodifiable = Iterators.unmodifiableIterator(iterator);
178
ListIterator<T> unmodifiableList = Iterators.unmodifiableListIterator(listIterator);
179
180
// Comparison
181
boolean equal = Iterators.elementsEqual(iter1, iter2);
182
String string = Iterators.toString(iterator);
183
184
// Collection modification
185
int removed = Iterators.removeAll(iterator, elementsToRemove);
186
int retained = Iterators.retainAll(iterator, elementsToRetain);
187
boolean removedIf = Iterators.removeIf(iterator, predicate);
188
```
189
190
**Key Methods:**
191
- `size(Iterator)` - Count remaining elements (consumes iterator)
192
- `advance(Iterator, int)` - Skip N elements
193
- `getNext(Iterator, T)` - Get next element with default
194
- `getLast(Iterator)` - Get last element (consumes iterator)
195
- `filter(Iterator, Predicate)` - Filter by predicate
196
- `transform(Iterator, Function)` - Transform elements
197
- `find(Iterator, Predicate)` - Find first matching element
198
- `concat(Iterator...)` - Concatenate multiple iterators
199
- `cycle(Iterable)` - Create infinite cycling iterator
200
- `partition(Iterator, int)` - Batch elements into lists
201
- `limit(Iterator, int)` - Limit number of elements
202
- `peekingIterator(Iterator)` - Wrap to support peeking
203
- `consumingIterator(Iterator)` - Remove elements as they're accessed
204
- `toList(Iterator)` / `toArray(Iterator, Class)` - Convert to collections
205
206
### Multimap
207
208
A collection that maps keys to multiple values, similar to `Map<K, Collection<V>>` but with a cleaner API.
209
210
```java { .api }
211
import com.google.common.collect.Multimap;
212
import com.google.common.collect.ArrayListMultimap;
213
import com.google.common.collect.HashMultimap;
214
import com.google.common.collect.LinkedHashMultimap;
215
216
// Creating multimaps
217
ListMultimap<String, String> listMultimap = ArrayListMultimap.create();
218
SetMultimap<String, String> setMultimap = HashMultimap.create();
219
SetMultimap<String, String> orderedMultimap = LinkedHashMultimap.create();
220
221
// Adding values
222
listMultimap.put("fruits", "apple");
223
listMultimap.put("fruits", "banana");
224
listMultimap.put("fruits", "apple"); // Duplicates allowed in ListMultimap
225
listMultimap.put("vegetables", "carrot");
226
227
// Retrieving values
228
Collection<String> fruits = listMultimap.get("fruits"); // ["apple", "banana", "apple"]
229
boolean hasFruit = listMultimap.containsKey("fruits"); // true
230
boolean hasApple = listMultimap.containsValue("apple"); // true
231
boolean hasEntry = listMultimap.containsEntry("fruits", "apple"); // true
232
233
// Bulk operations
234
listMultimap.putAll("colors", Arrays.asList("red", "green", "blue"));
235
listMultimap.removeAll("fruits"); // Removes all values for key
236
listMultimap.replaceValues("vegetables", Arrays.asList("carrot", "potato"));
237
238
// Views
239
Set<String> keys = listMultimap.keySet(); // All keys
240
Collection<String> values = listMultimap.values(); // All values
241
Collection<Map.Entry<String, String>> entries = listMultimap.entries(); // All key-value pairs
242
Map<String, Collection<String>> mapView = listMultimap.asMap(); // Map view
243
244
// Size operations
245
int size = listMultimap.size(); // Total number of key-value pairs
246
int keyCount = listMultimap.keySet().size(); // Number of distinct keys
247
boolean empty = listMultimap.isEmpty();
248
```
249
250
**Multimap Implementations:**
251
- `ArrayListMultimap` - Backed by ArrayList for each key (allows duplicate values, preserves order)
252
- `HashMultimap` - Backed by HashSet for each key (no duplicate values, no order guarantees)
253
- `LinkedHashMultimap` - Backed by LinkedHashSet for each key (no duplicates, preserves insertion order)
254
- `TreeMultimap` - Backed by TreeSet for each key (sorted values, no duplicates)
255
256
### Multiset
257
258
A collection that allows duplicate elements and provides count-based operations.
259
260
```java { .api }
261
import com.google.common.collect.Multiset;
262
import com.google.common.collect.HashMultiset;
263
import com.google.common.collect.TreeMultiset;
264
265
// Creating multisets
266
Multiset<String> multiset = HashMultiset.create();
267
Multiset<String> sorted = TreeMultiset.create();
268
269
// Adding elements with counts
270
multiset.add("apple"); // count: 1
271
multiset.add("apple", 5); // count: 6
272
multiset.setCount("banana", 3); // Set absolute count
273
274
// Counting elements
275
int appleCount = multiset.count("apple"); // 6
276
int totalSize = multiset.size(); // Total number of elements (including duplicates)
277
int distinctSize = multiset.elementSet().size(); // Number of distinct elements
278
279
// Removing elements
280
multiset.remove("apple"); // count: 5
281
multiset.remove("apple", 2); // count: 3
282
multiset.setCount("apple", 0); // Remove completely
283
284
// Views
285
Set<String> distinctElements = multiset.elementSet(); // Unique elements
286
Set<Multiset.Entry<String>> entries = multiset.entrySet(); // Element-count pairs
287
288
// Iterating with counts
289
for (Multiset.Entry<String> entry : multiset.entrySet()) {
290
String element = entry.getElement();
291
int count = entry.getCount();
292
System.out.println(element + " appears " + count + " times");
293
}
294
295
// Multiset operations using Multisets utility class
296
import com.google.common.collect.Multisets;
297
298
Multiset<String> intersection = Multisets.intersection(multiset1, multiset2);
299
Multiset<String> union = Multisets.union(multiset1, multiset2);
300
boolean containsAll = Multisets.containsOccurrences(multiset1, multiset2);
301
```
302
303
### BiMap
304
305
A bidirectional map that maintains both key-to-value and value-to-key mappings, ensuring that values are unique.
306
307
```java { .api }
308
import com.google.common.collect.BiMap;
309
import com.google.common.collect.HashBiMap;
310
311
// Creating BiMap
312
BiMap<String, Integer> bimap = HashBiMap.create();
313
314
// Adding entries (values must be unique)
315
bimap.put("one", 1);
316
bimap.put("two", 2);
317
bimap.put("three", 3);
318
319
// Forward mapping
320
Integer value = bimap.get("one"); // 1
321
322
// Inverse mapping
323
BiMap<Integer, String> inverse = bimap.inverse();
324
String key = inverse.get(1); // "one"
325
326
// Forced put (removes existing mappings)
327
bimap.forcePut("four", 1); // Removes "one" -> 1 mapping
328
329
// Handling duplicate values
330
try {
331
bimap.put("four", 2); // Throws IllegalArgumentException (2 already mapped to "two")
332
} catch (IllegalArgumentException e) {
333
// Handle duplicate value
334
}
335
```
336
337
### Table
338
339
A collection similar to `Map<R, Map<C, V>>` but with a cleaner API for two-dimensional data.
340
341
```java { .api }
342
import com.google.common.collect.Table;
343
import com.google.common.collect.HashBasedTable;
344
import com.google.common.collect.TreeBasedTable;
345
import com.google.common.collect.ArrayTable;
346
347
// Creating tables
348
Table<String, String, Integer> table = HashBasedTable.create();
349
Table<String, String, Integer> sortedTable = TreeBasedTable.create();
350
351
// Adding data (row, column, value)
352
table.put("John", "Math", 95);
353
table.put("John", "Science", 87);
354
table.put("Jane", "Math", 92);
355
table.put("Jane", "Science", 94);
356
357
// Retrieving data
358
Integer johnMath = table.get("John", "Math"); // 95
359
boolean hasEntry = table.contains("John", "Math"); // true
360
boolean hasRow = table.containsRow("John"); // true
361
boolean hasColumn = table.containsColumn("Math"); // true
362
363
// Row and column views
364
Map<String, Integer> johnScores = table.row("John"); // {Math=95, Science=87}
365
Map<String, Integer> mathScores = table.column("Math"); // {John=95, Jane=92}
366
367
// All data views
368
Set<String> students = table.rowKeySet(); // [John, Jane]
369
Set<String> subjects = table.columnKeySet(); // [Math, Science]
370
Collection<Integer> allScores = table.values(); // [95, 87, 92, 94]
371
Set<Table.Cell<String, String, Integer>> cells = table.cellSet();
372
373
// Size and operations
374
int size = table.size(); // 4
375
table.remove("John", "Math");
376
table.clear();
377
378
// Array-based table (for dense data with known row/column sets)
379
List<String> students = Arrays.asList("John", "Jane", "Bob");
380
List<String> subjects = Arrays.asList("Math", "Science", "History");
381
Table<String, String, Integer> arrayTable = ArrayTable.create(students, subjects);
382
```
383
384
### Range
385
386
Immutable ranges of Comparable values with various boundary types.
387
388
```java { .api }
389
import com.google.common.collect.Range;
390
import com.google.common.collect.RangeSet;
391
import com.google.common.collect.TreeRangeSet;
392
393
// Creating ranges
394
Range<Integer> open = Range.open(1, 5); // (1, 5) - excludes endpoints
395
Range<Integer> closed = Range.closed(1, 5); // [1, 5] - includes endpoints
396
Range<Integer> openClosed = Range.openClosed(1, 5); // (1, 5]
397
Range<Integer> closedOpen = Range.closedOpen(1, 5); // [1, 5)
398
399
// Unbounded ranges
400
Range<Integer> atLeast = Range.atLeast(5); // [5, +∞)
401
Range<Integer> lessThan = Range.lessThan(5); // (-∞, 5)
402
Range<Integer> greaterThan = Range.greaterThan(5); // (5, +∞)
403
Range<Integer> atMost = Range.atMost(5); // (-∞, 5]
404
Range<Integer> all = Range.all(); // (-∞, +∞)
405
406
// Range operations
407
boolean contains = closed.contains(3); // true
408
boolean encloses = Range.closed(1, 10).encloses(Range.closed(2, 8)); // true
409
410
// Range intersection and span
411
Range<Integer> intersection = Range.closed(1, 5).intersection(Range.closed(3, 7)); // [3, 5]
412
Range<Integer> span = Range.closed(1, 3).span(Range.closed(5, 7)); // [1, 7]
413
414
// Range sets - collection of non-overlapping ranges
415
RangeSet<Integer> rangeSet = TreeRangeSet.create();
416
rangeSet.add(Range.closed(1, 10));
417
rangeSet.add(Range.closed(15, 20));
418
rangeSet.remove(Range.open(5, 7));
419
// Result: [1, 5] ∪ [7, 10] ∪ [15, 20]
420
421
boolean inSet = rangeSet.contains(6); // false
422
RangeSet<Integer> complement = rangeSet.complement();
423
```
424
425
### Iterables and Iterators
426
427
Powerful utilities for working with Iterable and Iterator objects.
428
429
```java { .api }
430
import com.google.common.collect.Iterables;
431
import com.google.common.collect.Iterators;
432
import com.google.common.base.Predicate;
433
import com.google.common.base.Function;
434
435
// Concatenation
436
Iterable<String> combined = Iterables.concat(list1, list2, list3);
437
438
// Transformation
439
Iterable<Integer> lengths = Iterables.transform(strings, new Function<String, Integer>() {
440
public Integer apply(String input) {
441
return input.length();
442
}
443
});
444
445
// Filtering
446
Predicate<String> notEmpty = new Predicate<String>() {
447
public boolean apply(String input) {
448
return !input.isEmpty();
449
}
450
};
451
Iterable<String> filtered = Iterables.filter(strings, notEmpty);
452
453
// Finding elements
454
String first = Iterables.find(strings, notEmpty); // First matching element
455
Optional<String> found = Iterables.tryFind(strings, notEmpty); // Optional result
456
457
// Size and emptiness
458
int size = Iterables.size(iterable); // Works with any Iterable
459
boolean empty = Iterables.isEmpty(iterable);
460
461
// Element access
462
String first = Iterables.getFirst(strings, "default");
463
String last = Iterables.getLast(strings, "default");
464
String third = Iterables.get(strings, 2, "default"); // Index-based access
465
466
// Limiting and skipping
467
Iterable<String> limited = Iterables.limit(strings, 10); // First 10 elements
468
Iterable<String> skipped = Iterables.skip(strings, 5); // Skip first 5 elements
469
470
// Cycling and partitioning
471
Iterable<String> cycled = Iterables.cycle(strings); // Infinite repetition
472
Iterable<List<String>> partitioned = Iterables.partition(strings, 3); // Groups of 3
473
474
// Similar operations available for Iterators
475
Iterator<String> concatenated = Iterators.concat(iter1, iter2);
476
Iterator<Integer> transformed = Iterators.transform(stringIter, lengthFunction);
477
Iterator<String> filtered2 = Iterators.filter(stringIter, predicate);
478
```
479
480
### Map Utilities
481
482
Advanced map operations including transformations, filtering, and specialized map types.
483
484
```java { .api }
485
import com.google.common.collect.Maps;
486
import com.google.common.collect.MapDifference;
487
488
// Map transformation
489
Map<String, String> upperCaseKeys = Maps.transformKeys(originalMap,
490
new Function<String, String>() {
491
public String apply(String key) {
492
return key.toUpperCase();
493
}
494
});
495
496
Map<String, Integer> lengthValues = Maps.transformValues(stringMap,
497
new Function<String, Integer>() {
498
public Integer apply(String value) {
499
return value.length();
500
}
501
});
502
503
// Map filtering
504
Map<String, Integer> filteredByKeys = Maps.filterKeys(map,
505
new Predicate<String>() {
506
public boolean apply(String key) {
507
return key.startsWith("a");
508
}
509
});
510
511
Map<String, Integer> filteredByValues = Maps.filterValues(map,
512
new Predicate<Integer>() {
513
public boolean apply(Integer value) {
514
return value > 10;
515
}
516
});
517
518
// Map differences
519
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
520
Map<String, Integer> right = ImmutableMap.of("a", 1, "b", 4, "d", 5);
521
MapDifference<String, Integer> diff = Maps.difference(left, right);
522
523
Map<String, Integer> entriesOnlyOnLeft = diff.entriesOnlyOnLeft(); // {c=3}
524
Map<String, Integer> entriesOnlyOnRight = diff.entriesOnlyOnRight(); // {d=5}
525
Map<String, Integer> entriesInCommon = diff.entriesInCommon(); // {a=1}
526
Map<String, MapDifference.ValueDifference<Integer>> entriesDiffering = diff.entriesDiffering(); // {b=(2, 4)}
527
528
// Creating map from properties
529
Properties props = new Properties();
530
Map<String, String> mapFromProps = Maps.fromProperties(props);
531
```
532
533
### Advanced Collection Operations
534
535
```java { .api }
536
import com.google.common.collect.Collections2;
537
import com.google.common.collect.Ordering;
538
539
// Collection transformation and filtering
540
Collection<Integer> lengths = Collections2.transform(strings, lengthFunction);
541
Collection<String> filtered = Collections2.filter(strings, notEmptyPredicate);
542
543
// Permutations
544
Collection<List<String>> permutations = Collections2.permutations(Arrays.asList("a", "b", "c"));
545
// Results in: [[a,b,c], [a,c,b], [b,a,c], [b,c,a], [c,a,b], [c,b,a]]
546
547
// Ordering (comparator utilities)
548
Ordering<String> byLength = Ordering.natural().onResultOf(new Function<String, Integer>() {
549
public Integer apply(String input) {
550
return input.length();
551
}
552
});
553
554
List<String> sorted = byLength.sortedCopy(strings);
555
String min = byLength.min(strings);
556
String max = byLength.max(strings);
557
List<String> greatest = byLength.greatestOf(strings, 3);
558
List<String> least = byLength.leastOf(strings, 3);
559
560
// Compound ordering
561
Ordering<Person> byAgeThemByName = Ordering.natural()
562
.onResultOf(new Function<Person, Integer>() {
563
public Integer apply(Person p) { return p.getAge(); }
564
})
565
.compound(Ordering.natural().onResultOf(new Function<Person, String>() {
566
public String apply(Person p) { return p.getName(); }
567
}));
568
```
569
570
### Synchronized and Concurrent Collections
571
572
```java { .api }
573
import com.google.common.collect.Multimaps;
574
import com.google.common.collect.Multisets;
575
import com.google.common.collect.Tables;
576
577
// Synchronized wrappers
578
Multimap<String, String> syncMultimap = Multimaps.synchronizedMultimap(multimap);
579
Multiset<String> syncMultiset = Multisets.synchronizedMultiset(multiset);
580
Table<String, String, Integer> syncTable = Tables.synchronizedTable(table);
581
582
// Unmodifiable views
583
Multimap<String, String> unmodifiableMultimap = Multimaps.unmodifiableMultimap(multimap);
584
Multiset<String> unmodifiableMultiset = Multisets.unmodifiableMultiset(multiset);
585
586
// Creating multimaps from existing maps
587
Map<String, String> existingMap = Maps.newHashMap();
588
Multimap<String, String> multimapFromMap = Multimaps.forMap(existingMap);
589
590
// Index operations - creating multimaps by indexing collections
591
List<String> words = Arrays.asList("apple", "banana", "apricot", "blueberry");
592
Multimap<Character, String> byFirstLetter = Multimaps.index(words,
593
new Function<String, Character>() {
594
public Character apply(String word) {
595
return word.charAt(0);
596
}
597
});
598
// Result: {a=[apple, apricot], b=[banana, blueberry]}
599
```
600
601
### Additional Collection Implementations
602
603
Specialized collection implementations for specific use cases.
604
605
```java { .api }
606
import com.google.common.collect.ArrayTable;
607
import com.google.common.collect.Collections2;
608
import com.google.common.collect.Ordering;
609
610
// Array-based table for dense data with known dimensions
611
List<String> rowKeys = Arrays.asList("Q1", "Q2", "Q3", "Q4");
612
List<String> columnKeys = Arrays.asList("Sales", "Marketing", "Engineering");
613
614
ArrayTable<String, String, Integer> quarterlyBudget = ArrayTable.create(rowKeys, columnKeys);
615
quarterlyBudget.put("Q1", "Sales", 100000);
616
quarterlyBudget.put("Q1", "Marketing", 50000);
617
quarterlyBudget.put("Q1", "Engineering", 200000);
618
619
// Efficient access by index
620
Integer q1Sales = quarterlyBudget.at(0, 0); // Q1 Sales budget
621
Map<String, Integer> q1Budget = quarterlyBudget.row("Q1");
622
623
// Collections2 utilities for collection transformation
624
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
625
626
// Transform collection (creates a view, not a copy)
627
Collection<String> upperCase = Collections2.transform(names,
628
new Function<String, String>() {
629
public String apply(String name) {
630
return name.toUpperCase();
631
}
632
});
633
634
// Filter collection (creates a view, not a copy)
635
Collection<String> longNames = Collections2.filter(names,
636
new Predicate<String>() {
637
public boolean apply(String name) {
638
return name.length() > 4;
639
}
640
});
641
642
// Generate permutations
643
Collection<List<String>> permutations = Collections2.permutations(
644
Arrays.asList("A", "B", "C"));
645
// Results in all 6 permutations: [A,B,C], [A,C,B], [B,A,C], etc.
646
647
// Ordering utilities (enhanced comparator)
648
Ordering<String> byLength = Ordering.natural().onResultOf(
649
new Function<String, Integer>() {
650
public Integer apply(String s) {
651
return s.length();
652
}
653
});
654
655
// Use ordering for various operations
656
List<String> words = Arrays.asList("elephant", "cat", "hippopotamus", "dog");
657
List<String> sortedByLength = byLength.sortedCopy(words); // [cat, dog, elephant, hippopotamus]
658
String shortest = byLength.min(words); // "cat"
659
String longest = byLength.max(words); // "hippopotamus"
660
661
// Get top/bottom N elements
662
List<String> shortest3 = byLength.leastOf(words, 3); // [cat, dog, elephant]
663
List<String> longest2 = byLength.greatestOf(words, 2); // [hippopotamus, elephant]
664
665
// Null-safe ordering
666
Ordering<String> nullsFirst = Ordering.natural().nullsFirst();
667
Ordering<String> nullsLast = Ordering.natural().nullsLast();
668
669
// Compound ordering (multiple criteria)
670
Ordering<Person> byAgeThemName = Ordering.natural()
671
.onResultOf(new Function<Person, Integer>() {
672
public Integer apply(Person p) { return p.getAge(); }
673
})
674
.compound(Ordering.natural().onResultOf(new Function<Person, String>() {
675
public String apply(Person p) { return p.getName(); }
676
}));
677
```
678
679
**Additional Collection Classes:**
680
681
- `ArrayTable<R,C,V>` - Table implementation backed by a 2D array, optimized for dense data
682
- `Collections2` - Static utility methods for creating transformed views of collections
683
- `Ordering<T>` - Enhanced comparator with fluent API for sorting and selection operations
684
685
This collections framework provides powerful abstractions that extend Java's standard collections with specialized data structures optimized for common use cases, comprehensive utility methods for transformation and manipulation, and convenient APIs that reduce boilerplate code while maintaining type safety and performance.