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