001/* 002 * Copyright (C) 2009 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.checkArgument; 020import static com.google.common.base.Preconditions.checkNotNull; 021import static com.google.common.collect.Maps.keyOrNull; 022 023import com.google.common.annotations.GwtCompatible; 024 025import java.util.Arrays; 026import java.util.Collection; 027import java.util.Collections; 028import java.util.Comparator; 029import java.util.List; 030import java.util.Map; 031import java.util.NavigableMap; 032import java.util.SortedMap; 033import java.util.TreeMap; 034 035import javax.annotation.Nullable; 036 037/** 038 * An immutable {@link SortedMap}. Does not permit null keys or values. 039 * 040 * <p>Unlike {@link Collections#unmodifiableSortedMap}, which is a <i>view</i> 041 * of a separate map which can still change, an instance of {@code 042 * ImmutableSortedMap} contains its own data and will <i>never</i> change. 043 * {@code ImmutableSortedMap} is convenient for {@code public static final} maps 044 * ("constant maps") and also lets you easily make a "defensive copy" of a map 045 * provided to your class by a caller. 046 * 047 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as 048 * it has no public or protected constructors. Thus, instances of this class are 049 * guaranteed to be immutable. 050 * 051 * <p>See the Guava User Guide article on <a href= 052 * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained"> 053 * immutable collections</a>. 054 * 055 * @author Jared Levy 056 * @author Louis Wasserman 057 * @since 2.0 (imported from Google Collections Library; implements {@code 058 * NavigableMap} since 12.0) 059 */ 060@GwtCompatible(serializable = true, emulated = true) 061public abstract class ImmutableSortedMap<K, V> 062 extends ImmutableSortedMapFauxverideShim<K, V> implements NavigableMap<K, V> { 063 /* 064 * TODO(kevinb): Confirm that ImmutableSortedMap is faster to construct and 065 * uses less memory than TreeMap; then say so in the class Javadoc. 066 */ 067 private static final Comparator<Comparable> NATURAL_ORDER = Ordering.natural(); 068 069 private static final ImmutableSortedMap<Comparable, Object> NATURAL_EMPTY_MAP = 070 new EmptyImmutableSortedMap<Comparable, Object>(NATURAL_ORDER); 071 072 static <K, V> ImmutableSortedMap<K, V> emptyMap(Comparator<? super K> comparator) { 073 if (Ordering.natural().equals(comparator)) { 074 return of(); 075 } else { 076 return new EmptyImmutableSortedMap<K, V>(comparator); 077 } 078 } 079 080 static <K, V> ImmutableSortedMap<K, V> fromSortedEntries( 081 Comparator<? super K> comparator, 082 Collection<? extends Entry<? extends K, ? extends V>> entries) { 083 if (entries.isEmpty()) { 084 return emptyMap(comparator); 085 } 086 087 ImmutableList.Builder<K> keyBuilder = ImmutableList.builder(); 088 ImmutableList.Builder<V> valueBuilder = ImmutableList.builder(); 089 for (Entry<? extends K, ? extends V> entry : entries) { 090 keyBuilder.add(entry.getKey()); 091 valueBuilder.add(entry.getValue()); 092 } 093 094 return new RegularImmutableSortedMap<K, V>( 095 new RegularImmutableSortedSet<K>(keyBuilder.build(), comparator), 096 valueBuilder.build()); 097 } 098 099 static <K, V> ImmutableSortedMap<K, V> from( 100 ImmutableSortedSet<K> keySet, ImmutableList<V> valueList) { 101 if (keySet.isEmpty()) { 102 return emptyMap(keySet.comparator()); 103 } else { 104 return new RegularImmutableSortedMap<K, V>( 105 (RegularImmutableSortedSet<K>) keySet, 106 valueList); 107 } 108 } 109 110 /** 111 * Returns the empty sorted map. 112 */ 113 @SuppressWarnings("unchecked") 114 // unsafe, comparator() returns a comparator on the specified type 115 // TODO(kevinb): evaluate whether or not of().comparator() should return null 116 public static <K, V> ImmutableSortedMap<K, V> of() { 117 return (ImmutableSortedMap<K, V>) NATURAL_EMPTY_MAP; 118 } 119 120 /** 121 * Returns an immutable map containing a single entry. 122 */ 123 public static <K extends Comparable<? super K>, V> 124 ImmutableSortedMap<K, V> of(K k1, V v1) { 125 return from(ImmutableSortedSet.of(k1), ImmutableList.of(v1)); 126 } 127 128 /** 129 * Returns an immutable sorted map containing the given entries, sorted by the 130 * natural ordering of their keys. 131 * 132 * @throws IllegalArgumentException if the two keys are equal according to 133 * their natural ordering 134 */ 135 public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V> 136 of(K k1, V v1, K k2, V v2) { 137 return new Builder<K, V>(Ordering.natural()) 138 .put(k1, v1).put(k2, v2).build(); 139 } 140 141 /** 142 * Returns an immutable sorted map containing the given entries, sorted by the 143 * natural ordering of their keys. 144 * 145 * @throws IllegalArgumentException if any two keys are equal according to 146 * their natural ordering 147 */ 148 public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V> 149 of(K k1, V v1, K k2, V v2, K k3, V v3) { 150 return new Builder<K, V>(Ordering.natural()) 151 .put(k1, v1).put(k2, v2).put(k3, v3).build(); 152 } 153 154 /** 155 * Returns an immutable sorted map containing the given entries, sorted by the 156 * natural ordering of their keys. 157 * 158 * @throws IllegalArgumentException if any two keys are equal according to 159 * their natural ordering 160 */ 161 public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V> 162 of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 163 return new Builder<K, V>(Ordering.natural()) 164 .put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).build(); 165 } 166 167 /** 168 * Returns an immutable sorted map containing the given entries, sorted by the 169 * natural ordering of their keys. 170 * 171 * @throws IllegalArgumentException if any two keys are equal according to 172 * their natural ordering 173 */ 174 public static <K extends Comparable<? super K>, V> ImmutableSortedMap<K, V> 175 of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 176 return new Builder<K, V>(Ordering.natural()) 177 .put(k1, v1).put(k2, v2).put(k3, v3).put(k4, v4).put(k5, v5).build(); 178 } 179 180 /** 181 * Returns an immutable map containing the same entries as {@code map}, sorted 182 * by the natural ordering of the keys. 183 * 184 * <p>Despite the method name, this method attempts to avoid actually copying 185 * the data when it is safe to do so. The exact circumstances under which a 186 * copy will or will not be performed are undocumented and subject to change. 187 * 188 * <p>This method is not type-safe, as it may be called on a map with keys 189 * that are not mutually comparable. 190 * 191 * @throws ClassCastException if the keys in {@code map} are not mutually 192 * comparable 193 * @throws NullPointerException if any key or value in {@code map} is null 194 * @throws IllegalArgumentException if any two keys are equal according to 195 * their natural ordering 196 */ 197 public static <K, V> ImmutableSortedMap<K, V> copyOf( 198 Map<? extends K, ? extends V> map) { 199 // Hack around K not being a subtype of Comparable. 200 // Unsafe, see ImmutableSortedSetFauxverideShim. 201 @SuppressWarnings("unchecked") 202 Ordering<K> naturalOrder = (Ordering<K>) Ordering.<Comparable>natural(); 203 return copyOfInternal(map, naturalOrder); 204 } 205 206 /** 207 * Returns an immutable map containing the same entries as {@code map}, with 208 * keys sorted by the provided comparator. 209 * 210 * <p>Despite the method name, this method attempts to avoid actually copying 211 * the data when it is safe to do so. The exact circumstances under which a 212 * copy will or will not be performed are undocumented and subject to change. 213 * 214 * @throws NullPointerException if any key or value in {@code map} is null 215 * @throws IllegalArgumentException if any two keys are equal according to the 216 * comparator 217 */ 218 public static <K, V> ImmutableSortedMap<K, V> copyOf( 219 Map<? extends K, ? extends V> map, Comparator<? super K> comparator) { 220 return copyOfInternal(map, checkNotNull(comparator)); 221 } 222 223 /** 224 * Returns an immutable map containing the same entries as the provided sorted 225 * map, with the same ordering. 226 * 227 * <p>Despite the method name, this method attempts to avoid actually copying 228 * the data when it is safe to do so. The exact circumstances under which a 229 * copy will or will not be performed are undocumented and subject to change. 230 * 231 * @throws NullPointerException if any key or value in {@code map} is null 232 */ 233 @SuppressWarnings("unchecked") 234 public static <K, V> ImmutableSortedMap<K, V> copyOfSorted( 235 SortedMap<K, ? extends V> map) { 236 Comparator<? super K> comparator = map.comparator(); 237 if (comparator == null) { 238 // If map has a null comparator, the keys should have a natural ordering, 239 // even though K doesn't explicitly implement Comparable. 240 comparator = (Comparator<? super K>) NATURAL_ORDER; 241 } 242 return copyOfInternal(map, comparator); 243 } 244 245 private static <K, V> ImmutableSortedMap<K, V> copyOfInternal( 246 Map<? extends K, ? extends V> map, Comparator<? super K> comparator) { 247 boolean sameComparator = false; 248 if (map instanceof SortedMap) { 249 SortedMap<?, ?> sortedMap = (SortedMap<?, ?>) map; 250 Comparator<?> comparator2 = sortedMap.comparator(); 251 sameComparator = (comparator2 == null) 252 ? comparator == NATURAL_ORDER 253 : comparator.equals(comparator2); 254 } 255 256 if (sameComparator && (map instanceof ImmutableSortedMap)) { 257 // TODO(kevinb): Prove that this cast is safe, even though 258 // Collections.unmodifiableSortedMap requires the same key type. 259 @SuppressWarnings("unchecked") 260 ImmutableSortedMap<K, V> kvMap = (ImmutableSortedMap<K, V>) map; 261 if (!kvMap.isPartialView()) { 262 return kvMap; 263 } 264 } 265 266 // "adding" type params to an array of a raw type should be safe as 267 // long as no one can ever cast that same array instance back to a 268 // raw type. 269 @SuppressWarnings("unchecked") 270 Entry<K, V>[] entries = map.entrySet().toArray(new Entry[0]); 271 272 for (int i = 0; i < entries.length; i++) { 273 Entry<K, V> entry = entries[i]; 274 entries[i] = entryOf(entry.getKey(), entry.getValue()); 275 } 276 277 List<Entry<K, V>> list = Arrays.asList(entries); 278 279 if (!sameComparator) { 280 sortEntries(list, comparator); 281 validateEntries(list, comparator); 282 } 283 284 return fromSortedEntries(comparator, list); 285 } 286 287 private static <K, V> void sortEntries( 288 List<Entry<K, V>> entries, final Comparator<? super K> comparator) { 289 Comparator<Entry<K, V>> entryComparator = new Comparator<Entry<K, V>>() { 290 291 @Override public int compare(Entry<K, V> entry1, Entry<K, V> entry2) { 292 return comparator.compare(entry1.getKey(), entry2.getKey()); 293 } 294 }; 295 296 Collections.sort(entries, entryComparator); 297 } 298 299 private static <K, V> void validateEntries(List<Entry<K, V>> entries, 300 Comparator<? super K> comparator) { 301 for (int i = 1; i < entries.size(); i++) { 302 if (comparator.compare( 303 entries.get(i - 1).getKey(), entries.get(i).getKey()) == 0) { 304 throw new IllegalArgumentException( 305 "Duplicate keys in mappings " + entries.get(i - 1) + " and " 306 + entries.get(i)); 307 } 308 } 309 } 310 311 /** 312 * Returns a builder that creates immutable sorted maps whose keys are 313 * ordered by their natural ordering. The sorted maps use {@link 314 * Ordering#natural()} as the comparator. 315 */ 316 public static <K extends Comparable<?>, V> Builder<K, V> naturalOrder() { 317 return new Builder<K, V>(Ordering.natural()); 318 } 319 320 /** 321 * Returns a builder that creates immutable sorted maps with an explicit 322 * comparator. If the comparator has a more general type than the map's keys, 323 * such as creating a {@code SortedMap<Integer, String>} with a {@code 324 * Comparator<Number>}, use the {@link Builder} constructor instead. 325 * 326 * @throws NullPointerException if {@code comparator} is null 327 */ 328 public static <K, V> Builder<K, V> orderedBy(Comparator<K> comparator) { 329 return new Builder<K, V>(comparator); 330 } 331 332 /** 333 * Returns a builder that creates immutable sorted maps whose keys are 334 * ordered by the reverse of their natural ordering. 335 */ 336 public static <K extends Comparable<?>, V> Builder<K, V> reverseOrder() { 337 return new Builder<K, V>(Ordering.natural().reverse()); 338 } 339 340 /** 341 * A builder for creating immutable sorted map instances, especially {@code 342 * public static final} maps ("constant maps"). Example: <pre> {@code 343 * 344 * static final ImmutableSortedMap<Integer, String> INT_TO_WORD = 345 * new ImmutableSortedMap.Builder<Integer, String>(Ordering.natural()) 346 * .put(1, "one") 347 * .put(2, "two") 348 * .put(3, "three") 349 * .build();}</pre> 350 * 351 * For <i>small</i> immutable sorted maps, the {@code ImmutableSortedMap.of()} 352 * methods are even more convenient. 353 * 354 * <p>Builder instances can be reused - it is safe to call {@link #build} 355 * multiple times to build multiple maps in series. Each map is a superset of 356 * the maps created before it. 357 * 358 * @since 2.0 (imported from Google Collections Library) 359 */ 360 public static class Builder<K, V> extends ImmutableMap.Builder<K, V> { 361 private final Comparator<? super K> comparator; 362 363 /** 364 * Creates a new builder. The returned builder is equivalent to the builder 365 * generated by {@link ImmutableSortedMap#orderedBy}. 366 */ 367 public Builder(Comparator<? super K> comparator) { 368 this.comparator = checkNotNull(comparator); 369 } 370 371 /** 372 * Associates {@code key} with {@code value} in the built map. Duplicate 373 * keys, according to the comparator (which might be the keys' natural 374 * order), are not allowed, and will cause {@link #build} to fail. 375 */ 376 @Override public Builder<K, V> put(K key, V value) { 377 entries.add(entryOf(key, value)); 378 return this; 379 } 380 381 /** 382 * Adds the given {@code entry} to the map, making it immutable if 383 * necessary. Duplicate keys, according to the comparator (which might be 384 * the keys' natural order), are not allowed, and will cause {@link #build} 385 * to fail. 386 * 387 * @since 11.0 388 */ 389 @Override public Builder<K, V> put(Entry<? extends K, ? extends V> entry) { 390 super.put(entry); 391 return this; 392 } 393 394 /** 395 * Associates all of the given map's keys and values in the built map. 396 * Duplicate keys, according to the comparator (which might be the keys' 397 * natural order), are not allowed, and will cause {@link #build} to fail. 398 * 399 * @throws NullPointerException if any key or value in {@code map} is null 400 */ 401 @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) { 402 for (Entry<? extends K, ? extends V> entry : map.entrySet()) { 403 put(entry.getKey(), entry.getValue()); 404 } 405 return this; 406 } 407 408 /** 409 * Returns a newly-created immutable sorted map. 410 * 411 * @throws IllegalArgumentException if any two keys are equal according to 412 * the comparator (which might be the keys' natural order) 413 */ 414 @Override public ImmutableSortedMap<K, V> build() { 415 sortEntries(entries, comparator); 416 validateEntries(entries, comparator); 417 return fromSortedEntries(comparator, entries); 418 } 419 } 420 421 ImmutableSortedMap() { 422 } 423 424 ImmutableSortedMap(ImmutableSortedMap<K, V> descendingMap) { 425 this.descendingMap = descendingMap; 426 } 427 428 @Override 429 public int size() { 430 return values().size(); 431 } 432 433 @Override public boolean containsValue(@Nullable Object value) { 434 return values().contains(value); 435 } 436 437 @Override boolean isPartialView() { 438 return keySet().isPartialView() || values().isPartialView(); 439 } 440 441 /** 442 * Returns an immutable set of the mappings in this map, sorted by the key 443 * ordering. 444 */ 445 @Override public ImmutableSet<Entry<K, V>> entrySet() { 446 return super.entrySet(); 447 } 448 449 /** 450 * Returns an immutable sorted set of the keys in this map. 451 */ 452 @Override public abstract ImmutableSortedSet<K> keySet(); 453 454 /** 455 * Returns an immutable collection of the values in this map, sorted by the 456 * ordering of the corresponding keys. 457 */ 458 @Override public abstract ImmutableCollection<V> values(); 459 460 /** 461 * Returns the comparator that orders the keys, which is 462 * {@link Ordering#natural()} when the natural ordering of the keys is used. 463 * Note that its behavior is not consistent with {@link TreeMap#comparator()}, 464 * which returns {@code null} to indicate natural ordering. 465 */ 466 @Override 467 public Comparator<? super K> comparator() { 468 return keySet().comparator(); 469 } 470 471 @Override 472 public K firstKey() { 473 return keySet().first(); 474 } 475 476 @Override 477 public K lastKey() { 478 return keySet().last(); 479 } 480 481 /** 482 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 483 * whose keys are less than {@code toKey}. 484 * 485 * <p>The {@link SortedMap#headMap} documentation states that a submap of a 486 * submap throws an {@link IllegalArgumentException} if passed a {@code toKey} 487 * greater than an earlier {@code toKey}. However, this method doesn't throw 488 * an exception in that situation, but instead keeps the original {@code 489 * toKey}. 490 */ 491 @Override 492 public ImmutableSortedMap<K, V> headMap(K toKey) { 493 return headMap(toKey, false); 494 } 495 496 /** 497 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 498 * whose keys are less than (or equal to, if {@code inclusive}) {@code toKey}. 499 * 500 * <p>The {@link SortedMap#headMap} documentation states that a submap of a 501 * submap throws an {@link IllegalArgumentException} if passed a {@code toKey} 502 * greater than an earlier {@code toKey}. However, this method doesn't throw 503 * an exception in that situation, but instead keeps the original {@code 504 * toKey}. 505 * 506 * @since 12.0 507 */ 508 @Override 509 public abstract ImmutableSortedMap<K, V> headMap(K toKey, boolean inclusive); 510 511 /** 512 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 513 * whose keys ranges from {@code fromKey}, inclusive, to {@code toKey}, 514 * exclusive. 515 * 516 * <p>The {@link SortedMap#subMap} documentation states that a submap of a 517 * submap throws an {@link IllegalArgumentException} if passed a {@code 518 * fromKey} less than an earlier {@code fromKey}. However, this method doesn't 519 * throw an exception in that situation, but instead keeps the original {@code 520 * fromKey}. Similarly, this method keeps the original {@code toKey}, instead 521 * of throwing an exception, if passed a {@code toKey} greater than an earlier 522 * {@code toKey}. 523 */ 524 @Override 525 public ImmutableSortedMap<K, V> subMap(K fromKey, K toKey) { 526 return subMap(fromKey, true, toKey, false); 527 } 528 529 /** 530 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 531 * whose keys ranges from {@code fromKey} to {@code toKey}, inclusive or 532 * exclusive as indicated by the boolean flags. 533 * 534 * <p>The {@link SortedMap#subMap} documentation states that a submap of a 535 * submap throws an {@link IllegalArgumentException} if passed a {@code 536 * fromKey} less than an earlier {@code fromKey}. However, this method doesn't 537 * throw an exception in that situation, but instead keeps the original {@code 538 * fromKey}. Similarly, this method keeps the original {@code toKey}, instead 539 * of throwing an exception, if passed a {@code toKey} greater than an earlier 540 * {@code toKey}. 541 * 542 * @since 12.0 543 */ 544 @Override 545 public ImmutableSortedMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, 546 boolean toInclusive) { 547 checkNotNull(fromKey); 548 checkNotNull(toKey); 549 checkArgument(comparator().compare(fromKey, toKey) <= 0, 550 "expected fromKey <= toKey but %s > %s", fromKey, toKey); 551 return headMap(toKey, toInclusive).tailMap(fromKey, fromInclusive); 552 } 553 554 /** 555 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 556 * whose keys are greater than or equals to {@code fromKey}. 557 * 558 * <p>The {@link SortedMap#tailMap} documentation states that a submap of a 559 * submap throws an {@link IllegalArgumentException} if passed a {@code 560 * fromKey} less than an earlier {@code fromKey}. However, this method doesn't 561 * throw an exception in that situation, but instead keeps the original {@code 562 * fromKey}. 563 */ 564 @Override 565 public ImmutableSortedMap<K, V> tailMap(K fromKey) { 566 return tailMap(fromKey, true); 567 } 568 569 /** 570 * This method returns a {@code ImmutableSortedMap}, consisting of the entries 571 * whose keys are greater than (or equal to, if {@code inclusive}) 572 * {@code fromKey}. 573 * 574 * <p>The {@link SortedMap#tailMap} documentation states that a submap of a 575 * submap throws an {@link IllegalArgumentException} if passed a {@code 576 * fromKey} less than an earlier {@code fromKey}. However, this method doesn't 577 * throw an exception in that situation, but instead keeps the original {@code 578 * fromKey}. 579 * 580 * @since 12.0 581 */ 582 @Override 583 public abstract ImmutableSortedMap<K, V> tailMap(K fromKey, boolean inclusive); 584 585 @Override 586 public Entry<K, V> lowerEntry(K key) { 587 return headMap(key, false).lastEntry(); 588 } 589 590 @Override 591 public K lowerKey(K key) { 592 return keyOrNull(lowerEntry(key)); 593 } 594 595 @Override 596 public Entry<K, V> floorEntry(K key) { 597 return headMap(key, true).lastEntry(); 598 } 599 600 @Override 601 public K floorKey(K key) { 602 return keyOrNull(floorEntry(key)); 603 } 604 605 @Override 606 public Entry<K, V> ceilingEntry(K key) { 607 return tailMap(key, true).firstEntry(); 608 } 609 610 @Override 611 public K ceilingKey(K key) { 612 return keyOrNull(ceilingEntry(key)); 613 } 614 615 @Override 616 public Entry<K, V> higherEntry(K key) { 617 return tailMap(key, false).firstEntry(); 618 } 619 620 @Override 621 public K higherKey(K key) { 622 return keyOrNull(higherEntry(key)); 623 } 624 625 @Override 626 public Entry<K, V> firstEntry() { 627 return isEmpty() ? null : entrySet().asList().get(0); 628 } 629 630 @Override 631 public Entry<K, V> lastEntry() { 632 return isEmpty() ? null : entrySet().asList().get(size() - 1); 633 } 634 635 /** 636 * Guaranteed to throw an exception and leave the map unmodified. 637 * 638 * @throws UnsupportedOperationException always 639 * @deprecated Unsupported operation. 640 */ 641 @Deprecated 642 @Override 643 public final Entry<K, V> pollFirstEntry() { 644 throw new UnsupportedOperationException(); 645 } 646 647 /** 648 * Guaranteed to throw an exception and leave the map unmodified. 649 * 650 * @throws UnsupportedOperationException always 651 * @deprecated Unsupported operation. 652 */ 653 @Deprecated 654 @Override 655 public final Entry<K, V> pollLastEntry() { 656 throw new UnsupportedOperationException(); 657 } 658 659 private transient ImmutableSortedMap<K, V> descendingMap; 660 661 @Override 662 public ImmutableSortedMap<K, V> descendingMap() { 663 ImmutableSortedMap<K, V> result = descendingMap; 664 if (result == null) { 665 result = descendingMap = createDescendingMap(); 666 } 667 return result; 668 } 669 670 abstract ImmutableSortedMap<K, V> createDescendingMap(); 671 672 @Override 673 public ImmutableSortedSet<K> navigableKeySet() { 674 return keySet(); 675 } 676 677 @Override 678 public ImmutableSortedSet<K> descendingKeySet() { 679 return keySet().descendingSet(); 680 } 681 682 /** 683 * Serialized type for all ImmutableSortedMap instances. It captures the 684 * logical contents and they are reconstructed using public factory methods. 685 * This ensures that the implementation types remain as implementation 686 * details. 687 */ 688 private static class SerializedForm extends ImmutableMap.SerializedForm { 689 private final Comparator<Object> comparator; 690 @SuppressWarnings("unchecked") 691 SerializedForm(ImmutableSortedMap<?, ?> sortedMap) { 692 super(sortedMap); 693 comparator = (Comparator<Object>) sortedMap.comparator(); 694 } 695 @Override Object readResolve() { 696 Builder<Object, Object> builder = new Builder<Object, Object>(comparator); 697 return createMap(builder); 698 } 699 private static final long serialVersionUID = 0; 700 } 701 702 @Override Object writeReplace() { 703 return new SerializedForm(this); 704 } 705 706 // This class is never actually serialized directly, but we have to make the 707 // warning go away (and suppressing would suppress for all nested classes too) 708 private static final long serialVersionUID = 0; 709}