001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.collections4;
019
020import java.util.AbstractList;
021import java.util.ArrayList;
022import java.util.Collection;
023import java.util.Collections;
024import java.util.HashSet;
025import java.util.Iterator;
026import java.util.List;
027import java.util.Objects;
028
029import org.apache.commons.collections4.functors.DefaultEquator;
030import org.apache.commons.collections4.list.FixedSizeList;
031import org.apache.commons.collections4.list.LazyList;
032import org.apache.commons.collections4.list.PredicatedList;
033import org.apache.commons.collections4.list.TransformedList;
034import org.apache.commons.collections4.list.UnmodifiableList;
035import org.apache.commons.collections4.multiset.HashMultiSet;
036import org.apache.commons.collections4.sequence.CommandVisitor;
037import org.apache.commons.collections4.sequence.EditScript;
038import org.apache.commons.collections4.sequence.SequencesComparator;
039
040/**
041 * Provides utility methods and decorators for {@link List} instances.
042 *
043 * @since 1.0
044 */
045public class ListUtils {
046
047    /**
048     * A simple wrapper to use a CharSequence as List.
049     */
050    private static final class CharSequenceAsList extends AbstractList<Character> {
051
052        private final CharSequence sequence;
053
054        CharSequenceAsList(final CharSequence sequence) {
055            this.sequence = sequence;
056        }
057
058        @Override
059        public Character get(final int index) {
060            return Character.valueOf(sequence.charAt(index));
061        }
062
063        @Override
064        public int size() {
065            return sequence.length();
066        }
067    }
068
069    /**
070     * A helper class used to construct the longest common subsequence.
071     */
072    private static final class LcsVisitor<E> implements CommandVisitor<E> {
073
074        private final ArrayList<E> sequence;
075
076        LcsVisitor() {
077            sequence = new ArrayList<>();
078        }
079
080        public List<E> getSubSequence() {
081            return sequence;
082        }
083
084        @Override
085        public void visitDeleteCommand(final E object) {
086            // noop
087        }
088
089        @Override
090        public void visitInsertCommand(final E object) {
091            // noop
092        }
093
094        @Override
095        public void visitKeepCommand(final E object) {
096            sequence.add(object);
097        }
098    }
099
100    /**
101     * Provides a partition view on a {@link List}.
102     *
103     * @since 4.0
104     */
105    private static final class Partition<T> extends AbstractList<List<T>> {
106
107        private final List<T> list;
108
109        private final int size;
110
111        private Partition(final List<T> list, final int size) {
112            this.list = list;
113            this.size = size;
114        }
115
116        @Override
117        public List<T> get(final int index) {
118            final int listSize = size();
119            if (index < 0) {
120                throw new IndexOutOfBoundsException("Index " + index + " must not be negative");
121            }
122            if (index >= listSize) {
123                throw new IndexOutOfBoundsException("Index " + index + " must be less than size " + listSize);
124            }
125            final int start = index * size;
126            final int end = Math.min(start + size, list.size());
127            return list.subList(start, end);
128        }
129
130        @Override
131        public boolean isEmpty() {
132            return list.isEmpty();
133        }
134
135        @Override
136        public int size() {
137            return (int) Math.ceil((double) list.size() / (double) size);
138        }
139    }
140
141    /**
142     * Returns either the passed in list, or if the list is {@code null}, the value of {@code defaultList}.
143     *
144     * @param <T>         The element type.
145     * @param list        The list, possibly {@code null}.
146     * @param defaultList The returned values if list is {@code null}.
147     * @return An empty list if the argument is {@code null}.
148     * @since 4.0
149     */
150    public static <T> List<T> defaultIfNull(final List<T> list, final List<T> defaultList) {
151        return list == null ? defaultList : list;
152    }
153
154    /**
155     * Returns an immutable empty list if the argument is {@code null}, or the argument itself otherwise.
156     *
157     * @param <T>  The element type.
158     * @param list The list, possibly {@code null}.
159     * @return An empty list if the argument is {@code null}.
160     */
161    public static <T> List<T> emptyIfNull(final List<T> list) {
162        return list == null ? Collections.<T>emptyList() : list;
163    }
164
165    /**
166     * Returns a fixed-sized list backed by the given list. Elements may not be added or removed from the returned list, but existing elements can be changed
167     * (for instance, via the {@link List#set(int, Object)} method).
168     *
169     * @param <E>  the element type.
170     * @param list The list whose size to fix, must not be null.
171     * @return A fixed-size list backed by that list.
172     * @throws NullPointerException if the List is null.
173     */
174    public static <E> List<E> fixedSizeList(final List<E> list) {
175        return FixedSizeList.fixedSizeList(list);
176    }
177
178    /**
179     * Gets the first element of a list.
180     * <p>
181     * Shorthand for {@code list.get(0)}
182     * </p>
183     *
184     * @param <T>  The list type.
185     * @param list The list.
186     * @return The first element of a list.
187     * @throws NullPointerException      if list is null.
188     * @throws IndexOutOfBoundsException if the list is empty.
189     * @see List#get(int)
190     * @since 4.5.0-M1
191     */
192    public static <T> T getFirst(final List<T> list) {
193        return Objects.requireNonNull(list, "list").get(0);
194    }
195
196    /**
197     * Gets the last element of a list.
198     * <p>
199     * Shorthand for {@code list.get(list.size() - 1)}
200     * </p>
201     *
202     * @param <T>  The list type.
203     * @param list The list.
204     * @return The last element of a list.
205     * @throws NullPointerException      if list is null.
206     * @throws IndexOutOfBoundsException if the list is empty.
207     * @see List#get(int)
208     * @since 4.5.0-M1
209     */
210    public static <T> T getLast(final List<T> list) {
211        return Objects.requireNonNull(list, "list").get(list.size() - 1);
212    }
213
214    /**
215     * Generates a hash code using the algorithm specified in {@link java.util.List#hashCode()}.
216     * <p>
217     * This method is useful for implementing {@code List} when you cannot extend AbstractList. The method takes Collection instances to enable other collection
218     * types to use the List implementation algorithm.
219     * </p>
220     *
221     * @param list The list to generate the hashCode for, may be null.
222     * @return The hash code.
223     * @see java.util.List#hashCode()
224     */
225    public static int hashCodeForList(final Collection<?> list) {
226        if (list == null) {
227            return 0;
228        }
229        int hashCode = 1;
230        for (final Object obj : list) {
231            hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
232        }
233        return hashCode;
234    }
235
236    /**
237     * Finds the first index in the given List which matches the given predicate.
238     * <p>
239     * If the input List or predicate is null, or no element of the List matches the predicate, -1 is returned.
240     * </p>
241     *
242     * @param <E>       the element type.
243     * @param list      The List to search, may be null.
244     * @param predicate The predicate to use, may be null.
245     * @return The first index of an Object in the List which matches the predicate or -1 if none could be found.
246     */
247    public static <E> int indexOf(final List<E> list, final Predicate<E> predicate) {
248        if (list != null && predicate != null) {
249            for (int i = 0; i < list.size(); i++) {
250                final E item = list.get(i);
251                if (predicate.test(item)) {
252                    return i;
253                }
254            }
255        }
256        return CollectionUtils.INDEX_NOT_FOUND;
257    }
258
259    /**
260     * Returns a new list containing all elements that are contained in both given lists.
261     *
262     * @param <E>   The element type.
263     * @param list1 The first list.
264     * @param list2 The second list.
265     * @return the intersection of those two lists.
266     * @throws NullPointerException if either list is null.
267     */
268    public static <E> List<E> intersection(final List<? extends E> list1, final List<? extends E> list2) {
269        final List<E> result = new ArrayList<>();
270        List<? extends E> smaller = list1;
271        List<? extends E> larger = list2;
272        if (list1.size() > list2.size()) {
273            smaller = list2;
274            larger = list1;
275        }
276        final HashSet<E> hashSet = new HashSet<>(smaller);
277        for (final E e : larger) {
278            if (hashSet.contains(e)) {
279                result.add(e);
280                hashSet.remove(e);
281            }
282        }
283        return result;
284    }
285
286    /**
287     * Tests two lists for value-equality as per the equality contract in {@link java.util.List#equals(Object)}.
288     * <p>
289     * This method is useful for implementing {@code List} when you cannot extend AbstractList. The method takes Collection instances to enable other collection
290     * types to use the List implementation algorithm.
291     * </p>
292     * <p>
293     * The relevant text (slightly paraphrased as this is a static method) is:
294     * </p>
295     * <blockquote> Compares the two list objects for equality. Returns {@code true} if and only if both lists have the same size, and all corresponding pairs
296     * of elements in the two lists are <em>equal</em>. (Two elements {@code e1} and {@code e2} are <em>equal</em> if {@code (e1==null ? e2==null :
297     * e1.equals(e2))}.) In other words, two lists are defined to be equal if they contain the same elements in the same order. This definition ensures that the
298     * equals method works properly across different implementations of the {@code List} interface. </blockquote>
299     * <p>
300     * <strong>Note:</strong> The behavior of this method is undefined if the lists are modified during the equals comparison.
301     * </p>
302     *
303     * @param list1 The first list, may be null.
304     * @param list2 The second list, may be null.
305     * @return whether the lists are equal by value comparison.
306     * @see java.util.List
307     */
308    public static boolean isEqualList(final Collection<?> list1, final Collection<?> list2) {
309        if (list1 == list2) {
310            return true;
311        }
312        if (list1 == null || list2 == null || list1.size() != list2.size()) {
313            return false;
314        }
315        final Iterator<?> it1 = list1.iterator();
316        final Iterator<?> it2 = list2.iterator();
317        while (it1.hasNext() && it2.hasNext()) {
318            final Object obj1 = it1.next();
319            final Object obj2 = it2.next();
320            if (!Objects.equals(obj1, obj2)) {
321                return false;
322            }
323        }
324        return !(it1.hasNext() || it2.hasNext());
325    }
326
327    /**
328     * Returns a "lazy" list whose elements will be created on demand.
329     * <p>
330     * When the index passed to the returned list's {@link List#get(int) get} method is greater than the list's size, then the factory will be used to create a
331     * new object and that object will be inserted at that index.
332     * </p>
333     * <p>
334     * For instance:
335     * </p>
336     *
337     * <pre>
338     * Factory&lt;Date&gt; factory = new Factory&lt;Date&gt;() {
339     *     public Date create() {
340     *         return new Date();
341     *     }
342     * }
343     * List&lt;Date&gt; lazy = ListUtils.lazyList(new ArrayList&lt;Date&gt;(), factory);
344     * Date date = lazy.get(3);
345     * </pre>
346     * <p>
347     * After the above code is executed, {@code date} will refer to a new {@code Date} instance. Furthermore, that {@code Date} instance is the fourth element
348     * in the list. The first, second, and third element are all set to {@code null}.
349     * </p>
350     *
351     * @param <E>     The element type.
352     * @param list    The list to make lazy, must not be null.
353     * @param factory The factory for creating new objects, must not be null.
354     * @return A lazy list backed by the given list.
355     * @throws NullPointerException if the List or Factory is null.
356     */
357    public static <E> List<E> lazyList(final List<E> list, final Factory<? extends E> factory) {
358        return LazyList.lazyList(list, factory);
359    }
360
361    /**
362     * Returns a "lazy" list whose elements will be created on demand.
363     * <p>
364     * When the index passed to the returned list's {@link List#get(int) get} method is greater than the list's size, then the transformer will be used to
365     * create a new object and that object will be inserted at that index.
366     * </p>
367     * <p>
368     * For instance:
369     * </p>
370     *
371     * <pre>
372     *
373     * List&lt;Integer&gt; hours = Arrays.asList(7, 5, 8, 2);
374     *
375     * Transformer&lt;Integer, Date&gt; transformer = input -&gt; LocalDateTime.now().withHour(hours.get(input));
376     *
377     * List&lt;LocalDateTime&gt; lazy = ListUtils.lazyList(new ArrayList&lt;LocalDateTime&gt;(), transformer);
378     *
379     * Date date = lazy.get(3);
380     * </pre>
381     * <p>
382     * After the above code is executed, {@code date} will refer to a new {@code Date} instance. Furthermore, that {@code Date} instance is the fourth element
383     * in the list. The first, second, and third element are all set to {@code null}.
384     * </p>
385     *
386     * @param <E>         The element type.
387     * @param list        The list to make lazy, must not be null.
388     * @param transformer The transformer for creating new objects, must not be null.
389     * @return A lazy list backed by the given list.
390     * @throws NullPointerException if the List or Transformer is null.
391     */
392    public static <E> List<E> lazyList(final List<E> list, final Transformer<Integer, ? extends E> transformer) {
393        return LazyList.lazyList(list, transformer);
394    }
395
396    /**
397     * Returns the longest common subsequence (LCS) of two {@link CharSequence} objects.
398     * <p>
399     * This is a convenience method for using {@link #longestCommonSubsequence(List, List)} with {@link CharSequence} instances.
400     * </p>
401     *
402     * @param charSequenceA The first sequence.
403     * @param charSequenceB The second sequence.
404     * @return The longest common subsequence as {@link String}.
405     * @throws NullPointerException if either sequence is {@code null}.
406     * @since 4.0
407     */
408    public static String longestCommonSubsequence(final CharSequence charSequenceA, final CharSequence charSequenceB) {
409        Objects.requireNonNull(charSequenceA, "charSequenceA");
410        Objects.requireNonNull(charSequenceB, "charSequenceB");
411        final List<Character> lcs = longestCommonSubsequence(new CharSequenceAsList(charSequenceA), new CharSequenceAsList(charSequenceB));
412        final StringBuilder sb = new StringBuilder();
413        for (final Character ch : lcs) {
414            sb.append(ch);
415        }
416        return sb.toString();
417    }
418
419    /**
420     * Returns the longest common subsequence (LCS) of two sequences (lists).
421     *
422     * @param <E> the element type.
423     * @param a   The first list.
424     * @param b   The second list.
425     * @return The longest common subsequence.
426     * @throws NullPointerException if either list is {@code null}.
427     * @since 4.0
428     */
429    public static <E> List<E> longestCommonSubsequence(final List<E> a, final List<E> b) {
430        return longestCommonSubsequence(a, b, DefaultEquator.defaultEquator());
431    }
432
433    /**
434     * Returns the longest common subsequence (LCS) of two sequences (lists).
435     *
436     * @param <E>     the element type.
437     * @param listA   The first list.
438     * @param listB   The second list.
439     * @param equator The equator used to test object equality.
440     * @return The longest common subsequence.
441     * @throws NullPointerException if either list or the equator is {@code null}.
442     * @since 4.0
443     */
444    public static <E> List<E> longestCommonSubsequence(final List<E> listA, final List<E> listB, final Equator<? super E> equator) {
445        Objects.requireNonNull(listA, "listA");
446        Objects.requireNonNull(listB, "listB");
447        Objects.requireNonNull(equator, "equator");
448        final SequencesComparator<E> comparator = new SequencesComparator<>(listA, listB, equator);
449        final EditScript<E> script = comparator.getScript();
450        final LcsVisitor<E> visitor = new LcsVisitor<>();
451        script.visit(visitor);
452        return visitor.getSubSequence();
453    }
454
455    /**
456     * Returns consecutive {@link List#subList(int, int) sublists} of a list, each of the same size (the final list may be smaller). For example, partitioning a
457     * list containing {@code [a, b, c, d, e]} with a partition size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer list containing two inner lists of
458     * three and two elements, all in the original order.
459     * <p>
460     * The outer list is unmodifiable, but reflects the latest state of the source list. The inner lists are sublist views of the original list, produced on
461     * demand using {@link List#subList(int, int)}, and are subject to all the usual caveats about modification as explained in that API.
462     * </p>
463     * <p>
464     * Adapted from https://github.com/google/guava
465     * </p>
466     *
467     * @param <T>  The element type.
468     * @param list The list to return consecutive sublists of.
469     * @param size The desired size of each sublist (the last may be smaller).
470     * @return A list of consecutive sublists.
471     * @throws NullPointerException     if list is null.
472     * @throws IllegalArgumentException if size is not strictly positive.
473     * @since 4.0
474     */
475    public static <T> List<List<T>> partition(final List<T> list, final int size) {
476        Objects.requireNonNull(list, "list");
477        if (size <= 0) {
478            throw new IllegalArgumentException("Size must be greater than 0");
479        }
480        return new Partition<>(list, size);
481    }
482
483    /**
484     * Returns a predicated (validating) list backed by the given list.
485     * <p>
486     * Only objects that pass the test in the given predicate can be added to the list. Trying to add an invalid object results in an IllegalArgumentException.
487     * It is important not to use the original list after invoking this method, as it is a backdoor for adding invalid objects.
488     * </p>
489     *
490     * @param <E>       The element type.
491     * @param list      The list to predicate, must not be null.
492     * @param predicate The predicate for the list, must not be null.
493     * @return A predicated list backed by the given list.
494     * @throws NullPointerException if the List or Predicate is null.
495     */
496    public static <E> List<E> predicatedList(final List<E> list, final Predicate<E> predicate) {
497        return PredicatedList.predicatedList(list, predicate);
498    }
499
500    /**
501     * Removes the elements in {@code remove} from {@code collection}. That is, this method returns a list containing all the elements in {@code collection}
502     * that are not in {@code remove}. The cardinality of an element {@code e} in the returned collection is the same as the cardinality of {@code e} in
503     * {@code collection} unless {@code remove} contains {@code e}, in which case the cardinality is zero. This method is useful if you do not wish to modify
504     * {@code collection} and thus cannot call {@code collection.removeAll(remove);}.
505     * <p>
506     * This implementation iterates over {@code collection}, checking each element in turn to see if it's contained in {@code remove}. If it's not contained,
507     * it's added to the returned list. As a consequence, it is advised to use a collection type for {@code remove} that provides a fast (for example O(1))
508     * implementation of {@link Collection#contains(Object)}.
509     * </p>
510     *
511     * @param <E>        the element type.
512     * @param collection The collection from which items are removed (in the returned collection).
513     * @param remove     The items to be removed from the returned {@code collection}.
514     * @return A {@code List} containing all the elements of {@code c} except any elements that also occur in {@code remove}.
515     * @throws NullPointerException if either parameter is null.
516     * @since 3.2
517     */
518    public static <E> List<E> removeAll(final Collection<E> collection, final Collection<?> remove) {
519        Objects.requireNonNull(collection, "collection");
520        Objects.requireNonNull(remove, "remove");
521        final List<E> list = new ArrayList<>();
522        for (final E obj : collection) {
523            if (!remove.contains(obj)) {
524                list.add(obj);
525            }
526        }
527        return list;
528    }
529
530    /**
531     * Returns a List containing all the elements in {@code collection} that are also in {@code retain}. The cardinality of an element {@code e} in the returned
532     * list is the same as the cardinality of {@code e} in {@code collection} unless {@code retain} does not contain {@code e}, in which case the cardinality is
533     * zero. This method is useful if you do not wish to modify the collection {@code c} and thus cannot call {@code collection.retainAll(retain);}.
534     * <p>
535     * This implementation iterates over {@code collection}, checking each element in turn to see if it's contained in {@code retain}. If it's contained, it's
536     * added to the returned list. As a consequence, it is advised to use a collection type for {@code retain} that provides a fast (for example O(1))
537     * implementation of {@link Collection#contains(Object)}.
538     * </p>
539     *
540     * @param <E>        the element type.
541     * @param collection The collection whose contents are the target of the #retailAll operation.
542     * @param retain     The collection containing the elements to be retained in the returned collection.
543     * @return A {@code List} containing all the elements of {@code c} that occur at least once in {@code retain}.
544     * @throws NullPointerException if either parameter is null.
545     * @since 3.2
546     */
547    public static <E> List<E> retainAll(final Collection<E> collection, final Collection<?> retain) {
548        final List<E> list = new ArrayList<>(Math.min(collection.size(), retain.size()));
549        for (final E obj : collection) {
550            if (retain.contains(obj)) {
551                list.add(obj);
552            }
553        }
554        return list;
555    }
556
557    /**
558     * Selects all elements from input collection which match the given predicate into an output list.
559     * <p>
560     * A {@code null} predicate matches no elements.
561     * </p>
562     *
563     * @param <E>             The element type.
564     * @param inputCollection The collection to get the input from, may not be null.
565     * @param predicate       The predicate to use, may be null.
566     * @return The elements matching the predicate (new list).
567     * @throws NullPointerException if the input list is null
568     * @since 4.0
569     * @see CollectionUtils#select(Iterable, Predicate)
570     */
571    public static <E> List<E> select(final Collection<? extends E> inputCollection, final Predicate<? super E> predicate) {
572        return CollectionUtils.select(inputCollection, predicate, new ArrayList<>(inputCollection.size()));
573    }
574
575    /**
576     * Selects all elements from inputCollection which don't match the given predicate into an output collection.
577     * <p>
578     * If the input predicate is {@code null}, the result is an empty list.
579     * </p>
580     *
581     * @param <E>             The element type.
582     * @param inputCollection The collection to get the input from, may not be null.
583     * @param predicate       The predicate to use, may be null.
584     * @return The elements <strong>not</strong> matching the predicate (new list).
585     * @throws NullPointerException if the input collection is null.
586     * @since 4.0
587     * @see CollectionUtils#selectRejected(Iterable, Predicate)
588     */
589    public static <E> List<E> selectRejected(final Collection<? extends E> inputCollection, final Predicate<? super E> predicate) {
590        return CollectionUtils.selectRejected(inputCollection, predicate, new ArrayList<>(inputCollection.size()));
591    }
592
593    /**
594     * Subtracts all elements in the second list from the first list, placing the results in a new list.
595     * <p>
596     * This differs from {@link List#removeAll(Collection)} in that cardinality is respected; if <Code>list1</Code> contains two occurrences of
597     * <Code>null</Code> and <Code>list2</Code> only contains one occurrence, then the returned list will still contain one occurrence.
598     * </p>
599     *
600     * @param <E>   The element type.
601     * @param list1 The list to subtract from.
602     * @param list2 The list to subtract.
603     * @return A new list containing the results.
604     * @throws NullPointerException if either list is null.
605     */
606    public static <E> List<E> subtract(final List<E> list1, final List<? extends E> list2) {
607        final ArrayList<E> result = new ArrayList<>();
608        final HashMultiSet<E> multiSet = new HashMultiSet<>(list2);
609        for (final E e : list1) {
610            if (multiSet.remove(e, 1) == 0) {
611                result.add(e);
612            }
613        }
614        return result;
615    }
616
617    /**
618     * Returns the sum of the given lists. This is their intersection subtracted from their union.
619     *
620     * @param <E>   The element type.
621     * @param list1 The first list.
622     * @param list2 The second list.
623     * @return a new list containing the sum of those lists.
624     * @throws NullPointerException if either list is null.
625     */
626    public static <E> List<E> sum(final List<? extends E> list1, final List<? extends E> list2) {
627        return subtract(union(list1, list2), intersection(list1, list2));
628    }
629
630    /**
631     * Returns a synchronized list backed by the given list.
632     * <p>
633     * You must manually synchronize on the returned list's iterator to avoid non-deterministic behavior:
634     * </p>
635     *
636     * <pre>
637     * List list = ListUtils.synchronizedList(myList);
638     * synchronized (list) {
639     *     Iterator i = list.iterator();
640     *     while (i.hasNext()) {
641     *         process(i.next());
642     *     }
643     * }
644     * </pre>
645     * <p>
646     * This method is just a wrapper for {@link Collections#synchronizedList(List)}.
647     * </p>
648     *
649     * @param <E>  The element type.
650     * @param list The list to synchronize, must not be null.
651     * @return A synchronized list backed by the given list.
652     * @throws NullPointerException if the list is null.
653     */
654    public static <E> List<E> synchronizedList(final List<E> list) {
655        return Collections.synchronizedList(list);
656    }
657
658    /**
659     * Returns a transformed list backed by the given list.
660     * <p>
661     * This method returns a new list (decorating the specified list) that will transform any new entries added to it. Existing entries in the specified list
662     * will not be transformed.
663     * </p>
664     * <p>
665     * Each object is passed through the transformer as it is added to the List. It is important not to use the original list after invoking this method, as it
666     * is a backdoor for adding untransformed objects.
667     * </p>
668     * <p>
669     * Existing entries in the specified list will not be transformed. If you want that behavior, see {@link TransformedList#transformedList}.
670     * </p>
671     *
672     * @param <E>         The element type.
673     * @param list        The list to predicate, must not be null.
674     * @param transformer The transformer for the list, must not be null.
675     * @return A transformed list backed by the given list.
676     * @throws NullPointerException if the List or Transformer is null.
677     */
678    public static <E> List<E> transformedList(final List<E> list, final Transformer<? super E, ? extends E> transformer) {
679        return TransformedList.transformingList(list, transformer);
680    }
681
682    /**
683     * Returns a new list containing the second list appended to the first list. The {@link List#addAll(Collection)} operation is used to append the two given
684     * lists into a new list.
685     *
686     * @param <E>   The element type.
687     * @param list1 The first list.
688     * @param list2 The second list.
689     * @return A new list containing the union of those lists.
690     * @throws NullPointerException if either list is null.
691     */
692    public static <E> List<E> union(final List<? extends E> list1, final List<? extends E> list2) {
693        final ArrayList<E> result = new ArrayList<>(list1.size() + list2.size());
694        result.addAll(list1);
695        result.addAll(list2);
696        return result;
697    }
698
699    /**
700     * Returns an unmodifiable list backed by the given list.
701     * <p>
702     * This method uses the implementation in the decorators subpackage.
703     * </p>
704     *
705     * @param <E>  the element type.
706     * @param list The list to make unmodifiable, must not be null.
707     * @return An unmodifiable list backed by the given list.
708     * @throws NullPointerException if the list is null.
709     */
710    public static <E> List<E> unmodifiableList(final List<? extends E> list) {
711        return UnmodifiableList.unmodifiableList(list);
712    }
713
714    /**
715     * Don't allow instances.
716     */
717    private ListUtils() {
718        // empty
719    }
720}