001/* 002* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. 003* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004* 005* This code is free software; you can redistribute it and/or modify it 006* under the terms of the GNU General Public License version 2 only, as 007* published by the Free Software Foundation. Oracle designates this 008* particular file as subject to the "Classpath" exception as provided 009* by Oracle in the LICENSE file that accompanied this code. 010* 011* This code is distributed in the hope that it will be useful, but WITHOUT 012* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014* version 2 for more details (a copy is included in the LICENSE file that 015* accompanied this code). 016* 017* You should have received a copy of the GNU General Public License version 018* 2 along with this work; if not, write to the Free Software Foundation, 019* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020* 021* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022* or visit www.oracle.com if you need additional information or have any 023* questions. 024*/ 025 026package Torello.Java.ReadOnly; 027 028import Torello.Java.Additional.RemoveUnsupportedIterator; 029 030import java.util.function.*; 031 032import java.util.*; 033 034import java.util.stream.Collector; 035 036import java.io.Serializable; 037 038/** 039 * Immutable Wrapper for <CODE>java.util.ArrayList</CODE>, found in the "Java Collections 040 * Framework". 041 * 042 * <EMBED CLASS=globalDefs DATA-JDK=ArrayList> 043 * <EMBED CLASS='external-html' DATA-FILE-ID=MUCHOS_CONSTRUCTORS> 044 * <EMBED CLASS='external-html' DATA-FILE-ID=DATA_CLASS> 045 * 046 * @param <E> the type of elements in this list 047 */ 048@SuppressWarnings("unchecked") 049@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="JDHBI_MAIN") 050public class ReadOnlyArrayList<E> implements ReadOnlyList<E>, RandomAccess, Serializable 051{ 052 // ******************************************************************************************** 053 // ******************************************************************************************** 054 // Protected & Private Fields, Methods, Statics 055 // ******************************************************************************************** 056 // ******************************************************************************************** 057 058 059 /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */ 060 protected static final long serialVersionUID = 1; 061 062 // Minor Optimization where new ArrayList's that have no contents always re-use this static 063 // instance. Since this instance is completely empty, the Raw-Types things is irrelevant. 064 065 @SuppressWarnings("rawtypes") 066 private static final ArrayList EMPTY_ARRAY_LIST = new ArrayList(0); 067 068 // Singleton & Empty ReadOnlyArrayList, Uses the "Supplier Constructor" 069 @SuppressWarnings("rawtypes") 070 private static final ReadOnlyArrayList EMPTY_READONLY_ARRAY_LIST = 071 new ReadOnlyArrayList(0, () -> null); 072 073 // The actual ArrayList used by this instance. 074 private final ArrayList<E> arrayList; 075 076 // TRUE => This was built using the class ROArrayListBuilder 077 // FALSE => This was built using the clone() of a standard java.util.ArrayList constructor 078 079 private final boolean fromBuilderOrArrayList; 080 081 // Mimics the C++ Keyword/Concept of "Friend Class". Is "Friends With" ROArrayListBuilder 082 static class AccessBadge { private AccessBadge() { } } 083 private static final AccessBadge friendClassBadge = new AccessBadge(); 084 085 public static <T> ReadOnlyArrayList<T> emptyROAL() 086 { return (ReadOnlyArrayList<T>) EMPTY_READONLY_ARRAY_LIST; } 087 088 089 // ******************************************************************************************** 090 // ******************************************************************************************** 091 // Basic Constructors 092 // ******************************************************************************************** 093 // ******************************************************************************************** 094 095 096 // To all the readers out there following along: The "AccessBadge" thing is just a slightly 097 // wimpier substitute for the C++ keyword / concept 'friend' or "Friend Class". It means this 098 // constructor is (for all intents and purposes) a private-constructor, except for the class 099 // ROArrayListBuilder 100 // 101 // This is the Constructor used by the Builder. It has a "Zero-Size" Optimization 102 103 ReadOnlyArrayList(ROArrayListBuilder<E> roalb, ROArrayListBuilder.AccessBadge badge) 104 { 105 Objects.requireNonNull(badge, "Access Badge is null. Requires Friend-Class Badge"); 106 107 fromBuilderOrArrayList = true; 108 this.arrayList = roalb; 109 } 110 111 /** 112 * Copies parameter {@code 'c'} (and saves it) in order to guarantee that {@code 'this'} 113 * instance is Read-Only, and shielded from outside modification. 114 * 115 * @param c The {@code Collection} to be copied and saved into this instance internal 116 * and private {@code 'arrayList'} field. 117 */ 118 public ReadOnlyArrayList(Collection<E> c) 119 { 120 fromBuilderOrArrayList = false; 121 122 // Empty Optimization (throw away, completely, the reference, use static-constant) 123 this.arrayList = (c.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : new ArrayList<>(c); 124 } 125 126 /** 127 * Use a {@code Supplier<E>} to provide an arbitrary number of elements of type {@code 'E'} 128 * directly to this constructor. This constructor will request elements from the 129 * {@code Supplier} provided to parameter {@code 's'} until {@code 's'} returns null. 130 * 131 * <EMBED CLASS=defs DATA-SOURCE=Supplier> 132 * 133 * @param quantityIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY> 134 * @param s Any Java {@code Supplier<E>} 135 * @throws IllegalArgumentException if the specified quantity / capacity is negative 136 */ 137 public ReadOnlyArrayList(Integer quantityIfKnown, Supplier<E> s) 138 { 139 fromBuilderOrArrayList = false; 140 141 ArrayList<E> arrayList = (quantityIfKnown != null) 142 ? new ArrayList<>(quantityIfKnown) 143 : new ArrayList<>(); 144 145 E e; 146 while ((e = s.get()) != null) arrayList.add(e); 147 148 // Empty Optimization (throw away, completely, the reference, use static-constant) 149 this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList; 150 } 151 152 153 // ******************************************************************************************** 154 // ******************************************************************************************** 155 // Iterable & Array Based Constructors - **NO FILTER** 156 // ******************************************************************************************** 157 // ******************************************************************************************** 158 159 160 /** 161 * If only a small amount of processing needs to be done on the contents of some Java 162 * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this 163 * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyArrayList}, using 164 * a simple {@code 'mapper'}</I>. 165 * 166 * <EMBED CLASS=defs DATA-SOURCE=Iterable> 167 * 168 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM> 169 * @param i Any Java {@code Iterable<T>} 170 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER> 171 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY> 172 * 173 * @throws NullPointerException if either {@code 'i'} or {@code 'mapper'} are passed null 174 */ 175 public <T> ReadOnlyArrayList( 176 Iterable<T> i, 177 Function<? super T, ? extends E> mapper, 178 Integer sizeIfKnown) 179 { 180 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 181 182 fromBuilderOrArrayList = false; 183 184 ArrayList<E> arrayList = (sizeIfKnown != null) 185 ? new ArrayList<>(sizeIfKnown) 186 : new ArrayList<>(); 187 188 for (T t : i) arrayList.add(mapper.apply(t)); 189 190 // Empty Optimization (throw away, completely, the reference, use static-constant) 191 this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList; 192 } 193 194 /** 195 * If a Standard Java {@code Iterable} can be directly mapped into an {@code ArrayList} 196 * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will 197 * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyArrayList<E>} 198 * with just this single invocation</I>. 199 * 200 * <EMBED CLASS=defs DATA-SOURCE=Iterable> 201 * 202 * @param i Any Java {@code Iterable<E>} 203 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY> 204 * 205 * @throws IllegalArgumentException if the specified initial capacity is negative 206 */ 207 public ReadOnlyArrayList(Iterable<E> i, Integer sizeIfKnown) 208 { 209 fromBuilderOrArrayList = false; 210 211 ArrayList<E> arrayList = (sizeIfKnown != null) 212 ? new ArrayList<>(sizeIfKnown) 213 : new ArrayList<>(); 214 215 for (E element : i) arrayList.add(element); 216 217 // Empty Optimization (throw away, completely, the reference, use static-constant) 218 this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList; 219 } 220 221 /** 222 * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents 223 * {@code 'elements'}. 224 * 225 * @param elementsType <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE> 226 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 227 * 228 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 229 * @throws NullPointerException If {@code 'elementsType'} is passed null. 230 */ 231 public ReadOnlyArrayList(Class<E> elementsType, Object... elements) 232 { 233 Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'"); 234 235 fromBuilderOrArrayList = false; 236 237 if (elements.length == 0) 238 this.arrayList = (ArrayList<E>) EMPTY_ARRAY_LIST; 239 240 else 241 { 242 this.arrayList = new ArrayList<>(elements.length); 243 for (Object element : elements) this.arrayList.add(elementsType.cast(element)); 244 } 245 } 246 247 /** 248 * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents 249 * {@code 'elements'}. 250 * 251 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER> 252 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 253 * 254 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 255 * @throws NullPointerException If {@code 'mapper'} is passed null. 256 */ 257 public ReadOnlyArrayList(Function<Object, ? extends E> mapper, Object... elements) 258 { 259 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 260 261 fromBuilderOrArrayList = false; 262 263 if (elements.length == 0) 264 this.arrayList = (ArrayList<E>) EMPTY_ARRAY_LIST; 265 266 else 267 { 268 this.arrayList = new ArrayList<>(elements.length); 269 for (Object element : elements) this.arrayList.add(mapper.apply(element)); 270 } 271 } 272 273 274 // ******************************************************************************************** 275 // ******************************************************************************************** 276 // Iterable & Array Based Constructors - **INCLUDES ELEMENT FILTER** 277 // ******************************************************************************************** 278 // ******************************************************************************************** 279 280 281 /** 282 * If only a small amount of processing needs to be done on the contents of some Java 283 * Data-Type, and using an entire Builder-Class seems disproportionately complex - <I>this 284 * constructor can convert any Java {@code Iterable} into a {@code ReadOnlyArrayList}, using 285 * a simple {@code 'mapper'}</I>. 286 * 287 * <EMBED CLASS=defs DATA-SOURCE=Iterable> 288 * 289 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_TYPE_PARAM> 290 * @param i Any Java {@code Iterable<T>} 291 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=ITERABLE_MAPPER> 292 * @param filter <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER> 293 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY> 294 * 295 * @throws NullPointerException if any of {@code 'i'}, {@code 'mapper'} or {@code 'filter'} 296 * are passed null. 297 */ 298 public <T> ReadOnlyArrayList( 299 Iterable<T> i, 300 Function<? super T, ? extends E> mapper, 301 Predicate<? super T> filter, 302 Integer sizeIfKnown 303 ) 304 { 305 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 306 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 307 308 fromBuilderOrArrayList = false; 309 310 ArrayList<E> arrayList = (sizeIfKnown != null) 311 ? new ArrayList<>(sizeIfKnown) 312 : new ArrayList<>(); 313 314 for (T t : i) if (filter.test(t)) arrayList.add(mapper.apply(t)); 315 316 // Empty Optimization (throw away, completely, the reference, use static-constant) 317 this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList; 318 } 319 320 /** 321 * If a Standard Java {@code Iterable} can be directly mapped into an {@code ArrayList} 322 * (and, ergo, an entire Builder-Instance would be a bit excessive) - <I>this constructor will 323 * seamlessly convert any Java {@code Iterable<E>} directly into a {@code ReadOnlyArrayList<E>} 324 * with just this single invocation</I>. 325 * 326 * <EMBED CLASS=defs DATA-SOURCE=Iterable> 327 * 328 * @param i Any Java {@code Iteratable<E>} 329 * @param filter <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER> 330 * @param sizeIfKnown <EMBED CLASS='external-html' DATA-FILE-ID=VECAL_INIT_CAPACITY> 331 * 332 * @throws IllegalArgumentException if the specified initial capacity is negative 333 * @throws NullPointerException if either {'i'} or {@code 'filter'} are passed null 334 */ 335 public ReadOnlyArrayList(Iterable<E> i, Predicate<? super E> filter, Integer sizeIfKnown) 336 { 337 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 338 339 fromBuilderOrArrayList = false; 340 341 ArrayList<E> arrayList = (sizeIfKnown != null) 342 ? new ArrayList<>(sizeIfKnown) 343 : new ArrayList<>(); 344 345 for (E element : i) if (filter.test(element)) arrayList.add(element); 346 347 // Empty Optimization (throw away, completely, the reference, use static-constant) 348 this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList; 349 } 350 351 /** 352 * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents 353 * {@code 'elements'}. 354 * 355 * @param elementsType <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_TYPE> 356 * @param filter <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER> 357 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 358 * 359 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=CCEX> 360 * 361 * @throws NullPointerException If either {@code 'elementsType'} or {@code 'filter'} are 362 * passsed null. 363 */ 364 public ReadOnlyArrayList 365 (Class<E> elementsType, Predicate<? super E> filter, Object... elements) 366 { 367 Objects.requireNonNull(elementsType, ROHelpers.NULL_MSG + "'elementsType'"); 368 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 369 370 fromBuilderOrArrayList = false; 371 372 ArrayList<E> arrayList = new ArrayList<>(elements.length); 373 374 E e; 375 for (Object element : elements) 376 if (filter.test(e = elementsType.cast(element))) 377 arrayList.add(e); 378 379 // Empty Optimization (throw away, completely, the reference, use static-constant) 380 this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList; 381 } 382 383 /** 384 * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents 385 * {@code 'elements'}. 386 * 387 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=OBJ_E_MAPPER> 388 * @param filter <EMBED CLASS='external-html' DATA-FTP=Object DATA-FILE-ID=PREDICATE_FILTER> 389 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 390 * 391 * @throws NullPointerException If either {@code 'mapper'} or {@code 'filter'} are passed null 392 */ 393 public ReadOnlyArrayList 394 (Function<Object, ? extends E> mapper, Predicate<Object> filter, Object... elements) 395 { 396 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 397 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 398 399 fromBuilderOrArrayList = false; 400 401 ArrayList<E> arrayList = new ArrayList<>(elements.length); 402 403 for (Object element : elements) 404 if (filter.test(element)) 405 arrayList.add(mapper.apply(element)); 406 407 // Empty Optimization (throw away, completely, the reference, use static-constant) 408 this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList; 409 } 410 411 412 // ******************************************************************************************** 413 // ******************************************************************************************** 414 // @SafeVarargs / Variable-Arity / VarArgs: with Parameterized / Generic Type's 415 // ******************************************************************************************** 416 // ******************************************************************************************** 417 418 419 /** 420 * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents 421 * {@code 'elements'}. 422 * 423 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 424 */ 425 @SafeVarargs 426 public ReadOnlyArrayList(E... elements) 427 { 428 fromBuilderOrArrayList = false; 429 430 if (elements.length == 0) 431 this.arrayList = (ArrayList<E>) EMPTY_ARRAY_LIST; 432 433 else 434 { 435 this.arrayList = new ArrayList<>(elements.length); 436 for (E e : elements) this.arrayList.add(e); 437 } 438 } 439 440 /** 441 * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents 442 * {@code 'elements'}. 443 * 444 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM> 445 * @param dummy <EMBED CLASS='external-html' DATA-FILE-ID=DUMMY_INT> 446 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER> 447 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 448 * 449 * @throws NullPointerException If {@code 'mapper'} is passed null. 450 */ 451 @SafeVarargs 452 public <T> ReadOnlyArrayList( 453 int dummy, 454 Function<? super T, ? extends E> mapper, 455 T... elements 456 ) 457 { 458 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 459 460 fromBuilderOrArrayList = false; 461 462 if (elements.length == 0) 463 this.arrayList = (ArrayList<E>) EMPTY_ARRAY_LIST; 464 465 else 466 { 467 this.arrayList = new ArrayList<>(elements.length); 468 for (T t : elements) this.arrayList.add(mapper.apply(t)); 469 } 470 } 471 472 /** 473 * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents 474 * {@code 'elements'}. 475 * 476 * @param filter <EMBED CLASS='external-html' DATA-FTP=E DATA-FILE-ID=PREDICATE_FILTER> 477 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 478 * 479 * @throws NullPointerException If {@code 'filter'} is passsed null. 480 */ 481 @SafeVarargs 482 public ReadOnlyArrayList(Predicate<? super E> filter, E... elements) 483 { 484 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 485 486 fromBuilderOrArrayList = false; 487 488 ArrayList<E> arrayList = new ArrayList<>(elements.length); 489 for (E e : elements) if (filter.test(e)) arrayList.add(e); 490 491 // Empty Optimization (throw away, completely, the reference, use static-constant) 492 this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList; 493 } 494 495 /** 496 * Builds {@code ReadOnlyArrayList<E>} instance having Generic-Type {@code 'E'}, and contents 497 * {@code 'elements'}. 498 * 499 * @param <T> <EMBED CLASS='external-html' DATA-FILE-ID=VARARGS_TYPE_PARAM> 500 * @param filter <EMBED CLASS='external-html' DATA-FTP=T DATA-FILE-ID=PREDICATE_FILTER> 501 * @param mapper <EMBED CLASS='external-html' DATA-FILE-ID=T_ARR_E_MAPPER> 502 * @param elements <EMBED CLASS='external-html' DATA-FILE-ID=ELEMENTS_VAR_ARGS> 503 * 504 * @throws NullPointerException If either {@code 'mapper'} or {@code 'filter'} are passed null 505 */ 506 @SafeVarargs 507 public <T> ReadOnlyArrayList( 508 Predicate<? super T> filter, 509 Function<? super T, ? extends E> mapper, 510 T... elements 511 ) 512 { 513 Objects.requireNonNull(mapper, ROHelpers.NULL_MSG + "'mapper'"); 514 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 515 516 fromBuilderOrArrayList = false; 517 518 ArrayList<E> arrayList = new ArrayList<>(elements.length); 519 for (T t : elements) if (filter.test(t)) arrayList.add(mapper.apply(t)); 520 521 // Empty Optimization (throw away, completely, the reference, use static-constant) 522 this.arrayList = (arrayList.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : arrayList; 523 } 524 525 526 // ******************************************************************************************** 527 // ******************************************************************************************** 528 // PRIMITIVE-ARRAY INPUT 529 // ******************************************************************************************** 530 // ******************************************************************************************** 531 532 533 /** 534 * Converts a Java Primitive-Array to a {@code ReadOnlyArrayList<E>}, where {@code 'E'} is the 535 * Java Boxed-Type which corresponds to the Primitive-Array's Type. 536 * 537 * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC> 538 * @param primitiveArray <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY> 539 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX> 540 * @throws NullPointerException If {@code 'primitiveArray'} is passed null; 541 */ 542 public ReadOnlyArrayList(Object primitiveArray) 543 { 544 fromBuilderOrArrayList = false; 545 546 ArrayList<E> al = ROHelpers.buildROListOrSet( 547 primitiveArray, 548 (int arrayLen) -> new ArrayList<E>(arrayLen), 549 null 550 ); 551 552 // Empty Optimization (throw away, completely, the reference, use static-constant) 553 this.arrayList = (al.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : al; 554 } 555 556 /** 557 * Converts a Java Primitive-Array to a {@code ReadOnlyArrayList<E>}, where {@code 'E'} is the 558 * Java Boxed-Type which corresponds to the Primitive-Array's Type - <I>but also accepts a 559 * {@code 'filter'} that can remove any array-entries that need to be removed</I>. 560 * 561 * <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CTOR_DESC> 562 * @param primitiveArray <EMBED CLASS='external-html' DATA-FILE-ID=PRIMITIVE_ARRAY> 563 * @param filter <EMBED CLASS='external-html' DATA-FILE-ID=PRED_FILT_PRIM> 564 * @throws ClassCastException <EMBED CLASS='external-html' DATA-FILE-ID=PRIM_ARR_CCEX> 565 * @throws NullPointerException If {@code 'primitiveArray'} is passed null; 566 */ 567 public ReadOnlyArrayList( 568 Object primitiveArray, 569 Predicate<?> filter 570 ) 571 { 572 Objects.requireNonNull(filter, ROHelpers.NULL_MSG + "'filter'"); 573 574 fromBuilderOrArrayList = false; 575 576 ArrayList<E> al = ROHelpers.buildROListOrSet( 577 primitiveArray, 578 (int arrayLen) -> new ArrayList<E>(arrayLen), 579 filter 580 ); 581 582 // Empty Optimization (throw away, completely, the reference, use static-constant) 583 this.arrayList = (al.size() == 0) ? ((ArrayList<E>) EMPTY_ARRAY_LIST) : al; 584 } 585 586 587 // ******************************************************************************************** 588 // ******************************************************************************************** 589 // java.util.stream.Stream HELPER 590 // ******************************************************************************************** 591 // ******************************************************************************************** 592 593 594 /** 595 * For use with a the Java Stream method {@code 'collect(Collector c)'}. 596 * 597 * <EMBED CLASS='external-html' DATA-ABBREV=al DATA-FILE-ID=STREAM_COLLECTOR> 598 * 599 * @param <T> This is the Generic-Type of the Input-Stream. It will also be the Generic-Type 600 * of the {@code ReadOnlyArrayList} that's returned from the stream's {@code collect} method. 601 * 602 * @param characteristics Optional Characteristics List. See Java Stream-API Documentation on 603 * {@code Collector.Characteristics} inner-class for more details. 604 * 605 * @return This returns a collector that may be piped into a stream's {@code 'collect'} method, 606 * as in the example, above. 607 */ 608 public static <T> java.util.stream.Collector 609 <T, ROArrayListBuilder<T>, ReadOnlyArrayList<T>> 610 streamCollector(Collector.Characteristics... characteristics) 611 { 612 return Collector.of( 613 ROArrayListBuilder<T>::new, // The "Supplier" (builds a new ROArrayListBuilder) 614 ROArrayListBuilder<T>::add, // The "Accumulator" (adds elements to the builder) 615 616 // Oracle Making Life Difficult - It should be the line below, but, alas, it is not! 617 // ROArrayListBuilder<T>::addAll, // The "Combiner" (combines two ROArrayListBuilders) 618 // 619 // In Stream.collect(), the 3rd parameter - the "combiner" - is a "BiConsumer<R, R>" 620 // NOTE: A "BiConsumer" is a FunctionalInterface that does not return anything - it is 621 // (obviously) a "void" return method! 622 // 623 // **BUT** 624 // 625 // In Collector.of, the 3rd parameter - the "combiner" - is a "BinaryOperation<R>" 626 627 (ROArrayListBuilder<T> roalb1, ROArrayListBuilder<T> roalb2) -> 628 { 629 roalb1.addAll(roalb2); 630 return roalb1; 631 }, 632 633 ROArrayListBuilder<T>::build, // The "Finisher" (Converts Builder to ReadOnlyArrayList) 634 characteristics 635 ); 636 } 637 638 639 // ******************************************************************************************** 640 // ******************************************************************************************** 641 // Convert to java.util Types 642 // ******************************************************************************************** 643 // ******************************************************************************************** 644 645 646 /** 647 * Clone's {@code 'this'} instance internal {@code ArrayList<E>} field, and returns it. 648 * <EMBED CLASS='external-html' DATA-TYPE=ArrayList DATA-FILE-ID=CLONE_TO> 649 * 650 * @return An independent, mutable copy of {@code 'this'} instance' internal 651 * {@code ArrayList<E>} data-structure. 652 */ 653 public ArrayList<E> cloneToArrayList() 654 { 655 return fromBuilderOrArrayList 656 ? new ArrayList<E>(this.arrayList) 657 : (ArrayList<E>) this.arrayList.clone(); 658 } 659 660 /** 661 * Invokes {@code java.util.Collections.unmodifiableList} on the internal {@code ArrayList}. 662 * <EMBED CLASS='external-html' DATA-RET_TYPE=List DATA-FILE-ID=WRAP_TO_IMMUTABLE> 663 * 664 * @return A {@code List} which adheres to the JDK interface {@code java.util.List}, but throws 665 * an {@code UnsupportedOperationException} if a user attempts to invoke a Mutator-Method on 666 * the returned instance. 667 */ 668 public List<E> wrapToImmutableList() 669 { return Collections.unmodifiableList(this.arrayList); } 670 671 672 // ******************************************************************************************** 673 // ******************************************************************************************** 674 // Original JDK Methods, java.util.ArrayList 675 // ******************************************************************************************** 676 // ******************************************************************************************** 677 678 679 /** 680 * Returns the number of elements in this list. 681 * @return the number of elements in this list 682 */ 683 public int size() 684 { return this.arrayList.size(); } 685 686 /** 687 * Returns {@code TRUE} if this list contains no elements. 688 * @return {@code TRUE} if this list contains no elements 689 */ 690 public boolean isEmpty() 691 { return this.arrayList.isEmpty(); } 692 693 /** 694 * Returns {@code TRUE} if this list contains the specified element. More formally, returns 695 * {@code TRUE} if and only if this list contains at least one element {@code e} such that 696 * {@code Objects.equals(o, e)}. 697 * 698 * @param o element whose presence in this list is to be tested 699 * @return {@code TRUE} if this list contains the specified element 700 */ 701 public boolean contains(Object o) 702 { return this.arrayList.contains(o); } 703 704 /** 705 * Returns the index of the first occurrence of the specified element in this list, or 706 * {@code -1} if this list does not contain the element. More formally, returns the lowest 707 * index {@code i} such that {@code Objects.equals(o, get(i))}, or {@code -1} if there is no 708 * such index. 709 */ 710 public int indexOf(Object o) 711 { return this.arrayList.indexOf(o); } 712 713 /** 714 * Returns the index of the last occurrence of the specified element in this list, or 715 * {@code -1} if this list does not contain the element. More formally, returns the highest 716 * index {@code i} such that {@code Objects.equals(o, get(i))}, or {@code -1} if there is no 717 * such index. 718 */ 719 public int lastIndexOf(Object o) 720 { return this.arrayList.lastIndexOf(o); } 721 722 /** 723 * Returns an array containing all of the elements in this list in proper sequence (from first 724 * to last element). 725 * 726 * <BR /><BR />The returned array will be "safe" in that no references to it are maintained by 727 * this list. (In other words, this method must allocate a new array). The caller is thus 728 * free to modify the returned array. 729 * 730 * <BR /><BR />This method acts as bridge between array-based and collection-based APIs. 731 * 732 * @return an array containing all of the elements in this list in proper sequence 733 */ 734 public Object[] toArray() 735 { return this.arrayList.toArray(); } 736 737 /** 738 * Returns an array containing all of the elements in this list in proper sequence (from first 739 * to last element); the runtime type of the returned array is that of the specified array. If 740 * the list fits in the specified array, it is returned therein. Otherwise, a new array is 741 * allocated with the runtime type of the specified array and the size of this list. 742 * 743 * <BR /><BR />If the list fits in the specified array with room to spare (i.e., the array has 744 * more elements than the list), the element in the array immediately following the end of the 745 * collection is set to {@code null}. (This is useful in determining the length of the list 746 * <i>only</i> if the caller knows that the list does not contain any null elements.) 747 * 748 * @param a the array into which the elements of the list are to be stored, if it is big enough; 749 * otherwise, a new array of the same runtime type is allocated for this purpose. 750 * 751 * @return an array containing the elements of the list 752 * 753 * @throws ArrayStoreException if the runtime type of the specified array is not a supertype of 754 * the runtime type of every element in this list 755 * 756 * @throws NullPointerException if the specified array is null 757 */ 758 public <T> T[] toArray(T[] a) 759 { return this.arrayList.toArray(a); } 760 761 /** 762 * Returns the element at the specified position in this list. 763 * @param index index of the element to return 764 * @return the element at the specified position in this list 765 * @throws IndexOutOfBoundsException {@inheritDoc} 766 */ 767 public E get(int index) 768 { return this.arrayList.get(index); } 769 770 /** @throws NullPointerException {@inheritDoc} */ 771 @Override 772 public void forEach(Consumer<? super E> action) 773 { this.arrayList.forEach(action); } 774 775 /** 776 * Utilizes this class private, internal {@code 'arrayList'} field to generate a 777 * {@code Spliterator}. 778 * 779 * @return a {@code Spliterator} over the elements in this list 780 */ 781 @Override 782 public Spliterator<E> spliterator() 783 { return this.arrayList.spliterator(); } 784 785 786 // ******************************************************************************************** 787 // ******************************************************************************************** 788 // The Builder AccessDenied Issue 789 // ******************************************************************************************** 790 // ******************************************************************************************** 791 792 793 /** 794 * Returns a list iterator over the elements in this list (in proper sequence), starting at the 795 * specified position in the list. The specified index indicates the first element that would 796 * be returned by an initial call to {@link ReadOnlyListIterator#next next}. An initial call to 797 * {@link ReadOnlyListIterator#previous previous} would return the element with the specified 798 * index minus one. 799 * 800 * @throws IndexOutOfBoundsException {@inheritDoc} 801 */ 802 public ReadOnlyListIterator<E> listIterator(int index) 803 { 804 return InterfaceBuilder.toReadOnlyListIterator( 805 fromBuilderOrArrayList 806 ? ((ROArrayListBuilder<E>) this.arrayList)._listIterator(index, friendClassBadge) 807 : this.arrayList.listIterator(index) 808 ); 809 } 810 811 /** 812 * Returns a list iterator over the elements in this list (in proper sequence). 813 * @see #listIterator(int) 814 */ 815 public ReadOnlyListIterator<E> listIterator() 816 { 817 return InterfaceBuilder.toReadOnlyListIterator( 818 fromBuilderOrArrayList 819 ? ((ROArrayListBuilder<E>) this.arrayList)._listIterator(friendClassBadge) 820 : this.arrayList.listIterator() 821 ); 822 } 823 824 /** 825 * Returns an iterator over the elements in this list in proper sequence. 826 * @return an iterator over the elements in this list in proper sequence 827 */ 828 public RemoveUnsupportedIterator<E> iterator() 829 { 830 return fromBuilderOrArrayList 831 ? (RemoveUnsupportedIterator<E>) this.arrayList.iterator() 832 : new RemoveUnsupportedIterator<E>(this.arrayList.iterator()); 833 } 834 835 /** 836 * Returns a view of the portion of this list between the specified {@code 'fromIndex'}, 837 * inclusive, and {@code toIndex}, exclusive. (If {@code 'fromIndex'} and {@code 'toIndex'} 838 * are equal, the returned list is empty.) 839 * 840 * @throws IndexOutOfBoundsException {@inheritDoc} 841 * @throws IllegalArgumentException {@inheritDoc} 842 */ 843 public ReadOnlyList<E> subList(int fromIndex, int toIndex) 844 { 845 return InterfaceBuilder.toReadOnlyList( 846 fromBuilderOrArrayList 847 ? ((ROArrayListBuilder<E>) this.arrayList). 848 _subList(fromIndex, toIndex, friendClassBadge) 849 : this.arrayList.subList(fromIndex, toIndex) 850 ); 851 } 852 853 854 // ******************************************************************************************** 855 // ******************************************************************************************** 856 // Original JDK Methods, java.util.AbstractList 857 // ******************************************************************************************** 858 // ******************************************************************************************** 859 860 861 public boolean containsAll(Collection<?> c) 862 { return this.arrayList.containsAll(c); } 863 864 865 // ******************************************************************************************** 866 // ******************************************************************************************** 867 // java.lang.Object 868 // ******************************************************************************************** 869 // ******************************************************************************************** 870 871 872 /** 873 * Returns a {@code String} representation of this {@code ArrayList}. The {@code String} 874 * representation consists of a list of the collection's elements in the order they are 875 * returned by its iterator, enclosed in square brackets ({@code "[]"}). Adjacent elements are 876 * separated by the characters {@code ", "} (comma and space). Elements are converted to 877 * {@code String's} as by {@code String.valueOf(Object)}. 878 * 879 * @return a {@code String} representation of this {@code ArrayList} 880 */ 881 public String toString() 882 { return this.arrayList.toString(); } 883 884 /** 885 * Compares the specified Object with this List for equality, as per the definition in the 886 * class {@code java.util.ArrayList}. 887 * 888 * @param o object to be compared for equality with this {@code ReadOnlyArrayList} 889 * @return {@code TRUE} if the specified Object is equal to this List 890 */ 891 public boolean equals(Object o) 892 { return ROHelpers.roListEq(this, o); } 893 894 /** 895 * Returns the hash code value for this List as per the definition in the class 896 * {@code java.util.ArrayList}. 897 */ 898 public int hashCode() 899 { return this.arrayList.hashCode(); } 900}