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&#46;util&#46;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 &amp; 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}