< prev index next >

src/java.base/share/classes/java/util/ImmutableCollections.java

Print this page
rev 48431 : 8193128: Reduce number of implementation classes returned by List/Set/Map.of()
8191418: List.of().indexOf(null) doesn't throw NullPointerException
Reviewed-by: smarks, jrose, martin, plevart


  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 
  28 import java.io.IOException;
  29 import java.io.InvalidObjectException;
  30 import java.io.ObjectInputStream;
  31 import java.io.ObjectOutputStream;
  32 import java.io.ObjectStreamException;
  33 import java.io.Serializable;
  34 import java.util.function.BiFunction;
  35 import java.util.function.Function;
  36 import java.util.function.Predicate;
  37 import java.util.function.UnaryOperator;
  38 import jdk.internal.misc.SharedSecrets;

  39 import jdk.internal.vm.annotation.Stable;
  40 
  41 /**
  42  * Container class for immutable collections. Not part of the public API.
  43  * Mainly for namespace management and shared infrastructure.
  44  *
  45  * Serial warnings are suppressed throughout because all implementation
  46  * classes use a serial proxy and thus have no need to declare serialVersionUID.
  47  */
  48 @SuppressWarnings("serial")
  49 class ImmutableCollections {
  50     /**
  51      * A "salt" value used for randomizing iteration order. This is initialized once
  52      * and stays constant for the lifetime of the JVM. It need not be truly random, but
  53      * it needs to vary sufficiently from one run to the next so that iteration order
  54      * will vary between JVM runs.
  55      */
  56     static final int SALT;
  57     static {
  58         long nt = System.nanoTime();
  59         SALT = (int)((nt >>> 32) ^ nt);
  60     }
  61 
  62     /** No instances. */
  63     private ImmutableCollections() { }
  64 
  65     /**
  66      * The reciprocal of load factor. Given a number of elements
  67      * to store, multiply by this factor to get the table size.
  68      */
  69     static final int EXPAND_FACTOR = 2;
  70 
  71     static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
  72 
  73     // ---------- List Implementations ----------
  74 
  75     abstract static class AbstractImmutableList<E> extends AbstractList<E>
  76                                                 implements RandomAccess, Serializable {





  77         @Override public boolean add(E e) { throw uoe(); }
  78         @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
  79         @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
  80         @Override public void    clear() { throw uoe(); }
  81         @Override public boolean remove(Object o) { throw uoe(); }
  82         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
  83         @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
  84         @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
  85         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
  86         @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
  87     }
  88 
  89     static final class List0<E> extends AbstractImmutableList<E> {
  90         private static final List0<?> INSTANCE = new List0<>();
  91 
  92         @SuppressWarnings("unchecked")
  93         static <T> List0<T> instance() {
  94             return (List0<T>) INSTANCE;













  95         }
  96 
  97         private List0() { }









  98 
  99         @Override
 100         public int size() {
 101             return 0;



























 102         }
 103 
 104         @Override
 105         public E get(int index) {
 106             Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
 107             return null;                  // but the compiler doesn't know this
 108         }
 109 
 110         @Override
 111         public Iterator<E> iterator() {
 112             return Collections.emptyIterator();
 113         }
 114 
 115         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 116             throw new InvalidObjectException("not serial proxy");
 117         }
 118 
 119         private Object writeReplace() {
 120             return new CollSer(CollSer.IMM_LIST);







 121         }
 122 
 123         @Override
 124         public boolean contains(Object o) {
 125             Objects.requireNonNull(o);
 126             return false;


 127         }
 128 
 129         @Override
 130         public boolean containsAll(Collection<?> o) {
 131             return o.isEmpty(); // implicit nullcheck of o
 132         }
 133 
 134         @Override
 135         public int hashCode() {
 136             return 1;


 137         }
 138     }
 139 
 140     static final class List1<E> extends AbstractImmutableList<E> {
 141         @Stable
 142         private final E e0;
 143 
 144         List1(E e0) {
 145             this.e0 = Objects.requireNonNull(e0);
 146         }
 147 
 148         @Override
 149         public int size() {
 150             return 1;

 151         }
 152 
 153         @Override
 154         public E get(int index) {
 155             Objects.checkIndex(index, 1);
 156             return e0;
 157         }
 158 
 159         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 160             throw new InvalidObjectException("not serial proxy");



 161         }
 162 
 163         private Object writeReplace() {
 164             return new CollSer(CollSer.IMM_LIST, e0);






 165         }
 166 
 167         @Override
 168         public boolean contains(Object o) {
 169             return o.equals(e0); // implicit nullcheck of o
 170         }
 171 
 172         @Override
 173         public int hashCode() {
 174             return 31 + e0.hashCode();







 175         }

 176     }
 177 
 178     static final class List2<E> extends AbstractImmutableList<E> {
 179         @Stable
 180         private final E e0;
 181         @Stable
 182         private final E e1;
 183 
 184         List2(E e0, E e1) {
 185             this.e0 = Objects.requireNonNull(e0);
 186             this.e1 = Objects.requireNonNull(e1);



 187         }
 188 
 189         @Override
 190         public int size() {
 191             return 2;
 192         }
 193 
 194         @Override
 195         public E get(int index) {
 196             Objects.checkIndex(index, 2);
 197             if (index == 0) {
 198                 return e0;
 199             } else { // index == 1
 200                 return e1;

 201             }
 202         }
 203 
 204         @Override
 205         public boolean contains(Object o) {
 206             return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
 207         }
 208 
 209         @Override
 210         public int hashCode() {
 211             int hash = 31 + e0.hashCode();
 212             return 31 * hash + e1.hashCode();

 213         }
 214 
 215         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 216             throw new InvalidObjectException("not serial proxy");
 217         }
 218 
 219         private Object writeReplace() {
 220             return new CollSer(CollSer.IMM_LIST, e0, e1);






 221         }
 222     }
 223 
 224     static final class ListN<E> extends AbstractImmutableList<E> {
 225         @Stable
 226         private final E[] elements;
 227 
 228         @SafeVarargs
 229         ListN(E... input) {
 230             // copy and check manually to avoid TOCTOU
 231             @SuppressWarnings("unchecked")
 232             E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
 233             for (int i = 0; i < input.length; i++) {
 234                 tmp[i] = Objects.requireNonNull(input[i]);



 235             }
 236             this.elements = tmp;
 237         }
 238 
 239         @Override
 240         public int size() {
 241             return elements.length;














 242         }
 243 
 244         @Override
 245         public E get(int index) {
 246             Objects.checkIndex(index, elements.length);
 247             return elements[index];





 248         }
 249 
 250         @Override
 251         public boolean contains(Object o) {
 252             for (E e : elements) {
 253                 if (o.equals(e)) { // implicit nullcheck of o
 254                     return true;

 255                 }
 256             }
 257             return false;
 258         }
 259 
 260         @Override
 261         public int hashCode() {
 262             int hash = 1;
 263             for (E e : elements) {
 264                 hash = 31 * hash + e.hashCode();
 265             }
 266             return hash;
 267         }
 268 
 269         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 270             throw new InvalidObjectException("not serial proxy");

 271         }
 272 
 273         private Object writeReplace() {
 274             return new CollSer(CollSer.IMM_LIST, elements);
 275         }
 276     }
 277 
 278     // ---------- Set Implementations ----------

 279 
 280     abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
 281         @Override public boolean add(E e) { throw uoe(); }
 282         @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
 283         @Override public void    clear() { throw uoe(); }
 284         @Override public boolean remove(Object o) { throw uoe(); }
 285         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
 286         @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
 287         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
 288     }
 289 
 290     static final class Set0<E> extends AbstractImmutableSet<E> {
 291         private static final Set0<?> INSTANCE = new Set0<>();
 292 
 293         @SuppressWarnings("unchecked")
 294         static <T> Set0<T> instance() {
 295             return (Set0<T>) INSTANCE;
 296         }
 297 
 298         private Set0() { }
 299 
 300         @Override
 301         public int size() {
 302             return 0;
 303         }
 304 
 305         @Override
 306         public boolean contains(Object o) {
 307             Objects.requireNonNull(o);
 308             return false;
 309         }
 310 
 311         @Override
 312         public boolean containsAll(Collection<?> o) {
 313             return o.isEmpty(); // implicit nullcheck of o



 314         }
 315 
 316         @Override
 317         public Iterator<E> iterator() {
 318             return Collections.emptyIterator();
 319         }
 320 
 321         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 322             throw new InvalidObjectException("not serial proxy");
 323         }
 324 
 325         private Object writeReplace() {
 326             return new CollSer(CollSer.IMM_SET);



 327         }
 328 
 329         @Override
 330         public int hashCode() {
 331             return 0;
 332         }

 333     }
 334 
 335     static final class Set1<E> extends AbstractImmutableSet<E> {




 336         @Stable
 337         private final E e0;
 338 
 339         Set1(E e0) {
 340             this.e0 = Objects.requireNonNull(e0);







 341         }
 342 
 343         @Override
 344         public int size() {
 345             return 1;
 346         }
 347 
 348         @Override
 349         public boolean contains(Object o) {
 350             return o.equals(e0); // implicit nullcheck of o
 351         }
 352 
 353         @Override
 354         public Iterator<E> iterator() {
 355             return Collections.singletonIterator(e0);
 356         }
 357 
 358         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 359             throw new InvalidObjectException("not serial proxy");
 360         }
 361 
 362         private Object writeReplace() {
 363             return new CollSer(CollSer.IMM_SET, e0);
 364         }
 365 
 366         @Override
 367         public int hashCode() {
 368             return e0.hashCode();
 369         }






 370     }
 371 
 372     static final class Set2<E> extends AbstractImmutableSet<E> {


 373         @Stable
 374         final E e0;
 375         @Stable
 376         final E e1;
 377 
 378         Set2(E e0, E e1) {





 379             if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
 380                 throw new IllegalArgumentException("duplicate element: " + e0);
 381             }
 382 
 383             if (SALT >= 0) {
 384                 this.e0 = e0;
 385                 this.e1 = e1;
 386             } else {
 387                 this.e0 = e1;
 388                 this.e1 = e0;
 389             }
 390         }
 391 
 392         @Override
 393         public int size() {
 394             return 2;
 395         }
 396 
 397         @Override
 398         public boolean contains(Object o) {
 399             return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
 400         }
 401 
 402         @Override
 403         public int hashCode() {
 404             return e0.hashCode() + e1.hashCode();
 405         }
 406 
 407         @Override
 408         public Iterator<E> iterator() {
 409             return new Iterator<E>() {
 410                 private int idx = 0;
 411 
 412                 @Override
 413                 public boolean hasNext() {
 414                     return idx < 2;
 415                 }
 416 
 417                 @Override
 418                 public E next() {
 419                     if (idx == 0) {
 420                         idx = 1;
 421                         return e0;
 422                     } else if (idx == 1) {
 423                         idx = 2;
 424                         return e1;
 425                     } else {
 426                         throw new NoSuchElementException();
 427                     }
 428                 }
 429             };
 430         }
 431 
 432         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 433             throw new InvalidObjectException("not serial proxy");
 434         }
 435 
 436         private Object writeReplace() {



 437             return new CollSer(CollSer.IMM_SET, e0, e1);
 438         }
 439     }

 440 
 441     /**
 442      * An array-based Set implementation. The element array must be strictly
 443      * larger than the size (the number of contained elements) so that at
 444      * least one null is always present.
 445      * @param <E> the element type
 446      */
 447     static final class SetN<E> extends AbstractImmutableSet<E> {




 448         @Stable
 449         final E[] elements;
 450         @Stable
 451         final int size;
 452 
 453         @SafeVarargs
 454         @SuppressWarnings("unchecked")
 455         SetN(E... input) {
 456             size = input.length; // implicit nullcheck of input
 457 
 458             elements = (E[])new Object[EXPAND_FACTOR * input.length];
 459             for (int i = 0; i < input.length; i++) {
 460                 E e = input[i];
 461                 int idx = probe(e); // implicit nullcheck of e
 462                 if (idx >= 0) {
 463                     throw new IllegalArgumentException("duplicate element: " + e);
 464                 } else {
 465                     elements[-(idx + 1)] = e;
 466                 }
 467             }
 468         }
 469 
 470         @Override
 471         public int size() {
 472             return size;
 473         }
 474 
 475         @Override
 476         public boolean contains(Object o) {
 477             return probe(o) >= 0; // implicit nullcheck of o

 478         }
 479 
 480         @Override
 481         public Iterator<E> iterator() {
 482             return new Iterator<E>() {
 483                 private int idx = 0;
 484 
 485                 @Override
 486                 public boolean hasNext() {
 487                     while (idx < elements.length) {
 488                         if (elements[idx] != null)
 489                             return true;
 490                         idx++;
 491                     }
 492                     return false;
 493                 }
 494 
 495                 @Override
 496                 public E next() {
 497                     if (! hasNext()) {


 532         }
 533 
 534         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 535             throw new InvalidObjectException("not serial proxy");
 536         }
 537 
 538         private Object writeReplace() {
 539             Object[] array = new Object[size];
 540             int dest = 0;
 541             for (Object o : elements) {
 542                 if (o != null) {
 543                     array[dest++] = o;
 544                 }
 545             }
 546             return new CollSer(CollSer.IMM_SET, array);
 547         }
 548     }
 549 
 550     // ---------- Map Implementations ----------
 551 





 552     abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
 553         @Override public void clear() { throw uoe(); }
 554         @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 555         @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
 556         @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 557         @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
 558         @Override public V put(K key, V value) { throw uoe(); }
 559         @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
 560         @Override public V putIfAbsent(K key, V value) { throw uoe(); }
 561         @Override public V remove(Object key) { throw uoe(); }
 562         @Override public boolean remove(Object key, Object value) { throw uoe(); }
 563         @Override public V replace(K key, V value) { throw uoe(); }
 564         @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
 565         @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
 566     }
 567 
 568     static final class Map0<K,V> extends AbstractImmutableMap<K,V> {
 569         private static final Map0<?,?> INSTANCE = new Map0<>();
 570 
 571         @SuppressWarnings("unchecked")
 572         static <K,V> Map0<K,V> instance() {
 573             return (Map0<K,V>) INSTANCE;
 574         }
 575 
 576         private Map0() { }
 577 
 578         @Override
 579         public Set<Map.Entry<K,V>> entrySet() {
 580             return Set.of();
 581         }
 582 
 583         @Override
 584         public boolean containsKey(Object o) {
 585             Objects.requireNonNull(o);
 586             return false;
 587         }
 588 
 589         @Override
 590         public boolean containsValue(Object o) {
 591             Objects.requireNonNull(o);
 592             return false;
 593         }
 594 
 595         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 596             throw new InvalidObjectException("not serial proxy");
 597         }
 598 
 599         private Object writeReplace() {
 600             return new CollSer(CollSer.IMM_MAP);
 601         }
 602 
 603         @Override
 604         public int hashCode() {
 605             return 0;
 606         }
 607     }
 608 
 609     static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
 610         @Stable
 611         private final K k0;
 612         @Stable
 613         private final V v0;
 614 
 615         Map1(K k0, V v0) {
 616             this.k0 = Objects.requireNonNull(k0);
 617             this.v0 = Objects.requireNonNull(v0);
 618         }
 619 
 620         @Override
 621         public Set<Map.Entry<K,V>> entrySet() {
 622             return Set.of(new KeyValueHolder<>(k0, v0));
 623         }
 624 
 625         @Override
 626         public boolean containsKey(Object o) {
 627             return o.equals(k0); // implicit nullcheck of o
 628         }


 639         private Object writeReplace() {
 640             return new CollSer(CollSer.IMM_MAP, k0, v0);
 641         }
 642 
 643         @Override
 644         public int hashCode() {
 645             return k0.hashCode() ^ v0.hashCode();
 646         }
 647     }
 648 
 649     /**
 650      * An array-based Map implementation. There is a single array "table" that
 651      * contains keys and values interleaved: table[0] is kA, table[1] is vA,
 652      * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
 653      * also be strictly larger than the size (the number of key-value pairs contained
 654      * in the map) so that at least one null key is always present.
 655      * @param <K> the key type
 656      * @param <V> the value type
 657      */
 658     static final class MapN<K,V> extends AbstractImmutableMap<K,V> {



 659         @Stable
 660         final Object[] table; // pairs of key, value

 661         @Stable
 662         final int size; // number of pairs
 663 
 664         MapN(Object... input) {
 665             if ((input.length & 1) != 0) { // implicit nullcheck of input
 666                 throw new InternalError("length is odd");
 667             }
 668             size = input.length >> 1;
 669 
 670             int len = EXPAND_FACTOR * input.length;
 671             len = (len + 1) & ~1; // ensure table is even length
 672             table = new Object[len];
 673 
 674             for (int i = 0; i < input.length; i += 2) {
 675                 @SuppressWarnings("unchecked")
 676                     K k = Objects.requireNonNull((K)input[i]);
 677                 @SuppressWarnings("unchecked")
 678                     V v = Objects.requireNonNull((V)input[i+1]);
 679                 int idx = probe(k);
 680                 if (idx >= 0) {
 681                     throw new IllegalArgumentException("duplicate key: " + k);
 682                 } else {
 683                     int dest = -(idx + 1);
 684                     table[dest] = k;
 685                     table[dest+1] = v;
 686                 }
 687             }
 688         }
 689 
 690         @Override
 691         public boolean containsKey(Object o) {
 692             return probe(o) >= 0; // implicit nullcheck of o

 693         }
 694 
 695         @Override
 696         public boolean containsValue(Object o) {

 697             for (int i = 1; i < table.length; i += 2) {
 698                 Object v = table[i];
 699                 if (v != null && o.equals(v)) { // implicit nullcheck of o
 700                     return true;
 701                 }
 702             }
 703             return false;
 704         }
 705 
 706         @Override
 707         public int hashCode() {
 708             int hash = 0;
 709             for (int i = 0; i < table.length; i += 2) {
 710                 Object k = table[i];
 711                 if (k != null) {
 712                     hash += k.hashCode() ^ table[i + 1].hashCode();
 713                 }
 714             }
 715             return hash;
 716         }
 717 
 718         @Override
 719         @SuppressWarnings("unchecked")
 720         public V get(Object o) {




 721             int i = probe(o);
 722             if (i >= 0) {
 723                 return (V)table[i+1];
 724             } else {
 725                 return null;
 726             }
 727         }
 728 
 729         @Override
 730         public int size() {
 731             return size;
 732         }
 733 
 734         @Override
 735         public Set<Map.Entry<K,V>> entrySet() {
 736             return new AbstractSet<Map.Entry<K,V>>() {
 737                 @Override
 738                 public int size() {
 739                     return MapN.this.size;
 740                 }
 741 
 742                 @Override
 743                 public Iterator<Map.Entry<K,V>> iterator() {
 744                     return new Iterator<Map.Entry<K,V>>() {
 745                         int idx = 0;
 746 
 747                         @Override
 748                         public boolean hasNext() {
 749                             while (idx < table.length) {
 750                                 if (table[idx] != null)
 751                                     return true;
 752                                 idx += 2;
 753                             }
 754                             return false;
 755                         }
 756 
 757                         @Override
 758                         public Map.Entry<K,V> next() {
 759                             if (hasNext()) {
 760                                 @SuppressWarnings("unchecked")
 761                                 Map.Entry<K,V> e =
 762                                     new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
 763                                 idx += 2;
 764                                 return e;


 931      * @throws InvalidObjectException if the tag value is illegal or if an exception
 932      *         is thrown during creation of the collection
 933      * @throws ObjectStreamException if another serialization error has occurred
 934      * @since 9
 935      */
 936     private Object readResolve() throws ObjectStreamException {
 937         try {
 938             if (array == null) {
 939                 throw new InvalidObjectException("null array");
 940             }
 941 
 942             // use low order 8 bits to indicate "kind"
 943             // ignore high order 24 bits
 944             switch (tag & 0xff) {
 945                 case IMM_LIST:
 946                     return List.of(array);
 947                 case IMM_SET:
 948                     return Set.of(array);
 949                 case IMM_MAP:
 950                     if (array.length == 0) {
 951                         return ImmutableCollections.Map0.instance();
 952                     } else if (array.length == 2) {
 953                         return new ImmutableCollections.Map1<>(array[0], array[1]);
 954                     } else {
 955                         return new ImmutableCollections.MapN<>(array);
 956                     }
 957                 default:
 958                     throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
 959             }
 960         } catch (NullPointerException|IllegalArgumentException ex) {
 961             InvalidObjectException ioe = new InvalidObjectException("invalid object");
 962             ioe.initCause(ex);
 963             throw ioe;
 964         }
 965     }
 966 }


  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.util;
  27 
  28 import java.io.IOException;
  29 import java.io.InvalidObjectException;
  30 import java.io.ObjectInputStream;
  31 import java.io.ObjectOutputStream;
  32 import java.io.ObjectStreamException;
  33 import java.io.Serializable;
  34 import java.util.function.BiFunction;
  35 import java.util.function.Function;
  36 import java.util.function.Predicate;
  37 import java.util.function.UnaryOperator;
  38 import jdk.internal.misc.SharedSecrets;
  39 import jdk.internal.vm.annotation.ForceInline;
  40 import jdk.internal.vm.annotation.Stable;
  41 
  42 /**
  43  * Container class for immutable collections. Not part of the public API.
  44  * Mainly for namespace management and shared infrastructure.
  45  *
  46  * Serial warnings are suppressed throughout because all implementation
  47  * classes use a serial proxy and thus have no need to declare serialVersionUID.
  48  */
  49 @SuppressWarnings("serial")
  50 class ImmutableCollections {
  51     /**
  52      * A "salt" value used for randomizing iteration order. This is initialized once
  53      * and stays constant for the lifetime of the JVM. It need not be truly random, but
  54      * it needs to vary sufficiently from one run to the next so that iteration order
  55      * will vary between JVM runs.
  56      */
  57     static final int SALT;
  58     static {
  59         long nt = System.nanoTime();
  60         SALT = (int)((nt >>> 32) ^ nt);
  61     }
  62 
  63     /** No instances. */
  64     private ImmutableCollections() { }
  65 
  66     /**
  67      * The reciprocal of load factor. Given a number of elements
  68      * to store, multiply by this factor to get the table size.
  69      */
  70     static final int EXPAND_FACTOR = 2;
  71 
  72     static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
  73 
  74     // ---------- List Implementations ----------
  75 
  76     @SuppressWarnings("unchecked")
  77     static <E> List<E> emptyList() {
  78         return (List<E>) ListN.EMPTY_LIST;
  79     }
  80 
  81     static abstract class AbstractImmutableCollection<E> extends AbstractCollection<E> {
  82         // all mutating methods throw UnsupportedOperationException
  83         @Override public boolean add(E e) { throw uoe(); }
  84         @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }

  85         @Override public void    clear() { throw uoe(); }
  86         @Override public boolean remove(Object o) { throw uoe(); }
  87         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
  88         @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }

  89         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }

  90     }
  91 
  92     static abstract class AbstractImmutableSet<E> extends AbstractImmutableCollection<E>
  93             implements Set<E> {
  94 
  95         @Override
  96         public boolean equals(Object o) {
  97             if (o == this)
  98                 return true;
  99 
 100             if (!(o instanceof Set))
 101                 return false;
 102             Collection<?> c = (Collection<?>) o;
 103             if (c.size() != size())
 104                 return false;
 105             try {
 106                 return containsAll(c);
 107             } catch (ClassCastException | NullPointerException unused) {
 108                 return false;
 109             }
 110         }
 111     }
 112 
 113     static abstract class AbstractImmutableList<E> extends AbstractImmutableCollection<E>
 114             implements List<E>, RandomAccess {
 115 
 116         // all mutating methods throw UnsupportedOperationException
 117         @Override public void    add(int index, E element) { throw uoe(); }
 118         @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
 119         @Override public E       remove(int index) { throw uoe(); }
 120         @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
 121         @Override public E       set(int index, E element) { throw uoe(); }
 122         @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
 123 
 124         @Override
 125         public List<E> subList(int fromIndex, int toIndex) {
 126             int size = size();
 127             subListRangeCheck(fromIndex, toIndex, size);
 128             return new SubList<E>(this, fromIndex, toIndex);
 129         }
 130 
 131         private static final class SubList<E> extends AbstractImmutableList<E>
 132                 implements RandomAccess {
 133             private final List<E> root;
 134             final int offset;
 135             int size;
 136 
 137             /**
 138              * Constructs a sublist of an arbitrary AbstractList, which is
 139              * not a SubList itself.
 140              */
 141             SubList(List<E> root, int fromIndex, int toIndex) {
 142                 this.root = root;
 143                 this.offset = fromIndex;
 144                 this.size = toIndex - fromIndex;
 145             }
 146 
 147             /**
 148              * Constructs a sublist of another SubList.
 149              */
 150             SubList(SubList<E> parent, int fromIndex, int toIndex) {
 151                 this.root = parent.root;
 152                 this.offset = parent.offset + fromIndex;
 153                 this.size = toIndex - fromIndex;
 154             }
 155 

 156             public E get(int index) {
 157                 Objects.checkIndex(index, size);
 158                 return root.get(offset + index);
 159             }
 160 
 161             public int size() {
 162                 return size;

 163             }
 164 
 165             public Iterator<E> iterator() {
 166                 return listIterator();
 167             }
 168 
 169             public ListIterator<E> listIterator(int index) {
 170                 rangeCheck(index);
 171 
 172                 ListIterator<E> i = root.listIterator(offset + index);
 173 
 174                 return new ListIterator<>() {
 175 
 176                     public boolean hasNext() {
 177                         return nextIndex() < size;
 178                     }
 179 
 180                     public E next() {
 181                         if (hasNext()) {
 182                             return i.next();
 183                         } else {
 184                             throw new NoSuchElementException();
 185                         }
 186                     }
 187 
 188                     public boolean hasPrevious() {
 189                         return previousIndex() >= 0;

 190                     }
 191 
 192                     public E previous() {
 193                         if (hasPrevious()) {
 194                             return i.previous();
 195                         } else {
 196                             throw new NoSuchElementException();
 197                         }
 198                     }
 199 
 200                     public int nextIndex() {
 201                         return i.nextIndex() - offset;
 202                     }
 203 
 204                     public int previousIndex() {
 205                         return i.previousIndex() - offset;
 206                     }
 207 
 208                     public void remove() { throw uoe(); }
 209                     public void set(E e) { throw uoe(); }
 210                     public void add(E e) { throw uoe(); }
 211                 };
 212             }
 213 
 214             public List<E> subList(int fromIndex, int toIndex) {
 215                 subListRangeCheck(fromIndex, toIndex, size);
 216                 return new SubList<>(this, fromIndex, toIndex);

 217             }
 218 
 219             private void rangeCheck(int index) {
 220                 if (index < 0 || index > size) {
 221                     throw outOfBounds(index);
 222                 }
 223             }
 224         }
 225 
 226         static void subListRangeCheck(int fromIndex, int toIndex, int size) {
 227             if (fromIndex < 0)
 228                 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
 229             if (toIndex > size)
 230                 throw new IndexOutOfBoundsException("toIndex = " + toIndex);
 231             if (fromIndex > toIndex)
 232                 throw new IllegalArgumentException("fromIndex(" + fromIndex +
 233                         ") > toIndex(" + toIndex + ")");
 234         }
 235 
 236         @Override
 237         public Iterator<E> iterator() {
 238             return new Itr(size());
 239         }
 240 
 241         @Override
 242         public ListIterator<E> listIterator() {
 243             return listIterator(0);
 244         }
 245 
 246         @Override
 247         public ListIterator<E> listIterator(final int index) {
 248             int size = size();
 249             if (index < 0 || index > size) {
 250                 throw outOfBounds(index);
 251             }
 252             return new ListItr(index, size);
 253         }
 254 
 255         private class Itr implements Iterator<E> {




 256 
 257             int cursor;
 258 
 259             private final int size;
 260 
 261             Itr(int size) {
 262                 this.size = size;
 263             }
 264 
 265             public boolean hasNext() {
 266                 return cursor != size;

 267             }
 268 
 269             public E next() {
 270                 try {
 271                     int i = cursor;
 272                     E next = get(i);
 273                     cursor = i + 1;
 274                     return next;
 275                 } catch (IndexOutOfBoundsException e) {
 276                     throw new NoSuchElementException();
 277                 }
 278             }
 279 
 280             public void remove() {
 281                 throw uoe();
 282             }
 283         }
 284 
 285         private class ListItr extends Itr implements ListIterator<E> {
 286 
 287             ListItr(int index, int size) {
 288                 super(size);
 289                 cursor = index;
 290             }
 291 
 292             public boolean hasPrevious() {
 293                 return cursor != 0;
 294             }
 295 
 296             public E previous() {
 297                 try {
 298                     int i = cursor - 1;
 299                     E previous = get(i);
 300                     cursor = i;
 301                     return previous;
 302                 } catch (IndexOutOfBoundsException e) {
 303                     throw new NoSuchElementException();
 304                 }
 305             }
 306 
 307             public int nextIndex() {
 308                 return cursor;
 309             }
 310 
 311             public int previousIndex() {
 312                 return cursor - 1;
 313             }
 314 
 315             public void set(E e) {
 316                 throw uoe();
 317             }
 318 
 319             public void add(E e) {
 320                 throw uoe();
 321             }

 322         }
 323 
 324         @Override
 325         public boolean equals(Object o) {
 326             if (o == this) {
 327                 return true;
 328             }
 329 
 330             if (!(o instanceof List)) {
 331                 return false;
 332             }
 333 
 334             Iterator<?> oit = ((List<?>) o).iterator();
 335             for (int i = 0, s = size(); i < s; i++) {
 336                 if (!oit.hasNext() || !get(i).equals(oit.next())) {
 337                     return false;
 338                 }
 339             }
 340             return !oit.hasNext();
 341         }
 342 
 343         @Override
 344         public int indexOf(Object o) {
 345             Objects.requireNonNull(o);
 346             for (int i = 0, s = size(); i < s; i++) {
 347                 if (o.equals(get(i))) {
 348                     return i;
 349                 }
 350             }
 351             return -1;
 352         }
 353 
 354         @Override
 355         public int lastIndexOf(Object o) {
 356             Objects.requireNonNull(o);
 357             for (int i = size() - 1; i >= 0; i--) {
 358                 if (o.equals(get(i))) {
 359                     return i;
 360                 }
 361             }
 362             return -1;
 363         }
 364 
 365         @Override
 366         public int hashCode() {
 367             int hash = 1;
 368             for (int i = 0, s = size(); i < s; i++) {
 369                 hash = 31 * hash + get(i).hashCode();
 370             }
 371             return hash;
 372         }
 373 
 374         @Override
 375         public boolean contains(Object o) {
 376             return indexOf(o) >= 0;
 377         }
 378 
 379         IndexOutOfBoundsException outOfBounds(int index) {
 380             return new IndexOutOfBoundsException("Index: " + index + " Size: " + size());
 381         }
 382     }
 383 
 384     static final class List12<E> extends AbstractImmutableList<E>
 385             implements Serializable {
 386 
 387         @Stable
 388         private final E e0;







 389 
 390         @Stable
 391         private final E e1;
 392 
 393         List12(E e0) {
 394             this.e0 = Objects.requireNonNull(e0);
 395             this.e1 = null;
 396         }
 397 
 398         List12(E e0, E e1) {
 399             this.e0 = Objects.requireNonNull(e0);
 400             this.e1 = Objects.requireNonNull(e1);


 401         }
 402 
 403         @Override
 404         public int size() {
 405             return e1 != null ? 2 : 1;

 406         }
 407 
 408         @Override
 409         public E get(int index) {
 410             if (index == 0) {
 411                 return e0;
 412             } else if (index == 1 && e1 != null) {
 413                 return e1;
 414             }
 415             throw outOfBounds(index);



 416         }
 417 
 418         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 419             throw new InvalidObjectException("not serial proxy");
 420         }
 421 
 422         private Object writeReplace() {
 423             if (e1 == null) {
 424                 return new CollSer(CollSer.IMM_LIST, e0);
 425             } else {
 426                 return new CollSer(CollSer.IMM_LIST, e0, e1);
 427             }




 428         }
 429 
 430     }
 431 
 432     static final class ListN<E> extends AbstractImmutableList<E>
 433             implements Serializable {
 434 
 435         static final List<?> EMPTY_LIST = new ListN<>();
 436 
 437         @Stable
 438         private final E[] elements;
 439 
 440         @SafeVarargs
 441         ListN(E... input) {
 442             // copy and check manually to avoid TOCTOU
 443             @SuppressWarnings("unchecked")
 444             E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
 445             for (int i = 0; i < input.length; i++) {
 446                 tmp[i] = Objects.requireNonNull(input[i]);
 447             }
 448             elements = tmp;
 449         }
 450 
 451         @Override
 452         public boolean isEmpty() {
 453             return size() == 0;
 454         }
 455 
 456         @Override
 457         public int size() {
 458             return elements.length;
 459         }
 460 
 461         @Override
 462         public E get(int index) {
 463             return elements[index];
 464         }
 465 
 466         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 467             throw new InvalidObjectException("not serial proxy");
 468         }
 469 
 470         private Object writeReplace() {
 471             return new CollSer(CollSer.IMM_LIST, elements);
 472         }




 473     }
 474 
 475     // ---------- Set Implementations ----------
 476 
 477     @SuppressWarnings("unchecked")
 478     static <E> Set<E> emptySet() {
 479         return (Set<E>) SetN.EMPTY_SET;
 480     }
 481 
 482     static final class Set12<E> extends AbstractImmutableSet<E>
 483             implements Serializable {
 484 
 485         @Stable
 486         final E e0;
 487         @Stable
 488         final E e1;
 489 
 490         Set12(E e0) {
 491             this.e0 = Objects.requireNonNull(e0);
 492             this.e1 = null;
 493         }
 494 
 495         Set12(E e0, E e1) {
 496             if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
 497                 throw new IllegalArgumentException("duplicate element: " + e0);
 498             }
 499 
 500             if (SALT >= 0) {
 501                 this.e0 = e0;
 502                 this.e1 = e1;
 503             } else {
 504                 this.e0 = e1;
 505                 this.e1 = e0;
 506             }
 507         }
 508 
 509         @Override
 510         public int size() {
 511             return (e1 == null) ? 1 : 2;
 512         }
 513 
 514         @Override
 515         public boolean contains(Object o) {
 516             return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
 517         }
 518 
 519         @Override
 520         public int hashCode() {
 521             return e0.hashCode() + (e1 == null ? 0 : e1.hashCode());
 522         }
 523 
 524         @Override
 525         public Iterator<E> iterator() {
 526             return new Iterator<E>() {
 527                 private int idx = size();
 528 
 529                 @Override
 530                 public boolean hasNext() {
 531                     return idx > 0;
 532                 }
 533 
 534                 @Override
 535                 public E next() {
 536                     if (idx == 1) {
 537                         idx = 0;
 538                         return e0;
 539                     } else if (idx == 2) {
 540                         idx = 1;
 541                         return e1;
 542                     } else {
 543                         throw new NoSuchElementException();
 544                     }
 545                 }
 546             };
 547         }
 548 
 549         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 550             throw new InvalidObjectException("not serial proxy");
 551         }
 552 
 553         private Object writeReplace() {
 554             if (e1 == null) {
 555                 return new CollSer(CollSer.IMM_SET, e0);
 556             } else {
 557                 return new CollSer(CollSer.IMM_SET, e0, e1);
 558             }
 559         }
 560     }
 561 
 562     /**
 563      * An array-based Set implementation. The element array must be strictly
 564      * larger than the size (the number of contained elements) so that at
 565      * least one null is always present.
 566      * @param <E> the element type
 567      */
 568     static final class SetN<E> extends AbstractImmutableSet<E>
 569             implements Serializable {
 570 
 571         static final Set<?> EMPTY_SET = new SetN<>();
 572 
 573         @Stable
 574         final E[] elements;
 575         @Stable
 576         final int size;
 577 
 578         @SafeVarargs
 579         @SuppressWarnings("unchecked")
 580         SetN(E... input) {
 581             size = input.length; // implicit nullcheck of input
 582 
 583             elements = (E[])new Object[EXPAND_FACTOR * input.length];
 584             for (int i = 0; i < input.length; i++) {
 585                 E e = input[i];
 586                 int idx = probe(e); // implicit nullcheck of e
 587                 if (idx >= 0) {
 588                     throw new IllegalArgumentException("duplicate element: " + e);
 589                 } else {
 590                     elements[-(idx + 1)] = e;
 591                 }
 592             }
 593         }
 594 
 595         @Override
 596         public int size() {
 597             return size;
 598         }
 599 
 600         @Override
 601         public boolean contains(Object o) {
 602             Objects.requireNonNull(o);
 603             return size > 0 && probe(o) >= 0;
 604         }
 605 
 606         @Override
 607         public Iterator<E> iterator() {
 608             return new Iterator<E>() {
 609                 private int idx = 0;
 610 
 611                 @Override
 612                 public boolean hasNext() {
 613                     while (idx < elements.length) {
 614                         if (elements[idx] != null)
 615                             return true;
 616                         idx++;
 617                     }
 618                     return false;
 619                 }
 620 
 621                 @Override
 622                 public E next() {
 623                     if (! hasNext()) {


 658         }
 659 
 660         private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 661             throw new InvalidObjectException("not serial proxy");
 662         }
 663 
 664         private Object writeReplace() {
 665             Object[] array = new Object[size];
 666             int dest = 0;
 667             for (Object o : elements) {
 668                 if (o != null) {
 669                     array[dest++] = o;
 670                 }
 671             }
 672             return new CollSer(CollSer.IMM_SET, array);
 673         }
 674     }
 675 
 676     // ---------- Map Implementations ----------
 677 
 678     @SuppressWarnings("unchecked")
 679     static <K,V> Map<K,V> emptyMap() {
 680         return (Map<K,V>) MapN.EMPTY_MAP;
 681     }
 682 
 683     abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
 684         @Override public void clear() { throw uoe(); }
 685         @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 686         @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
 687         @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
 688         @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
 689         @Override public V put(K key, V value) { throw uoe(); }
 690         @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
 691         @Override public V putIfAbsent(K key, V value) { throw uoe(); }
 692         @Override public V remove(Object key) { throw uoe(); }
 693         @Override public boolean remove(Object key, Object value) { throw uoe(); }
 694         @Override public V replace(K key, V value) { throw uoe(); }
 695         @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
 696         @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
 697     }
 698 









































 699     static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
 700         @Stable
 701         private final K k0;
 702         @Stable
 703         private final V v0;
 704 
 705         Map1(K k0, V v0) {
 706             this.k0 = Objects.requireNonNull(k0);
 707             this.v0 = Objects.requireNonNull(v0);
 708         }
 709 
 710         @Override
 711         public Set<Map.Entry<K,V>> entrySet() {
 712             return Set.of(new KeyValueHolder<>(k0, v0));
 713         }
 714 
 715         @Override
 716         public boolean containsKey(Object o) {
 717             return o.equals(k0); // implicit nullcheck of o
 718         }


 729         private Object writeReplace() {
 730             return new CollSer(CollSer.IMM_MAP, k0, v0);
 731         }
 732 
 733         @Override
 734         public int hashCode() {
 735             return k0.hashCode() ^ v0.hashCode();
 736         }
 737     }
 738 
 739     /**
 740      * An array-based Map implementation. There is a single array "table" that
 741      * contains keys and values interleaved: table[0] is kA, table[1] is vA,
 742      * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
 743      * also be strictly larger than the size (the number of key-value pairs contained
 744      * in the map) so that at least one null key is always present.
 745      * @param <K> the key type
 746      * @param <V> the value type
 747      */
 748     static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
 749 
 750         static final Map<?,?> EMPTY_MAP = new MapN<>();
 751 
 752         @Stable
 753         final Object[] table; // pairs of key, value
 754 
 755         @Stable
 756         final int size; // number of pairs
 757 
 758         MapN(Object... input) {
 759             if ((input.length & 1) != 0) { // implicit nullcheck of input
 760                 throw new InternalError("length is odd");
 761             }
 762             size = input.length >> 1;
 763 
 764             int len = EXPAND_FACTOR * input.length;
 765             len = (len + 1) & ~1; // ensure table is even length
 766             table = new Object[len];
 767 
 768             for (int i = 0; i < input.length; i += 2) {
 769                 @SuppressWarnings("unchecked")
 770                     K k = Objects.requireNonNull((K)input[i]);
 771                 @SuppressWarnings("unchecked")
 772                     V v = Objects.requireNonNull((V)input[i+1]);
 773                 int idx = probe(k);
 774                 if (idx >= 0) {
 775                     throw new IllegalArgumentException("duplicate key: " + k);
 776                 } else {
 777                     int dest = -(idx + 1);
 778                     table[dest] = k;
 779                     table[dest+1] = v;
 780                 }
 781             }
 782         }
 783 
 784         @Override
 785         public boolean containsKey(Object o) {
 786             Objects.requireNonNull(o);
 787             return size > 0 && probe(o) >= 0;
 788         }
 789 
 790         @Override
 791         public boolean containsValue(Object o) {
 792             Objects.requireNonNull(o);
 793             for (int i = 1; i < table.length; i += 2) {
 794                 Object v = table[i];
 795                 if (v != null && o.equals(v)) {
 796                     return true;
 797                 }
 798             }
 799             return false;
 800         }
 801 
 802         @Override
 803         public int hashCode() {
 804             int hash = 0;
 805             for (int i = 0; i < table.length; i += 2) {
 806                 Object k = table[i];
 807                 if (k != null) {
 808                     hash += k.hashCode() ^ table[i + 1].hashCode();
 809                 }
 810             }
 811             return hash;
 812         }
 813 
 814         @Override
 815         @SuppressWarnings("unchecked")
 816         public V get(Object o) {
 817             if (size == 0) {
 818                 Objects.requireNonNull(o);
 819                 return null;
 820             }
 821             int i = probe(o);
 822             if (i >= 0) {
 823                 return (V)table[i+1];
 824             } else {
 825                 return null;
 826             }
 827         }
 828 
 829         @Override
 830         public int size() {
 831             return size;
 832         }
 833 
 834         @Override
 835         public Set<Map.Entry<K,V>> entrySet() {
 836             return new AbstractSet<>() {
 837                 @Override
 838                 public int size() {
 839                     return MapN.this.size;
 840                 }
 841 
 842                 @Override
 843                 public Iterator<Map.Entry<K,V>> iterator() {
 844                     return new Iterator<>() {
 845                         int idx = 0;
 846 
 847                         @Override
 848                         public boolean hasNext() {
 849                             while (idx < table.length) {
 850                                 if (table[idx] != null)
 851                                     return true;
 852                                 idx += 2;
 853                             }
 854                             return false;
 855                         }
 856 
 857                         @Override
 858                         public Map.Entry<K,V> next() {
 859                             if (hasNext()) {
 860                                 @SuppressWarnings("unchecked")
 861                                 Map.Entry<K,V> e =
 862                                     new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
 863                                 idx += 2;
 864                                 return e;


1031      * @throws InvalidObjectException if the tag value is illegal or if an exception
1032      *         is thrown during creation of the collection
1033      * @throws ObjectStreamException if another serialization error has occurred
1034      * @since 9
1035      */
1036     private Object readResolve() throws ObjectStreamException {
1037         try {
1038             if (array == null) {
1039                 throw new InvalidObjectException("null array");
1040             }
1041 
1042             // use low order 8 bits to indicate "kind"
1043             // ignore high order 24 bits
1044             switch (tag & 0xff) {
1045                 case IMM_LIST:
1046                     return List.of(array);
1047                 case IMM_SET:
1048                     return Set.of(array);
1049                 case IMM_MAP:
1050                     if (array.length == 0) {
1051                         return ImmutableCollections.emptyMap();
1052                     } else if (array.length == 2) {
1053                         return new ImmutableCollections.Map1<>(array[0], array[1]);
1054                     } else {
1055                         return new ImmutableCollections.MapN<>(array);
1056                     }
1057                 default:
1058                     throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
1059             }
1060         } catch (NullPointerException|IllegalArgumentException ex) {
1061             InvalidObjectException ioe = new InvalidObjectException("invalid object");
1062             ioe.initCause(ex);
1063             throw ioe;
1064         }
1065     }
1066 }
< prev index next >