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