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 * <p>See the Guava User Guide article on <a href= 057 * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained"> 058 * immutable collections</a>. 059 * 060 * @author Jared Levy 061 * @since 2.0 (imported from Google Collections Library) 062 */ 063 @GwtCompatible(emulated = true) 064 // TODO(user): If BiMultimap graduates from labs, this class should implement it. 065 public abstract class ImmutableMultimap<K, V> 066 implements Multimap<K, V>, 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 AbstractMultimap<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 * Multimap for {@link ImmutableMultimap.Builder} that sorts key and allows 138 * duplicate values, 139 */ 140 private static class SortedKeyBuilderMultimap<K, V> 141 extends AbstractMultimap<K, V> { 142 SortedKeyBuilderMultimap( 143 Comparator<? super K> keyComparator, Multimap<K, V> multimap) { 144 super(new TreeMap<K, Collection<V>>(keyComparator)); 145 putAll(multimap); 146 } 147 @Override Collection<V> createCollection() { 148 return Lists.newArrayList(); 149 } 150 private static final long serialVersionUID = 0; 151 } 152 153 /** 154 * A builder for creating immutable multimap instances, especially 155 * {@code public static final} multimaps ("constant multimaps"). Example: 156 * <pre> {@code 157 * 158 * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP = 159 * new ImmutableMultimap.Builder<String, Integer>() 160 * .put("one", 1) 161 * .putAll("several", 1, 2, 3) 162 * .putAll("many", 1, 2, 3, 4, 5) 163 * .build();}</pre> 164 * 165 * Builder instances can be reused; it is safe to call {@link #build} multiple 166 * times to build multiple multimaps in series. Each multimap contains the 167 * key-value mappings in the previously created multimaps. 168 * 169 * @since 2.0 (imported from Google Collections Library) 170 */ 171 public static class Builder<K, V> { 172 Multimap<K, V> builderMultimap = new BuilderMultimap<K, V>(); 173 Comparator<? super V> valueComparator; 174 175 /** 176 * Creates a new builder. The returned builder is equivalent to the builder 177 * generated by {@link ImmutableMultimap#builder}. 178 */ 179 public Builder() {} 180 181 /** 182 * Adds a key-value mapping to the built multimap. 183 */ 184 public Builder<K, V> put(K key, V value) { 185 builderMultimap.put(checkNotNull(key), checkNotNull(value)); 186 return this; 187 } 188 189 /** 190 * Adds an entry to the built multimap. 191 * 192 * @since 11.0 193 */ 194 public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 195 builderMultimap.put( 196 checkNotNull(entry.getKey()), checkNotNull(entry.getValue())); 197 return this; 198 } 199 200 /** 201 * Stores a collection of values with the same key in the built multimap. 202 * 203 * @throws NullPointerException if {@code key}, {@code values}, or any 204 * element in {@code values} is null. The builder is left in an invalid 205 * state. 206 */ 207 public Builder<K, V> putAll(K key, Iterable<? extends V> values) { 208 Collection<V> valueList = builderMultimap.get(checkNotNull(key)); 209 for (V value : values) { 210 valueList.add(checkNotNull(value)); 211 } 212 return this; 213 } 214 215 /** 216 * Stores an array of values with the same key in the built multimap. 217 * 218 * @throws NullPointerException if the key or any value is null. The builder 219 * is left in an invalid state. 220 */ 221 public Builder<K, V> putAll(K key, V... values) { 222 return putAll(key, Arrays.asList(values)); 223 } 224 225 /** 226 * Stores another multimap's entries in the built multimap. The generated 227 * multimap's key and value orderings correspond to the iteration ordering 228 * of the {@code multimap.asMap()} view, with new keys and values following 229 * any existing keys and values. 230 * 231 * @throws NullPointerException if any key or value in {@code multimap} is 232 * null. The builder is left in an invalid state. 233 */ 234 public Builder<K, V> putAll(Multimap<? extends K, ? extends V> multimap) { 235 for (Entry<? extends K, ? extends Collection<? extends V>> entry 236 : multimap.asMap().entrySet()) { 237 putAll(entry.getKey(), entry.getValue()); 238 } 239 return this; 240 } 241 242 /** 243 * Specifies the ordering of the generated multimap's keys. 244 * 245 * @since 8.0 246 */ 247 @Beta 248 public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) { 249 builderMultimap = new SortedKeyBuilderMultimap<K, V>( 250 checkNotNull(keyComparator), builderMultimap); 251 return this; 252 } 253 254 /** 255 * Specifies the ordering of the generated multimap's values for each key. 256 * 257 * @since 8.0 258 */ 259 @Beta 260 public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) { 261 this.valueComparator = checkNotNull(valueComparator); 262 return this; 263 } 264 265 /** 266 * Returns a newly-created immutable multimap. 267 */ 268 public ImmutableMultimap<K, V> build() { 269 if (valueComparator != null) { 270 for (Collection<V> values : builderMultimap.asMap().values()) { 271 List<V> list = (List <V>) values; 272 Collections.sort(list, valueComparator); 273 } 274 } 275 return copyOf(builderMultimap); 276 } 277 } 278 279 /** 280 * Returns an immutable multimap containing the same mappings as {@code 281 * multimap}. The generated multimap's key and value orderings correspond to 282 * the iteration ordering of the {@code multimap.asMap()} view. 283 * 284 * <p>Despite the method name, this method attempts to avoid actually copying 285 * the data when it is safe to do so. The exact circumstances under which a 286 * copy will or will not be performed are undocumented and subject to change. 287 * 288 * @throws NullPointerException if any key or value in {@code multimap} is 289 * null 290 */ 291 public static <K, V> ImmutableMultimap<K, V> copyOf( 292 Multimap<? extends K, ? extends V> multimap) { 293 if (multimap instanceof ImmutableMultimap) { 294 @SuppressWarnings("unchecked") // safe since multimap is not writable 295 ImmutableMultimap<K, V> kvMultimap 296 = (ImmutableMultimap<K, V>) multimap; 297 if (!kvMultimap.isPartialView()) { 298 return kvMultimap; 299 } 300 } 301 return ImmutableListMultimap.copyOf(multimap); 302 } 303 304 final transient ImmutableMap<K, ? extends ImmutableCollection<V>> map; 305 final transient int size; 306 307 // These constants allow the deserialization code to set final fields. This 308 // holder class makes sure they are not initialized unless an instance is 309 // deserialized. 310 @GwtIncompatible("java serialization is not supported") 311 static class FieldSettersHolder { 312 static final Serialization.FieldSetter<ImmutableMultimap> 313 MAP_FIELD_SETTER = Serialization.getFieldSetter( 314 ImmutableMultimap.class, "map"); 315 static final Serialization.FieldSetter<ImmutableMultimap> 316 SIZE_FIELD_SETTER = Serialization.getFieldSetter( 317 ImmutableMultimap.class, "size"); 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 */ 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 */ 343 @Override 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 @Override 355 public void clear() { 356 throw new UnsupportedOperationException(); 357 } 358 359 /** 360 * Returns an immutable collection of the values for the given key. If no 361 * mappings in the multimap have the provided key, an empty immutable 362 * collection is returned. The values are in the same order as the parameters 363 * used to build this multimap. 364 */ 365 @Override 366 public abstract ImmutableCollection<V> get(K key); 367 368 /** 369 * Returns an immutable multimap which is the inverse of this one. For every 370 * key-value mapping in the original, the result will have a mapping with 371 * key and value reversed. 372 * 373 * @since 11 374 */ 375 @Beta 376 public abstract ImmutableMultimap<V, K> inverse(); 377 378 /** 379 * Guaranteed to throw an exception and leave the multimap unmodified. 380 * 381 * @throws UnsupportedOperationException always 382 */ 383 @Override 384 public boolean put(K key, V value) { 385 throw new UnsupportedOperationException(); 386 } 387 388 /** 389 * Guaranteed to throw an exception and leave the multimap unmodified. 390 * 391 * @throws UnsupportedOperationException always 392 */ 393 @Override 394 public boolean putAll(K key, Iterable<? extends V> values) { 395 throw new UnsupportedOperationException(); 396 } 397 398 /** 399 * Guaranteed to throw an exception and leave the multimap unmodified. 400 * 401 * @throws UnsupportedOperationException always 402 */ 403 @Override 404 public boolean putAll(Multimap<? extends K, ? extends V> multimap) { 405 throw new UnsupportedOperationException(); 406 } 407 408 /** 409 * Guaranteed to throw an exception and leave the multimap unmodified. 410 * 411 * @throws UnsupportedOperationException always 412 */ 413 @Override 414 public boolean remove(Object key, Object value) { 415 throw new UnsupportedOperationException(); 416 } 417 418 boolean isPartialView(){ 419 return map.isPartialView(); 420 } 421 422 // accessors 423 424 @Override 425 public boolean containsEntry(@Nullable Object key, @Nullable Object value) { 426 Collection<V> values = map.get(key); 427 return values != null && values.contains(value); 428 } 429 430 @Override 431 public boolean containsKey(@Nullable Object key) { 432 return map.containsKey(key); 433 } 434 435 @Override 436 public boolean containsValue(@Nullable Object value) { 437 for (Collection<V> valueCollection : map.values()) { 438 if (valueCollection.contains(value)) { 439 return true; 440 } 441 } 442 return false; 443 } 444 445 @Override 446 public boolean isEmpty() { 447 return size == 0; 448 } 449 450 @Override 451 public int size() { 452 return size; 453 } 454 455 @Override public boolean equals(@Nullable Object object) { 456 if (object instanceof Multimap) { 457 Multimap<?, ?> that = (Multimap<?, ?>) object; 458 return this.map.equals(that.asMap()); 459 } 460 return false; 461 } 462 463 @Override public int hashCode() { 464 return map.hashCode(); 465 } 466 467 @Override public String toString() { 468 return map.toString(); 469 } 470 471 // views 472 473 /** 474 * Returns an immutable set of the distinct keys in this multimap. These keys 475 * are ordered according to when they first appeared during the construction 476 * of this multimap. 477 */ 478 @Override 479 public ImmutableSet<K> keySet() { 480 return map.keySet(); 481 } 482 483 /** 484 * Returns an immutable map that associates each key with its corresponding 485 * values in the multimap. 486 */ 487 @Override 488 @SuppressWarnings("unchecked") // a widening cast 489 public ImmutableMap<K, Collection<V>> asMap() { 490 return (ImmutableMap) map; 491 } 492 493 private transient ImmutableCollection<Entry<K, V>> entries; 494 495 /** 496 * Returns an immutable collection of all key-value pairs in the multimap. Its 497 * iterator traverses the values for the first key, the values for the second 498 * key, and so on. 499 */ 500 @Override 501 public ImmutableCollection<Entry<K, V>> entries() { 502 ImmutableCollection<Entry<K, V>> result = entries; 503 return (result == null) 504 ? (entries = new EntryCollection<K, V>(this)) : result; 505 } 506 507 private static class EntryCollection<K, V> 508 extends ImmutableCollection<Entry<K, V>> { 509 final ImmutableMultimap<K, V> multimap; 510 511 EntryCollection(ImmutableMultimap<K, V> multimap) { 512 this.multimap = multimap; 513 } 514 515 @Override public UnmodifiableIterator<Entry<K, V>> iterator() { 516 final Iterator<? extends Entry<K, ? extends ImmutableCollection<V>>> 517 mapIterator = this.multimap.map.entrySet().iterator(); 518 519 return new UnmodifiableIterator<Entry<K, V>>() { 520 K key; 521 Iterator<V> valueIterator; 522 523 @Override 524 public boolean hasNext() { 525 return (key != null && valueIterator.hasNext()) 526 || mapIterator.hasNext(); 527 } 528 529 @Override 530 public Entry<K, V> next() { 531 if (key == null || !valueIterator.hasNext()) { 532 Entry<K, ? extends ImmutableCollection<V>> entry 533 = mapIterator.next(); 534 key = entry.getKey(); 535 valueIterator = entry.getValue().iterator(); 536 } 537 return Maps.immutableEntry(key, valueIterator.next()); 538 } 539 }; 540 } 541 542 @Override boolean isPartialView() { 543 return multimap.isPartialView(); 544 } 545 546 @Override 547 public int size() { 548 return multimap.size(); 549 } 550 551 @Override public boolean contains(Object object) { 552 if (object instanceof Entry) { 553 Entry<?, ?> entry = (Entry<?, ?>) object; 554 return multimap.containsEntry(entry.getKey(), entry.getValue()); 555 } 556 return false; 557 } 558 559 private static final long serialVersionUID = 0; 560 } 561 562 private transient ImmutableMultiset<K> keys; 563 564 /** 565 * Returns a collection, which may contain duplicates, of all keys. The number 566 * of times a key appears in the returned multiset equals the number of 567 * mappings the key has in the multimap. Duplicate keys appear consecutively 568 * in the multiset's iteration order. 569 */ 570 @Override 571 public ImmutableMultiset<K> keys() { 572 ImmutableMultiset<K> result = keys; 573 return (result == null) ? (keys = createKeys()) : result; 574 } 575 576 private ImmutableMultiset<K> createKeys() { 577 ImmutableMultiset.Builder<K> builder = ImmutableMultiset.builder(); 578 for (Entry<K, ? extends ImmutableCollection<V>> entry 579 : map.entrySet()) { 580 builder.addCopies(entry.getKey(), entry.getValue().size()); 581 } 582 return builder.build(); 583 } 584 585 private transient ImmutableCollection<V> values; 586 587 /** 588 * Returns an immutable collection of the values in this multimap. Its 589 * iterator traverses the values for the first key, the values for the second 590 * key, and so on. 591 */ 592 @Override 593 public ImmutableCollection<V> values() { 594 ImmutableCollection<V> result = values; 595 return (result == null) ? (values = new Values<V>(this)) : result; 596 } 597 598 private static class Values<V> extends ImmutableCollection<V> { 599 final ImmutableMultimap<?, V> multimap; 600 601 Values(ImmutableMultimap<?, V> multimap) { 602 this.multimap = multimap; 603 } 604 605 @Override public UnmodifiableIterator<V> iterator() { 606 return Maps.valueIterator(multimap.entries().iterator()); 607 } 608 609 @Override 610 public int size() { 611 return multimap.size(); 612 } 613 614 @Override boolean isPartialView() { 615 return true; 616 } 617 618 private static final long serialVersionUID = 0; 619 } 620 621 private static final long serialVersionUID = 0; 622 }