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