1 /* 2 * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 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.lang.reflect.Array; 35 import java.util.function.BiFunction; 36 import java.util.function.Function; 37 import java.util.function.Predicate; 38 import java.util.function.UnaryOperator; 39 import jdk.internal.access.JavaUtilCollectionAccess; 40 import jdk.internal.access.SharedSecrets; 41 import jdk.internal.vm.annotation.Stable; 42 43 /** 44 * Container class for immutable collections. Not part of the public API. 45 * Mainly for namespace management and shared infrastructure. 46 * 47 * Serial warnings are suppressed throughout because all implementation 48 * classes use a serial proxy and thus have no need to declare serialVersionUID. 49 */ 50 @SuppressWarnings("serial") 51 class ImmutableCollections { 52 /** 53 * A "salt" value used for randomizing iteration order. This is initialized once 54 * and stays constant for the lifetime of the JVM. It need not be truly random, but 55 * it needs to vary sufficiently from one run to the next so that iteration order 56 * will vary between JVM runs. 57 */ 58 private static final long SALT32L; 59 60 /** 61 * For set and map iteration, we will iterate in "reverse" stochastically, 62 * decided at bootstrap time. 63 */ 64 private static final boolean REVERSE; 65 static { 66 // to generate a reasonably random and well-mixed SALT, use an arbitrary 67 // value (a slice of pi), multiply with a random seed, then pick 68 // the mid 32-bits from the product. By picking a SALT value in the 69 // [0 ... 0xFFFF_FFFFL == 2^32-1] range, we ensure that for any positive 70 // int N, (SALT32L * N) >> 32 is a number in the [0 ... N-1] range. This 71 // property will be used to avoid more expensive modulo-based 72 // calculations. 73 long color = 0x243F_6A88_85A3_08D3L; // slice of pi 74 75 // BEGIN Android-changed: set seed directly, as CDS is not available. 76 // When running with -Xshare:dump, the VM will supply a "random" seed that's 77 // derived from the JVM build/version, so can we generate the exact same 78 // CDS archive for the same JDK build. This makes it possible to verify the 79 // consistency of the JDK build. 80 // long seed = CDS.getRandomSeedForDumping(); 81 // if (seed == 0) { 82 // seed = System.nanoTime(); 83 // } 84 long seed = System.nanoTime(); 85 // END Android-changed: set seed directly, as CDS is not available. 86 SALT32L = (int)((color * seed) >> 16) & 0xFFFF_FFFFL; 87 // use the lowest bit to determine if we should reverse iteration 88 REVERSE = (SALT32L & 1) == 0; 89 } 90 91 // BEGIN Android-changed: always initialize empty collections. 92 /* 93 * Constants following this might be initialized from the CDS archive via 94 * this array. 95 * 96 // private static Object[] archivedObjects; 97 */ 98 99 private static final Object EMPTY = new Object(); 100 static final ListN<?> EMPTY_LIST = new ListN<>(new Object[0], false); 101 static final ListN<?> EMPTY_LIST_NULLS = new ListN<>(new Object[0], true); 102 static final SetN<?> EMPTY_SET = new SetN<>(); 103 static final MapN<?,?> EMPTY_MAP = new MapN<>(); 104 105 /* 106 static { 107 CDS.initializeFromArchive(ImmutableCollections.class); 108 if (archivedObjects == null) { 109 EMPTY = new Object(); 110 EMPTY_LIST = new ListN<>(new Object[0], false); 111 EMPTY_LIST_NULLS = new ListN<>(new Object[0], true); 112 EMPTY_SET = new SetN<>(); 113 EMPTY_MAP = new MapN<>(); 114 archivedObjects = 115 new Object[] { EMPTY, EMPTY_LIST, EMPTY_LIST_NULLS, EMPTY_SET, EMPTY_MAP }; 116 } else { 117 EMPTY = archivedObjects[0]; 118 EMPTY_LIST = (ListN)archivedObjects[1]; 119 EMPTY_LIST_NULLS = (ListN)archivedObjects[2]; 120 EMPTY_SET = (SetN)archivedObjects[3]; 121 EMPTY_MAP = (MapN)archivedObjects[4]; 122 } 123 } 124 */ 125 // END Android-changed: always initialize empty collections. 126 127 static class Access { 128 static { SharedSecrets.setJavaUtilCollectionAccess(new JavaUtilCollectionAccess() { public <E> List<E> listFromTrustedArray(Object[] array) { return ImmutableCollections.listFromTrustedArray(array); } public <E> List<E> listFromTrustedArrayNullsAllowed(Object[] array) { return ImmutableCollections.listFromTrustedArrayNullsAllowed(array); } })129 SharedSecrets.setJavaUtilCollectionAccess(new JavaUtilCollectionAccess() { 130 public <E> List<E> listFromTrustedArray(Object[] array) { 131 return ImmutableCollections.listFromTrustedArray(array); 132 } 133 public <E> List<E> listFromTrustedArrayNullsAllowed(Object[] array) { 134 return ImmutableCollections.listFromTrustedArrayNullsAllowed(array); 135 } 136 }); 137 } 138 } 139 140 /** No instances. */ ImmutableCollections()141 private ImmutableCollections() { } 142 143 /** 144 * The reciprocal of load factor. Given a number of elements 145 * to store, multiply by this factor to get the table size. 146 */ 147 static final int EXPAND_FACTOR = 2; 148 uoe()149 static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); } 150 151 @jdk.internal.ValueBased 152 abstract static class AbstractImmutableCollection<E> extends AbstractCollection<E> { 153 // all mutating methods throw UnsupportedOperationException add(E e)154 @Override public boolean add(E e) { throw uoe(); } addAll(Collection<? extends E> c)155 @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); } clear()156 @Override public void clear() { throw uoe(); } remove(Object o)157 @Override public boolean remove(Object o) { throw uoe(); } removeAll(Collection<?> c)158 @Override public boolean removeAll(Collection<?> c) { throw uoe(); } removeIf(Predicate<? super E> filter)159 @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); } retainAll(Collection<?> c)160 @Override public boolean retainAll(Collection<?> c) { throw uoe(); } 161 } 162 163 // ---------- List Static Factory Methods ---------- 164 165 /** 166 * Copies a collection into a new List, unless the arg is already a safe, 167 * null-prohibiting unmodifiable list, in which case the arg itself is returned. 168 * Null argument or null elements in the argument will result in NPE. 169 * 170 * @param <E> the List's element type 171 * @param input the input array 172 * @return the new list 173 */ 174 @SuppressWarnings("unchecked") listCopy(Collection<? extends E> coll)175 static <E> List<E> listCopy(Collection<? extends E> coll) { 176 if (coll instanceof List12 || (coll instanceof ListN<?> c && !c.allowNulls)) { 177 return (List<E>)coll; 178 } else if (coll.isEmpty()) { // implicit nullcheck of coll 179 return List.of(); 180 } else { 181 return (List<E>)List.of(coll.toArray()); 182 } 183 } 184 185 /** 186 * Creates a new List from an untrusted array, creating a new array for internal 187 * storage, and checking for and rejecting null elements. 188 * 189 * @param <E> the List's element type 190 * @param input the input array 191 * @return the new list 192 */ 193 @SafeVarargs listFromArray(E... input)194 static <E> List<E> listFromArray(E... input) { 195 // copy and check manually to avoid TOCTOU 196 @SuppressWarnings("unchecked") 197 E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input 198 for (int i = 0; i < input.length; i++) { 199 tmp[i] = Objects.requireNonNull(input[i]); 200 } 201 return new ListN<>(tmp, false); 202 } 203 204 /** 205 * Creates a new List from a trusted array, checking for and rejecting null 206 * elements. 207 * 208 * <p>A trusted array has no references retained by the caller. It can therefore be 209 * safely reused as the List's internal storage, avoiding a defensive copy. The array's 210 * class must be Object[].class. This method is declared with a parameter type of 211 * Object... instead of E... so that a varargs call doesn't accidentally create an array 212 * of some class other than Object[].class. 213 * 214 * @param <E> the List's element type 215 * @param input the input array 216 * @return the new list 217 */ 218 @SuppressWarnings("unchecked") listFromTrustedArray(Object... input)219 static <E> List<E> listFromTrustedArray(Object... input) { 220 assert input.getClass() == Object[].class; 221 for (Object o : input) { // implicit null check of 'input' array 222 Objects.requireNonNull(o); 223 } 224 225 return switch (input.length) { 226 case 0 -> (List<E>) ImmutableCollections.EMPTY_LIST; 227 case 1 -> (List<E>) new List12<>(input[0]); 228 case 2 -> (List<E>) new List12<>(input[0], input[1]); 229 default -> (List<E>) new ListN<>(input, false); 230 }; 231 } 232 233 /** 234 * Creates a new List from a trusted array, allowing null elements. 235 * 236 * <p>A trusted array has no references retained by the caller. It can therefore be 237 * safely reused as the List's internal storage, avoiding a defensive copy. The array's 238 * class must be Object[].class. This method is declared with a parameter type of 239 * Object... instead of E... so that a varargs call doesn't accidentally create an array 240 * of some class other than Object[].class. 241 * 242 * <p>Avoids creating a List12 instance, as it cannot accommodate null elements. 243 * 244 * @param <E> the List's element type 245 * @param input the input array 246 * @return the new list 247 */ 248 @SuppressWarnings("unchecked") listFromTrustedArrayNullsAllowed(Object... input)249 static <E> List<E> listFromTrustedArrayNullsAllowed(Object... input) { 250 assert input.getClass() == Object[].class; 251 if (input.length == 0) { 252 return (List<E>) EMPTY_LIST_NULLS; 253 } else { 254 return new ListN<>((E[])input, true); 255 } 256 } 257 258 // ---------- List Implementations ---------- 259 260 @jdk.internal.ValueBased 261 abstract static class AbstractImmutableList<E> extends AbstractImmutableCollection<E> 262 implements List<E>, RandomAccess { 263 264 // all mutating methods throw UnsupportedOperationException add(int index, E element)265 @Override public void add(int index, E element) { throw uoe(); } addAll(int index, Collection<? extends E> c)266 @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); } remove(int index)267 @Override public E remove(int index) { throw uoe(); } replaceAll(UnaryOperator<E> operator)268 @Override public void replaceAll(UnaryOperator<E> operator) { throw uoe(); } set(int index, E element)269 @Override public E set(int index, E element) { throw uoe(); } sort(Comparator<? super E> c)270 @Override public void sort(Comparator<? super E> c) { throw uoe(); } 271 272 @Override subList(int fromIndex, int toIndex)273 public List<E> subList(int fromIndex, int toIndex) { 274 int size = size(); 275 subListRangeCheck(fromIndex, toIndex, size); 276 return SubList.fromList(this, fromIndex, toIndex); 277 } 278 subListRangeCheck(int fromIndex, int toIndex, int size)279 static void subListRangeCheck(int fromIndex, int toIndex, int size) { 280 if (fromIndex < 0) 281 throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); 282 if (toIndex > size) 283 throw new IndexOutOfBoundsException("toIndex = " + toIndex); 284 if (fromIndex > toIndex) 285 throw new IllegalArgumentException("fromIndex(" + fromIndex + 286 ") > toIndex(" + toIndex + ")"); 287 } 288 289 @Override iterator()290 public Iterator<E> iterator() { 291 return new ListItr<E>(this, size()); 292 } 293 294 @Override listIterator()295 public ListIterator<E> listIterator() { 296 return listIterator(0); 297 } 298 299 @Override listIterator(final int index)300 public ListIterator<E> listIterator(final int index) { 301 int size = size(); 302 if (index < 0 || index > size) { 303 throw outOfBounds(index); 304 } 305 return new ListItr<E>(this, size, index); 306 } 307 308 @Override equals(Object o)309 public boolean equals(Object o) { 310 if (o == this) { 311 return true; 312 } 313 314 if (!(o instanceof List)) { 315 return false; 316 } 317 318 Iterator<?> oit = ((List<?>) o).iterator(); 319 for (int i = 0, s = size(); i < s; i++) { 320 if (!oit.hasNext() || !Objects.equals(get(i), oit.next())) { 321 return false; 322 } 323 } 324 return !oit.hasNext(); 325 } 326 327 @Override hashCode()328 public int hashCode() { 329 int hash = 1; 330 for (int i = 0, s = size(); i < s; i++) { 331 hash = 31 * hash + Objects.hashCode(get(i)); 332 } 333 return hash; 334 } 335 336 @Override contains(Object o)337 public boolean contains(Object o) { 338 return indexOf(o) >= 0; 339 } 340 341 @Override reversed()342 public List<E> reversed() { 343 return ReverseOrderListView.of(this, false); 344 } 345 outOfBounds(int index)346 IndexOutOfBoundsException outOfBounds(int index) { 347 return new IndexOutOfBoundsException("Index: " + index + " Size: " + size()); 348 } 349 } 350 351 static final class ListItr<E> implements ListIterator<E> { 352 353 @Stable 354 private final List<E> list; 355 356 @Stable 357 private final int size; 358 359 @Stable 360 private final boolean isListIterator; 361 362 private int cursor; 363 ListItr(List<E> list, int size)364 ListItr(List<E> list, int size) { 365 this.list = list; 366 this.size = size; 367 this.cursor = 0; 368 isListIterator = false; 369 } 370 ListItr(List<E> list, int size, int index)371 ListItr(List<E> list, int size, int index) { 372 this.list = list; 373 this.size = size; 374 this.cursor = index; 375 isListIterator = true; 376 } 377 hasNext()378 public boolean hasNext() { 379 return cursor != size; 380 } 381 next()382 public E next() { 383 try { 384 int i = cursor; 385 E next = list.get(i); 386 cursor = i + 1; 387 return next; 388 } catch (IndexOutOfBoundsException e) { 389 throw new NoSuchElementException(); 390 } 391 } 392 remove()393 public void remove() { 394 throw uoe(); 395 } 396 hasPrevious()397 public boolean hasPrevious() { 398 if (!isListIterator) { 399 throw uoe(); 400 } 401 return cursor != 0; 402 } 403 previous()404 public E previous() { 405 if (!isListIterator) { 406 throw uoe(); 407 } 408 try { 409 int i = cursor - 1; 410 E previous = list.get(i); 411 cursor = i; 412 return previous; 413 } catch (IndexOutOfBoundsException e) { 414 throw new NoSuchElementException(); 415 } 416 } 417 nextIndex()418 public int nextIndex() { 419 if (!isListIterator) { 420 throw uoe(); 421 } 422 return cursor; 423 } 424 previousIndex()425 public int previousIndex() { 426 if (!isListIterator) { 427 throw uoe(); 428 } 429 return cursor - 1; 430 } 431 set(E e)432 public void set(E e) { 433 throw uoe(); 434 } 435 add(E e)436 public void add(E e) { 437 throw uoe(); 438 } 439 } 440 441 static final class SubList<E> extends AbstractImmutableList<E> 442 implements RandomAccess { 443 444 @Stable 445 private final AbstractImmutableList<E> root; 446 447 @Stable 448 private final int offset; 449 450 @Stable 451 private final int size; 452 SubList(AbstractImmutableList<E> root, int offset, int size)453 private SubList(AbstractImmutableList<E> root, int offset, int size) { 454 assert root instanceof List12 || root instanceof ListN; 455 this.root = root; 456 this.offset = offset; 457 this.size = size; 458 } 459 460 /** 461 * Constructs a sublist of another SubList. 462 */ fromSubList(SubList<E> parent, int fromIndex, int toIndex)463 static <E> SubList<E> fromSubList(SubList<E> parent, int fromIndex, int toIndex) { 464 return new SubList<>(parent.root, parent.offset + fromIndex, toIndex - fromIndex); 465 } 466 467 /** 468 * Constructs a sublist of an arbitrary AbstractImmutableList, which is 469 * not a SubList itself. 470 */ fromList(AbstractImmutableList<E> list, int fromIndex, int toIndex)471 static <E> SubList<E> fromList(AbstractImmutableList<E> list, int fromIndex, int toIndex) { 472 return new SubList<>(list, fromIndex, toIndex - fromIndex); 473 } 474 get(int index)475 public E get(int index) { 476 Objects.checkIndex(index, size); 477 return root.get(offset + index); 478 } 479 size()480 public int size() { 481 return size; 482 } 483 iterator()484 public Iterator<E> iterator() { 485 return new ListItr<>(this, size()); 486 } 487 listIterator(int index)488 public ListIterator<E> listIterator(int index) { 489 rangeCheck(index); 490 return new ListItr<>(this, size(), index); 491 } 492 subList(int fromIndex, int toIndex)493 public List<E> subList(int fromIndex, int toIndex) { 494 subListRangeCheck(fromIndex, toIndex, size); 495 return SubList.fromSubList(this, fromIndex, toIndex); 496 } 497 rangeCheck(int index)498 private void rangeCheck(int index) { 499 if (index < 0 || index > size) { 500 throw outOfBounds(index); 501 } 502 } 503 allowNulls()504 private boolean allowNulls() { 505 return root instanceof ListN && ((ListN<?>)root).allowNulls; 506 } 507 508 @Override indexOf(Object o)509 public int indexOf(Object o) { 510 if (!allowNulls() && o == null) { 511 throw new NullPointerException(); 512 } 513 for (int i = 0, s = size(); i < s; i++) { 514 if (Objects.equals(o, get(i))) { 515 return i; 516 } 517 } 518 return -1; 519 } 520 521 @Override lastIndexOf(Object o)522 public int lastIndexOf(Object o) { 523 if (!allowNulls() && o == null) { 524 throw new NullPointerException(); 525 } 526 for (int i = size() - 1; i >= 0; i--) { 527 if (Objects.equals(o, get(i))) { 528 return i; 529 } 530 } 531 return -1; 532 } 533 534 @Override toArray()535 public Object[] toArray() { 536 Object[] array = new Object[size]; 537 for (int i = 0; i < size; i++) { 538 array[i] = get(i); 539 } 540 return array; 541 } 542 543 @Override 544 @SuppressWarnings("unchecked") toArray(T[] a)545 public <T> T[] toArray(T[] a) { 546 T[] array = a.length >= size ? a : 547 (T[])java.lang.reflect.Array 548 .newInstance(a.getClass().getComponentType(), size); 549 for (int i = 0; i < size; i++) { 550 array[i] = (T)get(i); 551 } 552 if (array.length > size) { 553 array[size] = null; // null-terminate 554 } 555 return array; 556 } 557 } 558 559 @jdk.internal.ValueBased 560 static final class List12<E> extends AbstractImmutableList<E> 561 implements Serializable { 562 563 @Stable 564 private final E e0; 565 566 @Stable 567 private final Object e1; 568 List12(E e0)569 List12(E e0) { 570 this.e0 = Objects.requireNonNull(e0); 571 // Use EMPTY as a sentinel for an unused element: not using null 572 // enables constant folding optimizations over single-element lists 573 this.e1 = EMPTY; 574 } 575 List12(E e0, E e1)576 List12(E e0, E e1) { 577 this.e0 = Objects.requireNonNull(e0); 578 this.e1 = Objects.requireNonNull(e1); 579 } 580 581 @Override size()582 public int size() { 583 return e1 != EMPTY ? 2 : 1; 584 } 585 586 @Override isEmpty()587 public boolean isEmpty() { 588 return false; 589 } 590 591 @Override 592 @SuppressWarnings("unchecked") get(int index)593 public E get(int index) { 594 if (index == 0) { 595 return e0; 596 } else if (index == 1 && e1 != EMPTY) { 597 return (E)e1; 598 } 599 throw outOfBounds(index); 600 } 601 602 @Override indexOf(Object o)603 public int indexOf(Object o) { 604 Objects.requireNonNull(o); 605 if (o.equals(e0)) { 606 return 0; 607 } else if (e1 != EMPTY && o.equals(e1)) { 608 return 1; 609 } else { 610 return -1; 611 } 612 } 613 614 @Override lastIndexOf(Object o)615 public int lastIndexOf(Object o) { 616 Objects.requireNonNull(o); 617 if (e1 != EMPTY && o.equals(e1)) { 618 return 1; 619 } else if (o.equals(e0)) { 620 return 0; 621 } else { 622 return -1; 623 } 624 } 625 626 @java.io.Serial readObject(ObjectInputStream in)627 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 628 throw new InvalidObjectException("not serial proxy"); 629 } 630 631 @java.io.Serial writeReplace()632 private Object writeReplace() { 633 if (e1 == EMPTY) { 634 return new CollSer(CollSer.IMM_LIST, e0); 635 } else { 636 return new CollSer(CollSer.IMM_LIST, e0, e1); 637 } 638 } 639 640 @Override toArray()641 public Object[] toArray() { 642 if (e1 == EMPTY) { 643 return new Object[] { e0 }; 644 } else { 645 return new Object[] { e0, e1 }; 646 } 647 } 648 649 @Override 650 @SuppressWarnings("unchecked") toArray(T[] a)651 public <T> T[] toArray(T[] a) { 652 int size = size(); 653 T[] array = a.length >= size ? a : 654 (T[])Array.newInstance(a.getClass().getComponentType(), size); 655 array[0] = (T)e0; 656 if (size == 2) { 657 array[1] = (T)e1; 658 } 659 if (array.length > size) { 660 array[size] = null; // null-terminate 661 } 662 return array; 663 } 664 } 665 666 @jdk.internal.ValueBased 667 static final class ListN<E> extends AbstractImmutableList<E> 668 implements Serializable { 669 670 @Stable 671 private final E[] elements; 672 673 @Stable 674 private final boolean allowNulls; 675 676 // caller must ensure that elements has no nulls if allowNulls is false ListN(E[] elements, boolean allowNulls)677 private ListN(E[] elements, boolean allowNulls) { 678 this.elements = elements; 679 this.allowNulls = allowNulls; 680 } 681 682 @Override isEmpty()683 public boolean isEmpty() { 684 return elements.length == 0; 685 } 686 687 @Override size()688 public int size() { 689 return elements.length; 690 } 691 692 @Override get(int index)693 public E get(int index) { 694 return elements[index]; 695 } 696 697 @java.io.Serial readObject(ObjectInputStream in)698 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 699 throw new InvalidObjectException("not serial proxy"); 700 } 701 702 @java.io.Serial writeReplace()703 private Object writeReplace() { 704 return new CollSer(allowNulls ? CollSer.IMM_LIST_NULLS : CollSer.IMM_LIST, elements); 705 } 706 707 @Override toArray()708 public Object[] toArray() { 709 return Arrays.copyOf(elements, elements.length); 710 } 711 712 @Override 713 @SuppressWarnings("unchecked") toArray(T[] a)714 public <T> T[] toArray(T[] a) { 715 int size = elements.length; 716 if (a.length < size) { 717 // Make a new array of a's runtime type, but my contents: 718 return (T[]) Arrays.copyOf(elements, size, a.getClass()); 719 } 720 System.arraycopy(elements, 0, a, 0, size); 721 if (a.length > size) { 722 a[size] = null; // null-terminate 723 } 724 return a; 725 } 726 727 @Override indexOf(Object o)728 public int indexOf(Object o) { 729 if (!allowNulls && o == null) { 730 throw new NullPointerException(); 731 } 732 Object[] es = elements; 733 for (int i = 0; i < es.length; i++) { 734 if (Objects.equals(o, es[i])) { 735 return i; 736 } 737 } 738 return -1; 739 } 740 741 @Override lastIndexOf(Object o)742 public int lastIndexOf(Object o) { 743 if (!allowNulls && o == null) { 744 throw new NullPointerException(); 745 } 746 Object[] es = elements; 747 for (int i = es.length - 1; i >= 0; i--) { 748 if (Objects.equals(o, es[i])) { 749 return i; 750 } 751 } 752 return -1; 753 } 754 } 755 756 // ---------- Set Implementations ---------- 757 758 @jdk.internal.ValueBased 759 abstract static class AbstractImmutableSet<E> extends AbstractImmutableCollection<E> 760 implements Set<E> { 761 762 @Override equals(Object o)763 public boolean equals(Object o) { 764 if (o == this) { 765 return true; 766 } else if (!(o instanceof Set)) { 767 return false; 768 } 769 770 Collection<?> c = (Collection<?>) o; 771 if (c.size() != size()) { 772 return false; 773 } 774 for (Object e : c) { 775 if (e == null || !contains(e)) { 776 return false; 777 } 778 } 779 return true; 780 } 781 782 @Override hashCode()783 public abstract int hashCode(); 784 } 785 786 @jdk.internal.ValueBased 787 static final class Set12<E> extends AbstractImmutableSet<E> 788 implements Serializable { 789 790 @Stable 791 private final E e0; 792 793 @Stable 794 private final Object e1; 795 Set12(E e0)796 Set12(E e0) { 797 this.e0 = Objects.requireNonNull(e0); 798 // Use EMPTY as a sentinel for an unused element: not using null 799 // enable constant folding optimizations over single-element sets 800 this.e1 = EMPTY; 801 } 802 Set12(E e0, E e1)803 Set12(E e0, E e1) { 804 if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0 805 throw new IllegalArgumentException("duplicate element: " + e0); 806 } 807 808 this.e0 = e0; 809 this.e1 = e1; 810 } 811 812 @Override size()813 public int size() { 814 return (e1 == EMPTY) ? 1 : 2; 815 } 816 817 @Override isEmpty()818 public boolean isEmpty() { 819 return false; 820 } 821 822 @Override contains(Object o)823 public boolean contains(Object o) { 824 return o.equals(e0) || e1.equals(o); // implicit nullcheck of o 825 } 826 827 @Override hashCode()828 public int hashCode() { 829 return e0.hashCode() + (e1 == EMPTY ? 0 : e1.hashCode()); 830 } 831 832 @Override iterator()833 public Iterator<E> iterator() { 834 return new Iterator<>() { 835 private int idx = (e1 == EMPTY) ? 1 : 2; 836 837 @Override 838 public boolean hasNext() { 839 return idx > 0; 840 } 841 842 @Override 843 @SuppressWarnings("unchecked") 844 public E next() { 845 if (idx == 1) { 846 idx = 0; 847 return (REVERSE || e1 == EMPTY) ? e0 : (E)e1; 848 } else if (idx == 2) { 849 idx = 1; 850 return REVERSE ? (E)e1 : e0; 851 } else { 852 throw new NoSuchElementException(); 853 } 854 } 855 }; 856 } 857 858 @java.io.Serial readObject(ObjectInputStream in)859 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 860 throw new InvalidObjectException("not serial proxy"); 861 } 862 863 @java.io.Serial writeReplace()864 private Object writeReplace() { 865 if (e1 == EMPTY) { 866 return new CollSer(CollSer.IMM_SET, e0); 867 } else { 868 return new CollSer(CollSer.IMM_SET, e0, e1); 869 } 870 } 871 872 @Override toArray()873 public Object[] toArray() { 874 if (e1 == EMPTY) { 875 return new Object[] { e0 }; 876 } else if (REVERSE) { 877 return new Object[] { e1, e0 }; 878 } else { 879 return new Object[] { e0, e1 }; 880 } 881 } 882 883 @Override 884 @SuppressWarnings("unchecked") toArray(T[] a)885 public <T> T[] toArray(T[] a) { 886 int size = size(); 887 T[] array = a.length >= size ? a : 888 (T[])Array.newInstance(a.getClass().getComponentType(), size); 889 if (size == 1) { 890 array[0] = (T)e0; 891 } else if (REVERSE) { 892 array[0] = (T)e1; 893 array[1] = (T)e0; 894 } else { 895 array[0] = (T)e0; 896 array[1] = (T)e1; 897 } 898 if (array.length > size) { 899 array[size] = null; // null-terminate 900 } 901 return array; 902 } 903 } 904 905 906 /** 907 * An array-based Set implementation. The element array must be strictly 908 * larger than the size (the number of contained elements) so that at 909 * least one null is always present. 910 * @param <E> the element type 911 */ 912 @jdk.internal.ValueBased 913 static final class SetN<E> extends AbstractImmutableSet<E> 914 implements Serializable { 915 916 @Stable 917 final E[] elements; 918 919 @Stable 920 final int size; 921 922 @SafeVarargs 923 @SuppressWarnings("unchecked") 924 SetN(E... input) { 925 size = input.length; // implicit nullcheck of input 926 927 elements = (E[])new Object[EXPAND_FACTOR * input.length]; 928 for (int i = 0; i < input.length; i++) { 929 E e = input[i]; 930 int idx = probe(e); // implicit nullcheck of e 931 if (idx >= 0) { 932 throw new IllegalArgumentException("duplicate element: " + e); 933 } else { 934 elements[-(idx + 1)] = e; 935 } 936 } 937 } 938 939 @Override 940 public int size() { 941 return size; 942 } 943 944 @Override 945 public boolean isEmpty() { 946 return size == 0; 947 } 948 949 @Override 950 public boolean contains(Object o) { 951 Objects.requireNonNull(o); 952 return size > 0 && probe(o) >= 0; 953 } 954 955 private final class SetNIterator implements Iterator<E> { 956 957 private int remaining; 958 959 private int idx; 960 961 SetNIterator() { 962 remaining = size; 963 // pick a starting index in the [0 .. element.length-1] range 964 // randomly based on SALT32L 965 idx = (int) ((SALT32L * elements.length) >>> 32); 966 } 967 968 @Override 969 public boolean hasNext() { 970 return remaining > 0; 971 } 972 973 @Override 974 public E next() { 975 if (remaining > 0) { 976 E element; 977 int idx = this.idx; 978 int len = elements.length; 979 // step to the next element; skip null elements 980 do { 981 if (REVERSE) { 982 if (++idx >= len) { 983 idx = 0; 984 } 985 } else { 986 if (--idx < 0) { 987 idx = len - 1; 988 } 989 } 990 } while ((element = elements[idx]) == null); 991 this.idx = idx; 992 remaining--; 993 return element; 994 } else { 995 throw new NoSuchElementException(); 996 } 997 } 998 } 999 1000 @Override 1001 public Iterator<E> iterator() { 1002 return new SetNIterator(); 1003 } 1004 1005 @Override 1006 public int hashCode() { 1007 int h = 0; 1008 for (E e : elements) { 1009 if (e != null) { 1010 h += e.hashCode(); 1011 } 1012 } 1013 return h; 1014 } 1015 1016 // returns index at which element is present; or if absent, 1017 // (-i - 1) where i is location where element should be inserted. 1018 // Callers are relying on this method to perform an implicit nullcheck 1019 // of pe 1020 private int probe(Object pe) { 1021 int idx = Math.floorMod(pe.hashCode(), elements.length); 1022 while (true) { 1023 E ee = elements[idx]; 1024 if (ee == null) { 1025 return -idx - 1; 1026 } else if (pe.equals(ee)) { 1027 return idx; 1028 } else if (++idx == elements.length) { 1029 idx = 0; 1030 } 1031 } 1032 } 1033 1034 @java.io.Serial 1035 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 1036 throw new InvalidObjectException("not serial proxy"); 1037 } 1038 1039 @java.io.Serial 1040 private Object writeReplace() { 1041 Object[] array = new Object[size]; 1042 int dest = 0; 1043 for (Object o : elements) { 1044 if (o != null) { 1045 array[dest++] = o; 1046 } 1047 } 1048 return new CollSer(CollSer.IMM_SET, array); 1049 } 1050 1051 @Override 1052 public Object[] toArray() { 1053 Object[] array = new Object[size]; 1054 Iterator<E> it = iterator(); 1055 for (int i = 0; i < size; i++) { 1056 array[i] = it.next(); 1057 } 1058 return array; 1059 } 1060 1061 @Override 1062 @SuppressWarnings("unchecked") 1063 public <T> T[] toArray(T[] a) { 1064 T[] array = a.length >= size ? a : 1065 (T[])Array.newInstance(a.getClass().getComponentType(), size); 1066 Iterator<E> it = iterator(); 1067 for (int i = 0; i < size; i++) { 1068 array[i] = (T)it.next(); 1069 } 1070 if (array.length > size) { 1071 array[size] = null; // null-terminate 1072 } 1073 return array; 1074 } 1075 } 1076 1077 // ---------- Map Implementations ---------- 1078 1079 // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap 1080 abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable { 1081 @Override public void clear() { throw uoe(); } 1082 @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); } 1083 @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); } 1084 @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); } 1085 @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); } 1086 @Override public V put(K key, V value) { throw uoe(); } 1087 @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); } 1088 @Override public V putIfAbsent(K key, V value) { throw uoe(); } 1089 @Override public V remove(Object key) { throw uoe(); } 1090 @Override public boolean remove(Object key, Object value) { throw uoe(); } 1091 @Override public V replace(K key, V value) { throw uoe(); } 1092 @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); } 1093 @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); } 1094 1095 /** 1096 * @implNote {@code null} values are disallowed in these immutable maps, 1097 * so we can improve upon the default implementation since a 1098 * {@code null} return from {@code get(key)} always means the default 1099 * value should be returned. 1100 */ 1101 @Override 1102 public V getOrDefault(Object key, V defaultValue) { 1103 V v; 1104 return ((v = get(key)) != null) 1105 ? v 1106 : defaultValue; 1107 } 1108 } 1109 1110 // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap 1111 static final class Map1<K,V> extends AbstractImmutableMap<K,V> { 1112 @Stable 1113 private final K k0; 1114 @Stable 1115 private final V v0; 1116 1117 Map1(K k0, V v0) { 1118 this.k0 = Objects.requireNonNull(k0); 1119 this.v0 = Objects.requireNonNull(v0); 1120 } 1121 1122 @Override 1123 public Set<Map.Entry<K,V>> entrySet() { 1124 return Set.of(new KeyValueHolder<>(k0, v0)); 1125 } 1126 1127 @Override 1128 public V get(Object o) { 1129 return o.equals(k0) ? v0 : null; // implicit nullcheck of o 1130 } 1131 1132 @Override 1133 public boolean containsKey(Object o) { 1134 return o.equals(k0); // implicit nullcheck of o 1135 } 1136 1137 @Override 1138 public boolean containsValue(Object o) { 1139 return o.equals(v0); // implicit nullcheck of o 1140 } 1141 1142 @Override 1143 public int size() { 1144 return 1; 1145 } 1146 1147 @Override 1148 public boolean isEmpty() { 1149 return false; 1150 } 1151 1152 @java.io.Serial 1153 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 1154 throw new InvalidObjectException("not serial proxy"); 1155 } 1156 1157 @java.io.Serial 1158 private Object writeReplace() { 1159 return new CollSer(CollSer.IMM_MAP, k0, v0); 1160 } 1161 1162 @Override 1163 public int hashCode() { 1164 return k0.hashCode() ^ v0.hashCode(); 1165 } 1166 } 1167 1168 /** 1169 * An array-based Map implementation. There is a single array "table" that 1170 * contains keys and values interleaved: table[0] is kA, table[1] is vA, 1171 * table[2] is kB, table[3] is vB, etc. The table size must be even. It must 1172 * also be strictly larger than the size (the number of key-value pairs contained 1173 * in the map) so that at least one null key is always present. 1174 * @param <K> the key type 1175 * @param <V> the value type 1176 */ 1177 // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap 1178 static final class MapN<K,V> extends AbstractImmutableMap<K,V> { 1179 1180 @Stable 1181 final Object[] table; // pairs of key, value 1182 1183 @Stable 1184 final int size; // number of pairs 1185 1186 MapN(Object... input) { 1187 if ((input.length & 1) != 0) { // implicit nullcheck of input 1188 throw new InternalError("length is odd"); 1189 } 1190 size = input.length >> 1; 1191 1192 int len = EXPAND_FACTOR * input.length; 1193 len = (len + 1) & ~1; // ensure table is even length 1194 table = new Object[len]; 1195 1196 for (int i = 0; i < input.length; i += 2) { 1197 @SuppressWarnings("unchecked") 1198 K k = Objects.requireNonNull((K)input[i]); 1199 @SuppressWarnings("unchecked") 1200 V v = Objects.requireNonNull((V)input[i+1]); 1201 int idx = probe(k); 1202 if (idx >= 0) { 1203 throw new IllegalArgumentException("duplicate key: " + k); 1204 } else { 1205 int dest = -(idx + 1); 1206 table[dest] = k; 1207 table[dest+1] = v; 1208 } 1209 } 1210 } 1211 1212 @Override 1213 public boolean containsKey(Object o) { 1214 Objects.requireNonNull(o); 1215 return size > 0 && probe(o) >= 0; 1216 } 1217 1218 @Override 1219 public boolean containsValue(Object o) { 1220 Objects.requireNonNull(o); 1221 for (int i = 1; i < table.length; i += 2) { 1222 Object v = table[i]; 1223 if (v != null && o.equals(v)) { 1224 return true; 1225 } 1226 } 1227 return false; 1228 } 1229 1230 @Override 1231 public int hashCode() { 1232 int hash = 0; 1233 for (int i = 0; i < table.length; i += 2) { 1234 Object k = table[i]; 1235 if (k != null) { 1236 hash += k.hashCode() ^ table[i + 1].hashCode(); 1237 } 1238 } 1239 return hash; 1240 } 1241 1242 @Override 1243 @SuppressWarnings("unchecked") 1244 public V get(Object o) { 1245 if (size == 0) { 1246 Objects.requireNonNull(o); 1247 return null; 1248 } 1249 int i = probe(o); 1250 if (i >= 0) { 1251 return (V)table[i+1]; 1252 } else { 1253 return null; 1254 } 1255 } 1256 1257 @Override 1258 public int size() { 1259 return size; 1260 } 1261 1262 @Override 1263 public boolean isEmpty() { 1264 return size == 0; 1265 } 1266 1267 class MapNIterator implements Iterator<Map.Entry<K,V>> { 1268 1269 private int remaining; 1270 1271 private int idx; 1272 1273 MapNIterator() { 1274 remaining = size; 1275 // pick an even starting index in the [0 .. table.length-1] 1276 // range randomly based on SALT32L 1277 idx = (int) ((SALT32L * (table.length >> 1)) >>> 32) << 1; 1278 } 1279 1280 @Override 1281 public boolean hasNext() { 1282 return remaining > 0; 1283 } 1284 1285 private int nextIndex() { 1286 int idx = this.idx; 1287 if (REVERSE) { 1288 if ((idx += 2) >= table.length) { 1289 idx = 0; 1290 } 1291 } else { 1292 if ((idx -= 2) < 0) { 1293 idx = table.length - 2; 1294 } 1295 } 1296 return this.idx = idx; 1297 } 1298 1299 @Override 1300 public Map.Entry<K,V> next() { 1301 if (remaining > 0) { 1302 int idx; 1303 while (table[idx = nextIndex()] == null) {} 1304 @SuppressWarnings("unchecked") 1305 Map.Entry<K,V> e = 1306 new KeyValueHolder<>((K)table[idx], (V)table[idx+1]); 1307 remaining--; 1308 return e; 1309 } else { 1310 throw new NoSuchElementException(); 1311 } 1312 } 1313 } 1314 1315 @Override 1316 public Set<Map.Entry<K,V>> entrySet() { 1317 return new AbstractSet<>() { 1318 @Override 1319 public int size() { 1320 return MapN.this.size; 1321 } 1322 1323 @Override 1324 public Iterator<Map.Entry<K,V>> iterator() { 1325 return new MapNIterator(); 1326 } 1327 1328 // Android-added: AbstractCollection#clear implementation is no-op when 1329 // collection is empty. Overriding this method to make Map.of().clear() 1330 // and Map.of().entrySet().clear() behaviour equal. 1331 @Override 1332 public void clear() { 1333 throw uoe(); 1334 } 1335 }; 1336 } 1337 1338 // returns index at which the probe key is present; or if absent, 1339 // (-i - 1) where i is location where element should be inserted. 1340 // Callers are relying on this method to perform an implicit nullcheck 1341 // of pk. 1342 private int probe(Object pk) { 1343 int idx = Math.floorMod(pk.hashCode(), table.length >> 1) << 1; 1344 while (true) { 1345 @SuppressWarnings("unchecked") 1346 K ek = (K)table[idx]; 1347 if (ek == null) { 1348 return -idx - 1; 1349 } else if (pk.equals(ek)) { 1350 return idx; 1351 } else if ((idx += 2) == table.length) { 1352 idx = 0; 1353 } 1354 } 1355 } 1356 1357 @java.io.Serial 1358 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 1359 throw new InvalidObjectException("not serial proxy"); 1360 } 1361 1362 @java.io.Serial 1363 private Object writeReplace() { 1364 Object[] array = new Object[2 * size]; 1365 int len = table.length; 1366 int dest = 0; 1367 for (int i = 0; i < len; i += 2) { 1368 if (table[i] != null) { 1369 array[dest++] = table[i]; 1370 array[dest++] = table[i+1]; 1371 } 1372 } 1373 return new CollSer(CollSer.IMM_MAP, array); 1374 } 1375 } 1376 } 1377 1378 // ---------- Serialization Proxy ---------- 1379 1380 /** 1381 * A unified serialization proxy class for the immutable collections. 1382 * 1383 * @serial 1384 * @since 9 1385 */ 1386 final class CollSer implements Serializable { 1387 @java.io.Serial 1388 private static final long serialVersionUID = 6309168927139932177L; 1389 1390 static final int IMM_LIST = 1; 1391 static final int IMM_SET = 2; 1392 static final int IMM_MAP = 3; 1393 static final int IMM_LIST_NULLS = 4; 1394 1395 /** 1396 * Indicates the type of collection that is serialized. 1397 * The low order 8 bits have the value 1 for an immutable 1398 * {@code List}, 2 for an immutable {@code Set}, 3 for 1399 * an immutable {@code Map}, and 4 for an immutable 1400 * {@code List} that allows null elements. 1401 * 1402 * Any other value causes an 1403 * {@link InvalidObjectException} to be thrown. The high 1404 * order 24 bits are zero when an instance is serialized, 1405 * and they are ignored when an instance is deserialized. 1406 * They can thus be used by future implementations without 1407 * causing compatibility issues. 1408 * 1409 * <p>The tag value also determines the interpretation of the 1410 * transient {@code Object[] array} field. 1411 * For {@code List} and {@code Set}, the array's length is the size 1412 * of the collection, and the array contains the elements of the collection. 1413 * Null elements are not allowed. For {@code Set}, duplicate elements 1414 * are not allowed. 1415 * 1416 * <p>For {@code Map}, the array's length is twice the number of mappings 1417 * present in the map. The array length is necessarily even. 1418 * The array contains a succession of key and value pairs: 1419 * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed, 1420 * and duplicate keys are not allowed. 1421 * 1422 * @serial 1423 * @since 9 1424 */ 1425 private final int tag; 1426 1427 /** 1428 * @serial 1429 * @since 9 1430 */ 1431 private transient Object[] array; 1432 1433 CollSer(int t, Object... a) { 1434 tag = t; 1435 array = a; 1436 } 1437 1438 /** 1439 * Reads objects from the stream and stores them 1440 * in the transient {@code Object[] array} field. 1441 * 1442 * @serialData 1443 * A nonnegative int, indicating the count of objects, 1444 * followed by that many objects. 1445 * 1446 * @param ois the ObjectInputStream from which data is read 1447 * @throws IOException if an I/O error occurs 1448 * @throws ClassNotFoundException if a serialized class cannot be loaded 1449 * @throws InvalidObjectException if the count is negative 1450 * @since 9 1451 */ 1452 @java.io.Serial 1453 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 1454 ois.defaultReadObject(); 1455 int len = ois.readInt(); 1456 1457 if (len < 0) { 1458 throw new InvalidObjectException("negative length " + len); 1459 } 1460 1461 SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, len); 1462 Object[] a = new Object[len]; 1463 for (int i = 0; i < len; i++) { 1464 a[i] = ois.readObject(); 1465 } 1466 1467 array = a; 1468 } 1469 1470 /** 1471 * Writes objects to the stream from 1472 * the transient {@code Object[] array} field. 1473 * 1474 * @serialData 1475 * A nonnegative int, indicating the count of objects, 1476 * followed by that many objects. 1477 * 1478 * @param oos the ObjectOutputStream to which data is written 1479 * @throws IOException if an I/O error occurs 1480 * @since 9 1481 */ 1482 @java.io.Serial 1483 private void writeObject(ObjectOutputStream oos) throws IOException { 1484 oos.defaultWriteObject(); 1485 oos.writeInt(array.length); 1486 for (int i = 0; i < array.length; i++) { 1487 oos.writeObject(array[i]); 1488 } 1489 } 1490 1491 /** 1492 * Creates and returns an immutable collection from this proxy class. 1493 * The instance returned is created as if by calling one of the 1494 * static factory methods for 1495 * <a href="List.html#unmodifiable">List</a>, 1496 * <a href="Map.html#unmodifiable">Map</a>, or 1497 * <a href="Set.html#unmodifiable">Set</a>. 1498 * This proxy class is the serial form for all immutable collection instances, 1499 * regardless of implementation type. This is necessary to ensure that the 1500 * existence of any particular implementation type is kept out of the 1501 * serialized form. 1502 * 1503 * @return a collection created from this proxy object 1504 * @throws InvalidObjectException if the tag value is illegal or if an exception 1505 * is thrown during creation of the collection 1506 * @throws ObjectStreamException if another serialization error has occurred 1507 * @since 9 1508 */ 1509 @java.io.Serial 1510 private Object readResolve() throws ObjectStreamException { 1511 try { 1512 if (array == null) { 1513 throw new InvalidObjectException("null array"); 1514 } 1515 1516 // use low order 8 bits to indicate "kind" 1517 // ignore high order 24 bits 1518 switch (tag & 0xff) { 1519 case IMM_LIST: 1520 return List.of(array); 1521 case IMM_LIST_NULLS: 1522 return ImmutableCollections.listFromTrustedArrayNullsAllowed( 1523 Arrays.copyOf(array, array.length, Object[].class)); 1524 case IMM_SET: 1525 return Set.of(array); 1526 case IMM_MAP: 1527 if (array.length == 0) { 1528 return ImmutableCollections.EMPTY_MAP; 1529 } else if (array.length == 2) { 1530 return new ImmutableCollections.Map1<>(array[0], array[1]); 1531 } else { 1532 return new ImmutableCollections.MapN<>(array); 1533 } 1534 default: 1535 throw new InvalidObjectException(String.format("invalid flags 0x%x", tag)); 1536 } 1537 } catch (NullPointerException|IllegalArgumentException ex) { 1538 InvalidObjectException ioe = new InvalidObjectException("invalid object"); 1539 ioe.initCause(ex); 1540 throw ioe; 1541 } 1542 } 1543 } 1544