001 /*
002 * Copyright (C) 2008 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package com.google.common.collect;
018
019 import static com.google.common.base.Preconditions.checkNotNull;
020
021 import com.google.common.annotations.Beta;
022 import com.google.common.annotations.GwtCompatible;
023 import com.google.common.annotations.GwtIncompatible;
024 import com.google.common.base.Function;
025
026 import java.io.Serializable;
027 import java.util.Arrays;
028 import java.util.Collection;
029 import java.util.Collections;
030 import java.util.Comparator;
031 import java.util.Iterator;
032 import java.util.LinkedHashMap;
033 import java.util.List;
034 import java.util.Map;
035 import java.util.Map.Entry;
036 import java.util.Set;
037
038 import javax.annotation.Nullable;
039
040 /**
041 * An immutable {@link Multimap}. Does not permit null keys or values.
042 *
043 * <p>Unlike {@link Multimaps#unmodifiableMultimap(Multimap)}, which is
044 * a <i>view</i> of a separate multimap which can still change, an instance of
045 * {@code ImmutableMultimap} contains its own data and will <i>never</i>
046 * change. {@code ImmutableMultimap} is convenient for
047 * {@code public static final} multimaps ("constant multimaps") and also lets
048 * you easily make a "defensive copy" of a multimap provided to your class by
049 * a caller.
050 *
051 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
052 * it has no public or protected constructors. Thus, instances of this class
053 * are guaranteed to be immutable.
054 *
055 * <p>In addition to methods defined by {@link Multimap}, an {@link #inverse}
056 * method is also supported.
057 *
058 * <p>See the Guava User Guide article on <a href=
059 * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
060 * immutable collections</a>.
061 *
062 * @author Jared Levy
063 * @since 2.0 (imported from Google Collections Library)
064 */
065 @GwtCompatible(emulated = true)
066 public abstract class ImmutableMultimap<K, V>
067 implements Multimap<K, V>, Serializable {
068
069 /** Returns an empty multimap. */
070 public static <K, V> ImmutableMultimap<K, V> of() {
071 return ImmutableListMultimap.of();
072 }
073
074 /**
075 * Returns an immutable multimap containing a single entry.
076 */
077 public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1) {
078 return ImmutableListMultimap.of(k1, v1);
079 }
080
081 /**
082 * Returns an immutable multimap containing the given entries, in order.
083 */
084 public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1, K k2, V v2) {
085 return ImmutableListMultimap.of(k1, v1, k2, v2);
086 }
087
088 /**
089 * Returns an immutable multimap containing the given entries, in order.
090 */
091 public static <K, V> ImmutableMultimap<K, V> of(
092 K k1, V v1, K k2, V v2, K k3, V v3) {
093 return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3);
094 }
095
096 /**
097 * Returns an immutable multimap containing the given entries, in order.
098 */
099 public static <K, V> ImmutableMultimap<K, V> of(
100 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
101 return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4);
102 }
103
104 /**
105 * Returns an immutable multimap containing the given entries, in order.
106 */
107 public static <K, V> ImmutableMultimap<K, V> of(
108 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
109 return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
110 }
111
112 // looking for of() with > 5 entries? Use the builder instead.
113
114 /**
115 * Returns a new builder. The generated builder is equivalent to the builder
116 * created by the {@link Builder} constructor.
117 */
118 public static <K, V> Builder<K, V> builder() {
119 return new Builder<K, V>();
120 }
121
122 /**
123 * Multimap for {@link ImmutableMultimap.Builder} that maintains key and
124 * value orderings, allows duplicate values, and performs better than
125 * {@link LinkedListMultimap}.
126 */
127 private static class BuilderMultimap<K, V> extends AbstractMultimap<K, V> {
128 BuilderMultimap() {
129 super(new LinkedHashMap<K, Collection<V>>());
130 }
131
132 @Override
133 Collection<V> createCollection() {
134 return Lists.newArrayList();
135 }
136 private static final long serialVersionUID = 0;
137 }
138
139 /**
140 * A builder for creating immutable multimap instances, especially
141 * {@code public static final} multimaps ("constant multimaps"). Example:
142 * <pre> {@code
143 *
144 * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
145 * new ImmutableMultimap.Builder<String, Integer>()
146 * .put("one", 1)
147 * .putAll("several", 1, 2, 3)
148 * .putAll("many", 1, 2, 3, 4, 5)
149 * .build();}</pre>
150 *
151 * Builder instances can be reused; it is safe to call {@link #build} multiple
152 * times to build multiple multimaps in series. Each multimap contains the
153 * key-value mappings in the previously created multimaps.
154 *
155 * @since 2.0 (imported from Google Collections Library)
156 */
157 public static class Builder<K, V> {
158 Multimap<K, V> builderMultimap = new BuilderMultimap<K, V>();
159 Comparator<? super K> keyComparator;
160 Comparator<? super V> valueComparator;
161
162 /**
163 * Creates a new builder. The returned builder is equivalent to the builder
164 * generated by {@link ImmutableMultimap#builder}.
165 */
166 public Builder() {}
167
168 /**
169 * Adds a key-value mapping to the built multimap.
170 */
171 public Builder<K, V> put(K key, V value) {
172 builderMultimap.put(checkNotNull(key), checkNotNull(value));
173 return this;
174 }
175
176 /**
177 * Adds an entry to the built multimap.
178 *
179 * @since 11.0
180 */
181 public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
182 builderMultimap.put(
183 checkNotNull(entry.getKey()), checkNotNull(entry.getValue()));
184 return this;
185 }
186
187 /**
188 * Stores a collection of values with the same key in the built multimap.
189 *
190 * @throws NullPointerException if {@code key}, {@code values}, or any
191 * element in {@code values} is null. The builder is left in an invalid
192 * state.
193 */
194 public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
195 Collection<V> valueList = builderMultimap.get(checkNotNull(key));
196 for (V value : values) {
197 valueList.add(checkNotNull(value));
198 }
199 return this;
200 }
201
202 /**
203 * Stores an array of values with the same key in the built multimap.
204 *
205 * @throws NullPointerException if the key or any value is null. The builder
206 * is left in an invalid state.
207 */
208 public Builder<K, V> putAll(K key, V... values) {
209 return putAll(key, Arrays.asList(values));
210 }
211
212 /**
213 * Stores another multimap's entries in the built multimap. The generated
214 * multimap's key and value orderings correspond to the iteration ordering
215 * of the {@code multimap.asMap()} view, with new keys and values following
216 * any existing keys and values.
217 *
218 * @throws NullPointerException if any key or value in {@code multimap} is
219 * null. The builder is left in an invalid state.
220 */
221 public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) {
222 for (Entry<? extends K, ? extends Collection<? extends V>> entry
223 : multimap.asMap().entrySet()) {
224 putAll(entry.getKey(), entry.getValue());
225 }
226 return this;
227 }
228
229 /**
230 * Specifies the ordering of the generated multimap's keys.
231 *
232 * @since 8.0
233 */
234 @Beta
235 public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
236 this.keyComparator = checkNotNull(keyComparator);
237 return this;
238 }
239
240 /**
241 * Specifies the ordering of the generated multimap's values for each key.
242 *
243 * @since 8.0
244 */
245 @Beta
246 public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
247 this.valueComparator = checkNotNull(valueComparator);
248 return this;
249 }
250
251 /**
252 * Returns a newly-created immutable multimap.
253 */
254 public ImmutableMultimap<K, V> build() {
255 if (valueComparator != null) {
256 for (Collection<V> values : builderMultimap.asMap().values()) {
257 List<V> list = (List <V>) values;
258 Collections.sort(list, valueComparator);
259 }
260 }
261 if (keyComparator != null) {
262 Multimap<K, V> sortedCopy = new BuilderMultimap<K, V>();
263 List<Map.Entry<K, Collection<V>>> entries = Lists.newArrayList(
264 builderMultimap.asMap().entrySet());
265 Collections.sort(
266 entries,
267 Ordering.from(keyComparator).onResultOf(new Function<Entry<K, Collection<V>>, K>() {
268 public K apply(Entry<K, Collection<V>> entry) {
269 return entry.getKey();
270 }
271 }));
272 for (Map.Entry<K, Collection<V>> entry : entries) {
273 sortedCopy.putAll(entry.getKey(), entry.getValue());
274 }
275 builderMultimap = sortedCopy;
276 }
277 return copyOf(builderMultimap);
278 }
279 }
280
281 /**
282 * Returns an immutable multimap containing the same mappings as {@code
283 * multimap}. The generated multimap's key and value orderings correspond to
284 * the iteration ordering of the {@code multimap.asMap()} view.
285 *
286 * <p>Despite the method name, this method attempts to avoid actually copying
287 * the data when it is safe to do so. The exact circumstances under which a
288 * copy will or will not be performed are undocumented and subject to change.
289 *
290 * @throws NullPointerException if any key or value in {@code multimap} is
291 * null
292 */
293 public static <K, V> ImmutableMultimap<K, V> copyOf(
294 Multimap<? extends K, ? extends V> multimap) {
295 if (multimap instanceof ImmutableMultimap) {
296 @SuppressWarnings("unchecked") // safe since multimap is not writable
297 ImmutableMultimap<K, V> kvMultimap
298 = (ImmutableMultimap<K, V>) multimap;
299 if (!kvMultimap.isPartialView()) {
300 return kvMultimap;
301 }
302 }
303 return ImmutableListMultimap.copyOf(multimap);
304 }
305
306 final transient ImmutableMap<K, ? extends ImmutableCollection<V>> map;
307 final transient int size;
308
309 // These constants allow the deserialization code to set final fields. This
310 // holder class makes sure they are not initialized unless an instance is
311 // deserialized.
312 @GwtIncompatible("java serialization is not supported")
313 static class FieldSettersHolder {
314 static final Serialization.FieldSetter<ImmutableMultimap>
315 MAP_FIELD_SETTER = Serialization.getFieldSetter(
316 ImmutableMultimap.class, "map");
317 static final Serialization.FieldSetter<ImmutableMultimap>
318 SIZE_FIELD_SETTER = Serialization.getFieldSetter(
319 ImmutableMultimap.class, "size");
320 }
321
322 ImmutableMultimap(ImmutableMap<K, ? extends ImmutableCollection<V>> map,
323 int size) {
324 this.map = map;
325 this.size = size;
326 }
327
328 // mutators (not supported)
329
330 /**
331 * Guaranteed to throw an exception and leave the multimap unmodified.
332 *
333 * @throws UnsupportedOperationException always
334 */
335 public ImmutableCollection<V> removeAll(Object key) {
336 throw new UnsupportedOperationException();
337 }
338
339 /**
340 * Guaranteed to throw an exception and leave the multimap unmodified.
341 *
342 * @throws UnsupportedOperationException always
343 */
344 public ImmutableCollection<V> replaceValues(K key,
345 Iterable<? extends V> values) {
346 throw new UnsupportedOperationException();
347 }
348
349 /**
350 * Guaranteed to throw an exception and leave the multimap unmodified.
351 *
352 * @throws UnsupportedOperationException always
353 */
354 public void clear() {
355 throw new UnsupportedOperationException();
356 }
357
358 /**
359 * Returns an immutable collection of the values for the given key. If no
360 * mappings in the multimap have the provided key, an empty immutable
361 * collection is returned. The values are in the same order as the parameters
362 * used to build this multimap.
363 */
364 public abstract ImmutableCollection<V> get(K key);
365
366 /**
367 * Returns an immutable multimap which is the inverse of this one. For every
368 * key-value mapping in the original, the result will have a mapping with
369 * key and value reversed.
370 *
371 * @since 11.0
372 */
373 @Beta
374 public abstract ImmutableMultimap<V, K> inverse();
375
376 /**
377 * Guaranteed to throw an exception and leave the multimap unmodified.
378 *
379 * @throws UnsupportedOperationException always
380 */
381 public boolean put(K key, V value) {
382 throw new UnsupportedOperationException();
383 }
384
385 /**
386 * Guaranteed to throw an exception and leave the multimap unmodified.
387 *
388 * @throws UnsupportedOperationException always
389 */
390 public boolean putAll(K key, Iterable<? extends V> values) {
391 throw new UnsupportedOperationException();
392 }
393
394 /**
395 * Guaranteed to throw an exception and leave the multimap unmodified.
396 *
397 * @throws UnsupportedOperationException always
398 */
399 public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
400 throw new UnsupportedOperationException();
401 }
402
403 /**
404 * Guaranteed to throw an exception and leave the multimap unmodified.
405 *
406 * @throws UnsupportedOperationException always
407 */
408 public boolean remove(Object key, Object value) {
409 throw new UnsupportedOperationException();
410 }
411
412 boolean isPartialView() {
413 return map.isPartialView();
414 }
415
416 // accessors
417
418 public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
419 Collection<V> values = map.get(key);
420 return values != null && values.contains(value);
421 }
422
423 public boolean containsKey(@Nullable Object key) {
424 return map.containsKey(key);
425 }
426
427 public boolean containsValue(@Nullable Object value) {
428 for (Collection<V> valueCollection : map.values()) {
429 if (valueCollection.contains(value)) {
430 return true;
431 }
432 }
433 return false;
434 }
435
436 public boolean isEmpty() {
437 return size == 0;
438 }
439
440 public int size() {
441 return size;
442 }
443
444
445 @Override
446 public boolean equals(@Nullable Object object) {
447 if (object instanceof Multimap) {
448 Multimap<?, ?> that = (Multimap<?, ?>) object;
449 return this.map.equals(that.asMap());
450 }
451 return false;
452 }
453
454
455 @Override
456 public int hashCode() {
457 return map.hashCode();
458 }
459
460
461 @Override
462 public String toString() {
463 return map.toString();
464 }
465
466 // views
467
468 /**
469 * Returns an immutable set of the distinct keys in this multimap. These keys
470 * are ordered according to when they first appeared during the construction
471 * of this multimap.
472 */
473 public ImmutableSet<K> keySet() {
474 return map.keySet();
475 }
476
477 /**
478 * Returns an immutable map that associates each key with its corresponding
479 * values in the multimap.
480 */
481 @SuppressWarnings("unchecked") // a widening cast
482 public ImmutableMap<K, Collection<V>> asMap() {
483 return (ImmutableMap) map;
484 }
485
486 private transient ImmutableCollection<Entry<K, V>> entries;
487
488 /**
489 * Returns an immutable collection of all key-value pairs in the multimap. Its
490 * iterator traverses the values for the first key, the values for the second
491 * key, and so on.
492 */
493 public ImmutableCollection<Entry<K, V>> entries() {
494 ImmutableCollection<Entry<K, V>> result = entries;
495 return (result == null)
496 ? (entries = new EntryCollection<K, V>(this)) : result;
497 }
498
499 private static class EntryCollection<K, V>
500 extends ImmutableCollection<Entry<K, V>> {
501 final ImmutableMultimap<K, V> multimap;
502
503 EntryCollection(ImmutableMultimap<K, V> multimap) {
504 this.multimap = multimap;
505 }
506
507
508 @Override
509 public UnmodifiableIterator<Entry<K, V>> iterator() {
510 final Iterator<? extends Entry<K, ? extends ImmutableCollection<V>>>
511 mapIterator = this.multimap.map.entrySet().iterator();
512
513 return new UnmodifiableIterator<Entry<K, V>>() {
514 K key;
515 Iterator<V> valueIterator;
516
517 public boolean hasNext() {
518 return (key != null && valueIterator.hasNext())
519 || mapIterator.hasNext();
520 }
521
522 public Entry<K, V> next() {
523 if (key == null || !valueIterator.hasNext()) {
524 Entry<K, ? extends ImmutableCollection<V>> entry
525 = mapIterator.next();
526 key = entry.getKey();
527 valueIterator = entry.getValue().iterator();
528 }
529 return Maps.immutableEntry(key, valueIterator.next());
530 }
531 };
532 }
533
534
535 @Override
536 boolean isPartialView() {
537 return multimap.isPartialView();
538 }
539
540 public int size() {
541 return multimap.size();
542 }
543
544
545 @Override
546 public boolean contains(Object object) {
547 if (object instanceof Entry) {
548 Entry<?, ?> entry = (Entry<?, ?>) object;
549 return multimap.containsEntry(entry.getKey(), entry.getValue());
550 }
551 return false;
552 }
553
554 private static final long serialVersionUID = 0;
555 }
556
557 private transient ImmutableMultiset<K> keys;
558
559 /**
560 * Returns a collection, which may contain duplicates, of all keys. The number
561 * of times a key appears in the returned multiset equals the number of
562 * mappings the key has in the multimap. Duplicate keys appear consecutively
563 * in the multiset's iteration order.
564 */
565 public ImmutableMultiset<K> keys() {
566 ImmutableMultiset<K> result = keys;
567 return (result == null) ? (keys = createKeys()) : result;
568 }
569
570 private ImmutableMultiset<K> createKeys() {
571 return new Keys();
572 }
573
574 @SuppressWarnings("serial") // Uses writeReplace, not default serialization
575 class Keys extends ImmutableMultiset<K> {
576
577 @Override
578 public boolean contains(@Nullable Object object) {
579 return containsKey(object);
580 }
581
582
583 public int count(@Nullable Object element) {
584 Collection<V> values = map.get(element);
585 return (values == null) ? 0 : values.size();
586 }
587
588
589 public Set<K> elementSet() {
590 return keySet();
591 }
592
593
594 public int size() {
595 return ImmutableMultimap.this.size();
596 }
597
598
599 @Override
600 ImmutableSet<Entry<K>> createEntrySet() {
601 return new KeysEntrySet();
602 }
603
604 private class KeysEntrySet extends ImmutableMultiset<K>.EntrySet {
605
606 public int size() {
607 return keySet().size();
608 }
609
610
611 @Override
612 public UnmodifiableIterator<Entry<K>> iterator() {
613 return asList().iterator();
614 }
615
616
617 @Override
618 ImmutableList<Entry<K>> createAsList() {
619 final ImmutableList<? extends Map.Entry<K, ? extends Collection<V>>> mapEntries =
620 map.entrySet().asList();
621 return new ImmutableAsList<Entry<K>>() {
622
623 public Entry<K> get(int index) {
624 Map.Entry<K, ? extends Collection<V>> entry = mapEntries.get(index);
625 return Multisets.immutableEntry(entry.getKey(), entry.getValue().size());
626 }
627
628
629 @Override
630 ImmutableCollection<Entry<K>> delegateCollection() {
631 return KeysEntrySet.this;
632 }
633 };
634 }
635 }
636
637
638 @Override
639 boolean isPartialView() {
640 return true;
641 }
642 }
643
644 private transient ImmutableCollection<V> values;
645
646 /**
647 * Returns an immutable collection of the values in this multimap. Its
648 * iterator traverses the values for the first key, the values for the second
649 * key, and so on.
650 */
651 public ImmutableCollection<V> values() {
652 ImmutableCollection<V> result = values;
653 return (result == null) ? (values = new Values<V>(this)) : result;
654 }
655
656 private static class Values<V> extends ImmutableCollection<V> {
657 final ImmutableMultimap<?, V> multimap;
658
659 Values(ImmutableMultimap<?, V> multimap) {
660 this.multimap = multimap;
661 }
662
663
664 @Override
665 public UnmodifiableIterator<V> iterator() {
666 return Maps.valueIterator(multimap.entries().iterator());
667 }
668
669 public int size() {
670 return multimap.size();
671 }
672
673
674 @Override
675 boolean isPartialView() {
676 return true;
677 }
678
679 private static final long serialVersionUID = 0;
680 }
681
682 private static final long serialVersionUID = 0;
683 }