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