View Javadoc
1   /*
2    * Copyright (C) 2008 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.base.Preconditions.checkNotNull;
20  import static com.google.common.collect.CollectPreconditions.checkEntryNotNull;
21  
22  import com.google.common.annotations.GwtCompatible;
23  import com.google.common.annotations.GwtIncompatible;
24  
25  import java.io.Serializable;
26  import java.util.Arrays;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.Comparator;
30  import java.util.Iterator;
31  import java.util.LinkedHashMap;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.Map.Entry;
35  import java.util.Set;
36  
37  import javax.annotation.Nullable;
38  
39  /**
40   * An immutable {@link Multimap}. Does not permit null keys or values.
41   *
42   * <p>Unlike {@link Multimaps#unmodifiableMultimap(Multimap)}, which is
43   * a <i>view</i> of a separate multimap which can still change, an instance of
44   * {@code ImmutableMultimap} contains its own data and will <i>never</i>
45   * change. {@code ImmutableMultimap} is convenient for
46   * {@code public static final} multimaps ("constant multimaps") and also lets
47   * you easily make a "defensive copy" of a multimap provided to your class by
48   * a caller.
49   *
50   * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
51   * it has no public or protected constructors. Thus, instances of this class
52   * are guaranteed to be immutable.
53   *
54   * <p>In addition to methods defined by {@link Multimap}, an {@link #inverse}
55   * method is also supported.
56   *
57   * <p>See the Guava User Guide article on <a href=
58   * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
59   * immutable collections</a>.
60   *
61   * @author Jared Levy
62   * @since 2.0 (imported from Google Collections Library)
63   */
64  @GwtCompatible(emulated = true)
65  public abstract class ImmutableMultimap<K, V> extends AbstractMultimap<K, V>
66      implements Serializable {
67  
68    /** Returns an empty multimap. */
69    public static <K, V> ImmutableMultimap<K, V> of() {
70      return ImmutableListMultimap.of();
71    }
72  
73    /**
74     * Returns an immutable multimap containing a single entry.
75     */
76    public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1) {
77      return ImmutableListMultimap.of(k1, v1);
78    }
79  
80    /**
81     * Returns an immutable multimap containing the given entries, in order.
82     */
83    public static <K, V> ImmutableMultimap<K, V> of(K k1, V v1, K k2, V v2) {
84      return ImmutableListMultimap.of(k1, v1, k2, v2);
85    }
86  
87    /**
88     * Returns an immutable multimap containing the given entries, in order.
89     */
90    public static <K, V> ImmutableMultimap<K, V> of(
91        K k1, V v1, K k2, V v2, K k3, V v3) {
92      return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3);
93    }
94  
95    /**
96     * Returns an immutable multimap containing the given entries, in order.
97     */
98    public static <K, V> ImmutableMultimap<K, V> of(
99        K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
100     return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4);
101   }
102 
103   /**
104    * Returns an immutable multimap containing the given entries, in order.
105    */
106   public static <K, V> ImmutableMultimap<K, V> of(
107       K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
108     return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
109   }
110 
111   // looking for of() with > 5 entries? Use the builder instead.
112 
113   /**
114    * Returns a new builder. The generated builder is equivalent to the builder
115    * created by the {@link Builder} constructor.
116    */
117   public static <K, V> Builder<K, V> builder() {
118     return new Builder<K, V>();
119   }
120 
121   /**
122    * Multimap for {@link ImmutableMultimap.Builder} that maintains key and
123    * value orderings, allows duplicate values, and performs better than
124    * {@link LinkedListMultimap}.
125    */
126   private static class BuilderMultimap<K, V> extends AbstractMapBasedMultimap<K, V> {
127     BuilderMultimap() {
128       super(new LinkedHashMap<K, Collection<V>>());
129     }
130     @Override Collection<V> createCollection() {
131       return Lists.newArrayList();
132     }
133     private static final long serialVersionUID = 0;
134   }
135 
136   /**
137    * A builder for creating immutable multimap instances, especially
138    * {@code public static final} multimaps ("constant multimaps"). Example:
139    * <pre>   {@code
140    *
141    *   static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
142    *       new ImmutableMultimap.Builder<String, Integer>()
143    *           .put("one", 1)
144    *           .putAll("several", 1, 2, 3)
145    *           .putAll("many", 1, 2, 3, 4, 5)
146    *           .build();}</pre>
147    *
148    * <p>Builder instances can be reused; it is safe to call {@link #build} multiple
149    * times to build multiple multimaps in series. Each multimap contains the
150    * key-value mappings in the previously created multimaps.
151    *
152    * @since 2.0 (imported from Google Collections Library)
153    */
154   public static class Builder<K, V> {
155     Multimap<K, V> builderMultimap = new BuilderMultimap<K, V>();
156     Comparator<? super K> keyComparator;
157     Comparator<? super V> valueComparator;
158 
159     /**
160      * Creates a new builder. The returned builder is equivalent to the builder
161      * generated by {@link ImmutableMultimap#builder}.
162      */
163     public Builder() {}
164 
165     /**
166      * Adds a key-value mapping to the built multimap.
167      */
168     public Builder<K, V> put(K key, V value) {
169       checkEntryNotNull(key, value);
170       builderMultimap.put(key, value);
171       return this;
172     }
173 
174     /**
175      * Adds an entry to the built multimap.
176      *
177      * @since 11.0
178      */
179     public Builder<K, V> put(Entry<? extends K, ? extends V> entry) {
180       return put(entry.getKey(), entry.getValue());
181     }
182 
183     /**
184      * Stores a collection of values with the same key in the built multimap.
185      *
186      * @throws NullPointerException if {@code key}, {@code values}, or any
187      *     element in {@code values} is null. The builder is left in an invalid
188      *     state.
189      */
190     public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
191       if (key == null) {
192         throw new NullPointerException(
193             "null key in entry: null=" + Iterables.toString(values));
194       }
195       Collection<V> valueList = builderMultimap.get(key);
196       for (V value : values) {
197         checkEntryNotNull(key, value);
198         valueList.add(value);
199       }
200       return this;
201     }
202 
203     /**
204      * Stores an array of values with the same key in the built multimap.
205      *
206      * @throws NullPointerException if the key or any value is null. The builder
207      *     is left in an invalid state.
208      */
209     public Builder<K, V> putAll(K key, V... values) {
210       return putAll(key, Arrays.asList(values));
211     }
212 
213     /**
214      * Stores another multimap's entries in the built multimap. The generated
215      * multimap's key and value orderings correspond to the iteration ordering
216      * of the {@code multimap.asMap()} view, with new keys and values following
217      * any existing keys and values.
218      *
219      * @throws NullPointerException if any key or value in {@code multimap} is
220      *     null. The builder is left in an invalid state.
221      */
222     public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) {
223       for (Entry<? extends K, ? extends Collection<? extends V>> entry
224           : multimap.asMap().entrySet()) {
225         putAll(entry.getKey(), entry.getValue());
226       }
227       return this;
228     }
229 
230     /**
231      * Specifies the ordering of the generated multimap's keys.
232      *
233      * @since 8.0
234      */
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     public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
246       this.valueComparator = checkNotNull(valueComparator);
247       return this;
248     }
249 
250     /**
251      * Returns a newly-created immutable multimap.
252      */
253     public ImmutableMultimap<K, V> build() {
254       if (valueComparator != null) {
255         for (Collection<V> values : builderMultimap.asMap().values()) {
256           List<V> list = (List <V>) values;
257           Collections.sort(list, valueComparator);
258         }
259       }
260       if (keyComparator != null) {
261         Multimap<K, V> sortedCopy = new BuilderMultimap<K, V>();
262         List<Map.Entry<K, Collection<V>>> entries = Lists.newArrayList(
263             builderMultimap.asMap().entrySet());
264         Collections.sort(
265             entries,
266             Ordering.from(keyComparator).<K>onKeys());
267         for (Map.Entry<K, Collection<V>> entry : entries) {
268           sortedCopy.putAll(entry.getKey(), entry.getValue());
269         }
270         builderMultimap = sortedCopy;
271       }
272       return copyOf(builderMultimap);
273     }
274   }
275 
276   /**
277    * Returns an immutable multimap containing the same mappings as {@code
278    * multimap}. The generated multimap's key and value orderings correspond to
279    * the iteration ordering of the {@code multimap.asMap()} view.
280    *
281    * <p>Despite the method name, this method attempts to avoid actually copying
282    * the data when it is safe to do so. The exact circumstances under which a
283    * copy will or will not be performed are undocumented and subject to change.
284    *
285    * @throws NullPointerException if any key or value in {@code multimap} is
286    *         null
287    */
288   public static <K, V> ImmutableMultimap<K, V> copyOf(
289       Multimap<? extends K, ? extends V> multimap) {
290     if (multimap instanceof ImmutableMultimap) {
291       @SuppressWarnings("unchecked") // safe since multimap is not writable
292       ImmutableMultimap<K, V> kvMultimap
293           = (ImmutableMultimap<K, V>) multimap;
294       if (!kvMultimap.isPartialView()) {
295         return kvMultimap;
296       }
297     }
298     return ImmutableListMultimap.copyOf(multimap);
299   }
300 
301   final transient ImmutableMap<K, ? extends ImmutableCollection<V>> map;
302   final transient int size;
303 
304   // These constants allow the deserialization code to set final fields. This
305   // holder class makes sure they are not initialized unless an instance is
306   // deserialized.
307   @GwtIncompatible("java serialization is not supported")
308   static class FieldSettersHolder {
309     static final Serialization.FieldSetter<ImmutableMultimap>
310         MAP_FIELD_SETTER = Serialization.getFieldSetter(
311         ImmutableMultimap.class, "map");
312     static final Serialization.FieldSetter<ImmutableMultimap>
313         SIZE_FIELD_SETTER = Serialization.getFieldSetter(
314         ImmutableMultimap.class, "size");
315     static final Serialization.FieldSetter<ImmutableSetMultimap>
316         EMPTY_SET_FIELD_SETTER = Serialization.getFieldSetter(
317         ImmutableSetMultimap.class, "emptySet");
318   }
319 
320   ImmutableMultimap(ImmutableMap<K, ? extends ImmutableCollection<V>> map,
321       int size) {
322     this.map = map;
323     this.size = size;
324   }
325 
326   // mutators (not supported)
327 
328   /**
329    * Guaranteed to throw an exception and leave the multimap unmodified.
330    *
331    * @throws UnsupportedOperationException always
332    * @deprecated Unsupported operation.
333    */
334   @Deprecated
335   @Override
336   public ImmutableCollection<V> removeAll(Object key) {
337     throw new UnsupportedOperationException();
338   }
339 
340   /**
341    * Guaranteed to throw an exception and leave the multimap unmodified.
342    *
343    * @throws UnsupportedOperationException always
344    * @deprecated Unsupported operation.
345    */
346   @Deprecated
347   @Override
348   public ImmutableCollection<V> replaceValues(K key,
349       Iterable<? extends V> values) {
350     throw new UnsupportedOperationException();
351   }
352 
353   /**
354    * Guaranteed to throw an exception and leave the multimap unmodified.
355    *
356    * @throws UnsupportedOperationException always
357    * @deprecated Unsupported operation.
358    */
359   @Deprecated
360   @Override
361   public void clear() {
362     throw new UnsupportedOperationException();
363   }
364 
365   /**
366    * Returns an immutable collection of the values for the given key.  If no
367    * mappings in the multimap have the provided key, an empty immutable
368    * collection is returned. The values are in the same order as the parameters
369    * used to build this multimap.
370    */
371   @Override
372   public abstract ImmutableCollection<V> get(K key);
373 
374   /**
375    * Returns an immutable multimap which is the inverse of this one. For every
376    * key-value mapping in the original, the result will have a mapping with
377    * key and value reversed.
378    *
379    * @since 11.0
380    */
381   public abstract ImmutableMultimap<V, K> inverse();
382 
383   /**
384    * Guaranteed to throw an exception and leave the multimap unmodified.
385    *
386    * @throws UnsupportedOperationException always
387    * @deprecated Unsupported operation.
388    */
389   @Deprecated
390   @Override
391   public boolean put(K key, V value) {
392     throw new UnsupportedOperationException();
393   }
394 
395   /**
396    * Guaranteed to throw an exception and leave the multimap unmodified.
397    *
398    * @throws UnsupportedOperationException always
399    * @deprecated Unsupported operation.
400    */
401   @Deprecated
402   @Override
403   public boolean putAll(K key, Iterable<? extends V> values) {
404     throw new UnsupportedOperationException();
405   }
406 
407   /**
408    * Guaranteed to throw an exception and leave the multimap unmodified.
409    *
410    * @throws UnsupportedOperationException always
411    * @deprecated Unsupported operation.
412    */
413   @Deprecated
414   @Override
415   public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
416     throw new UnsupportedOperationException();
417   }
418 
419   /**
420    * Guaranteed to throw an exception and leave the multimap unmodified.
421    *
422    * @throws UnsupportedOperationException always
423    * @deprecated Unsupported operation.
424    */
425   @Deprecated
426   @Override
427   public boolean remove(Object key, Object value) {
428     throw new UnsupportedOperationException();
429   }
430   
431   /**
432    * Returns {@code true} if this immutable multimap's implementation contains references to
433    * user-created objects that aren't accessible via this multimap's methods. This is generally
434    * used to determine whether {@code copyOf} implementations should make an explicit copy to avoid
435    * memory leaks.
436    */
437   boolean isPartialView() {
438     return map.isPartialView();
439   }
440 
441   // accessors
442 
443   @Override
444   public boolean containsKey(@Nullable Object key) {
445     return map.containsKey(key);
446   }
447 
448   @Override
449   public boolean containsValue(@Nullable Object value) {
450     return value != null && super.containsValue(value);
451   }
452   
453   @Override
454   public int size() {
455     return size;
456   }
457 
458   // views
459 
460   /**
461    * Returns an immutable set of the distinct keys in this multimap. These keys
462    * are ordered according to when they first appeared during the construction
463    * of this multimap.
464    */
465   @Override
466   public ImmutableSet<K> keySet() {
467     return map.keySet();
468   }
469 
470   /**
471    * Returns an immutable map that associates each key with its corresponding
472    * values in the multimap.
473    */
474   @Override
475   @SuppressWarnings("unchecked") // a widening cast
476   public ImmutableMap<K, Collection<V>> asMap() {
477     return (ImmutableMap) map;
478   }
479   
480   @Override
481   Map<K, Collection<V>> createAsMap() {
482     throw new AssertionError("should never be called");
483   }
484 
485   /**
486    * Returns an immutable collection of all key-value pairs in the multimap. Its
487    * iterator traverses the values for the first key, the values for the second
488    * key, and so on.
489    */
490   @Override
491   public ImmutableCollection<Entry<K, V>> entries() {
492     return (ImmutableCollection<Entry<K, V>>) super.entries();
493   }
494   
495   @Override
496   ImmutableCollection<Entry<K, V>> createEntries() {
497     return new EntryCollection<K, V>(this);
498   }
499 
500   private static class EntryCollection<K, V>
501       extends ImmutableCollection<Entry<K, V>> {
502     final ImmutableMultimap<K, V> multimap;
503 
504     EntryCollection(ImmutableMultimap<K, V> multimap) {
505       this.multimap = multimap;
506     }
507 
508     @Override public UnmodifiableIterator<Entry<K, V>> iterator() {
509       return multimap.entryIterator();
510     }
511 
512     @Override boolean isPartialView() {
513       return multimap.isPartialView();
514     }
515 
516     @Override
517     public int size() {
518       return multimap.size();
519     }
520 
521     @Override public boolean contains(Object object) {
522       if (object instanceof Entry) {
523         Entry<?, ?> entry = (Entry<?, ?>) object;
524         return multimap.containsEntry(entry.getKey(), entry.getValue());
525       }
526       return false;
527     }
528 
529     private static final long serialVersionUID = 0;
530   }
531   
532   private abstract class Itr<T> extends UnmodifiableIterator<T> {
533     final Iterator<Entry<K, Collection<V>>> mapIterator = asMap().entrySet().iterator();
534     K key = null;
535     Iterator<V> valueIterator = Iterators.emptyIterator();
536     
537     abstract T output(K key, V value);
538 
539     @Override
540     public boolean hasNext() {
541       return mapIterator.hasNext() || valueIterator.hasNext();
542     }
543 
544     @Override
545     public T next() {
546       if (!valueIterator.hasNext()) {
547         Entry<K, Collection<V>> mapEntry = mapIterator.next();
548         key = mapEntry.getKey();
549         valueIterator = mapEntry.getValue().iterator();
550       }
551       return output(key, valueIterator.next());
552     }
553   }
554   
555   @Override
556   UnmodifiableIterator<Entry<K, V>> entryIterator() {
557     return new Itr<Entry<K, V>>() {
558       @Override
559       Entry<K, V> output(K key, V value) {
560         return Maps.immutableEntry(key, value);
561       }
562     };
563   }
564 
565   /**
566    * Returns a collection, which may contain duplicates, of all keys. The number
567    * of times a key appears in the returned multiset equals the number of
568    * mappings the key has in the multimap. Duplicate keys appear consecutively
569    * in the multiset's iteration order.
570    */
571   @Override
572   public ImmutableMultiset<K> keys() {
573     return (ImmutableMultiset<K>) super.keys();
574   }
575 
576   @Override
577   ImmutableMultiset<K> createKeys() {
578     return new Keys();
579   }
580 
581   @SuppressWarnings("serial") // Uses writeReplace, not default serialization
582   class Keys extends ImmutableMultiset<K> {
583     @Override
584     public boolean contains(@Nullable Object object) {
585       return containsKey(object);
586     }
587 
588     @Override
589     public int count(@Nullable Object element) {
590       Collection<V> values = map.get(element);
591       return (values == null) ? 0 : values.size();
592     }
593 
594     @Override
595     public Set<K> elementSet() {
596       return keySet();
597     }
598 
599     @Override
600     public int size() {
601       return ImmutableMultimap.this.size();
602     }
603     
604     @Override
605     Multiset.Entry<K> getEntry(int index) {
606       Map.Entry<K, ? extends Collection<V>> entry = map.entrySet().asList().get(index);
607       return Multisets.immutableEntry(entry.getKey(), entry.getValue().size());
608     }
609 
610     @Override
611     boolean isPartialView() {
612       return true;
613     }
614   }
615 
616   /**
617    * Returns an immutable collection of the values in this multimap. Its
618    * iterator traverses the values for the first key, the values for the second
619    * key, and so on.
620    */
621   @Override
622   public ImmutableCollection<V> values() {
623     return (ImmutableCollection<V>) super.values();
624   }
625   
626   @Override
627   ImmutableCollection<V> createValues() {
628     return new Values<K, V>(this);
629   }
630 
631   @Override
632   UnmodifiableIterator<V> valueIterator() {
633     return new Itr<V>() {
634       @Override
635       V output(K key, V value) {
636         return value;
637       }
638     };
639   }
640 
641   private static final class Values<K, V> extends ImmutableCollection<V> {
642     private transient final ImmutableMultimap<K, V> multimap;
643     
644     Values(ImmutableMultimap<K, V> multimap) {
645       this.multimap = multimap;
646     }
647 
648     @Override
649     public boolean contains(@Nullable Object object) {
650       return multimap.containsValue(object);
651     }
652     
653     @Override public UnmodifiableIterator<V> iterator() {
654       return multimap.valueIterator();
655     }
656 
657     @GwtIncompatible("not present in emulated superclass")
658     @Override
659     int copyIntoArray(Object[] dst, int offset) {
660       for (ImmutableCollection<V> valueCollection : multimap.map.values()) {
661         offset = valueCollection.copyIntoArray(dst, offset);
662       }
663       return offset;
664     }
665 
666     @Override
667     public int size() {
668       return multimap.size();
669     }
670 
671     @Override boolean isPartialView() {
672       return true;
673     }
674 
675     private static final long serialVersionUID = 0;
676   }
677 
678   private static final long serialVersionUID = 0;
679 }