    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 *      http://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 */
    017package org.apache.commons.collections4;
    018
    019import java.util.Arrays;
    020import java.util.Collection;
    021import java.util.Comparator;
    022import java.util.Enumeration;
    023import java.util.Iterator;
    024import java.util.List;
    025import java.util.Objects;
    026
    027import org.apache.commons.collections4.iterators.SingletonIterator;
    028
    029/**
    030 * A FluentIterable provides a powerful yet simple API for manipulating
    031 * Iterable instances in a fluent manner.
    032 * <p>
    033 * A FluentIterable can be created either from an Iterable or from a set
    034 * of elements. The following types of methods are provided:
    035 * </p>
    036 * <ul>
    037 *   <li>fluent methods which return a new {@code FluentIterable} instance,
    038 *       providing a view of the original iterable (for example filter(Predicate));
    039 *   <li>conversion methods which copy the FluentIterable's contents into a
    040 *       new collection or array (for example toList());
    041 *   <li>utility methods which answer questions about the FluentIterable's
    042 *       contents (for example size(), anyMatch(Predicate)).
    043 *   <li>
    044 * </ul>
    045 * <p>
    046 * The following example outputs the first 3 even numbers in the range [1, 10]
    047 * into a list:
    048 * </p>
    049 * <pre>
    050 * List&lt;String&gt; result =
    051 *   FluentIterable
    052 *       .of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    053 *       .filter(new Predicate&lt;Integer&gt;() {
    054 *                   public boolean evaluate(Integer number) {
    055 *                        return number % 2 == 0;
    056 *                   }
    057 *              )
    058 *       .transform(TransformerUtils.stringValueTransformer())
    059 *       .limit(3)
    060 *       .toList();
    061 * </pre>
    062 * The resulting list will contain the following elements:
    063 * <pre>[2, 4, 6]</pre>
    064 *
    065 * @param <E>  the element type
    066 * @since 4.1
    067 */
    068public class FluentIterable<E> implements Iterable<E> {
    069
    070    /**
    071     * Creates a new empty FluentIterable.
    072     *
    073     * @param <T>  the element type
    074     * @return a new empty FluentIterable
    075     */
    076    public static <T> FluentIterable<T> empty() {
    077        return IterableUtils.EMPTY_ITERABLE;
    078    }
    079
    080    /**
    081     * Constructs a new FluentIterable from the provided iterable. If the
    082     * iterable is already an instance of FluentIterable, the instance
    083     * will be returned instead.
    084     * <p>
    085     * The returned iterable's iterator supports {@code remove()} when the
    086     * corresponding input iterator supports it.
    087     * </p>
    088     *
    089     * @param <T>  the element type
    090     * @param iterable  the iterable to wrap into a FluentIterable, may not be null
    091     * @return a new FluentIterable wrapping the provided iterable
    092     * @throws NullPointerException if iterable is null
    093     */
    094    public static <T> FluentIterable<T> of(final Iterable<T> iterable) {
    095        Objects.requireNonNull(iterable, "iterable");
    096        if (iterable instanceof FluentIterable<?>) {
    097            return (FluentIterable<T>) iterable;
    098        }
    099        return new FluentIterable<>(iterable);
    100    }
    101
    102    /**
    103     * Creates a new FluentIterable of the single provided element.
    104     * <p>
    105     * The returned iterable's iterator does not support {@code remove()}.
    106     * </p>
    107     *
    108     * @param <T>  the element type
    109     * @param singleton  the singleton element
    110     * @return a new FluentIterable containing the singleton
    111     */
    112    public static <T> FluentIterable<T> of(final T singleton) {
    113        return of(IteratorUtils.asIterable(new SingletonIterator<>(singleton, false)));
    114    }
    115
    116    /**
    117     * Creates a new FluentIterable from the provided elements.
    118     * <p>
    119     * The returned iterable's iterator does not support {@code remove()}.
    120     * </p>
    121     *
    122     * @param <T>  the element type
    123     * @param elements  the elements to be contained in the FluentIterable
    124     * @return a new FluentIterable containing the provided elements
    125     */
    126    public static <T> FluentIterable<T> of(final T... elements) {
    127        return of(Arrays.asList(elements));
    128    }
    129
    130    /** A reference to the wrapped iterable. */
    131    private final Iterable<E> iterable;
    132
    133    /**
    134     * Don't allow instances.
    135     */
    136    FluentIterable() {
    137        iterable = this;
    138    }
    139
    140    /**
    141     * Create a new FluentIterable by wrapping the provided iterable.
    142     * @param iterable  the iterable to wrap
    143     */
    144    private FluentIterable(final Iterable<E> iterable) {
    145        this.iterable = iterable;
    146    }
    147
    148    /**
    149     * Checks if all elements contained in this iterable are matching the
    150     * provided predicate.
    151     * <p>
    152     * A {@code null} or empty iterable returns true.
    153     * </p>
    154     *
    155     * @param predicate  the predicate to use, may not be null
    156     * @return true if all elements contained in this iterable match the predicate,
    157     *   false otherwise
    158     * @throws NullPointerException if predicate is null
    159     */
    160    public boolean allMatch(final Predicate<? super E> predicate) {
    161        return IterableUtils.matchesAll(iterable, predicate);
    162    }
    163
    164    /**
    165     * Checks if this iterable contains any element matching the provided predicate.
    166     * <p>
    167     * A {@code null} or empty iterable returns false.
    168     * </p>
    169     *
    170     * @param predicate  the predicate to use, may not be null
    171     * @return true if at least one element contained in this iterable matches the predicate,
    172     *   false otherwise
    173     * @throws NullPointerException if predicate is null
    174     */
    175    public boolean anyMatch(final Predicate<? super E> predicate) {
    176        return IterableUtils.matchesAny(iterable, predicate);
    177    }
    178
    179    /**
    180     * Returns a new FluentIterable whose iterator will first traverse
    181     * the elements of the current iterable, followed by the provided
    182     * elements.
    183     *
    184     * @param elements  the elements to append to the iterable
    185     * @return a new iterable, combining this iterable with the elements
    186     */
    187    public FluentIterable<E> append(final E... elements) {
    188        return append(Arrays.asList(elements));
    189    }
    190
    191    /**
    192     * Returns a new FluentIterable whose iterator will first traverse
    193     * the elements of the current iterable, followed by the elements
    194     * of the provided iterable.
    195     *
    196     * @param other  the other iterable to combine, may not be null
    197     * @return a new iterable, combining this iterable with other
    198     * @throws NullPointerException if other is null
    199     */
    200    public FluentIterable<E> append(final Iterable<? extends E> other) {
    201        return of(IterableUtils.chainedIterable(iterable, other));
    202    }
    203
    204    /**
    205     * Returns an Enumeration that will enumerate all elements contained
    206     * in this iterable.
    207     *
    208     * @return an Enumeration over the elements of this iterable
    209     */
    210    public Enumeration<E> asEnumeration() {
    211        return IteratorUtils.asEnumeration(iterator());
    212    }
    213
    214    /**
    215     * Returns a new FluentIterable whose iterator will traverse the
    216     * elements of the current and provided iterable in natural order.
    217     * <p>
    218     * Example: natural ordering
    219     * </p>
    220     * <ul>
    221     *   <li>this contains elements [1, 3, 5, 7]
    222     *   <li>other contains elements [2, 4, 6, 8]
    223     * </ul>
    224     * <p>
    225     * The returned iterable will traverse the elements in the following
    226     * order: [1, 2, 3, 4, 5, 6, 7, 8]
    227     * </p>
    228     *
    229     * @param other  the other iterable to collate, may not be null
    230     * @return a new iterable, collating this iterable with the other in natural order
    231     * @throws NullPointerException if other is null
    232     * @see org.apache.commons.collections4.iterators.CollatingIterator
    233     */
    234    public FluentIterable<E> collate(final Iterable<? extends E> other) {
    235        return of(IterableUtils.collatedIterable(iterable, other));
    236    }
    237
    238    /**
    239     * Returns a new FluentIterable whose iterator will traverse the
    240     * elements of the current and provided iterable according to the
    241     * ordering defined by a comparator.
    242     * <p>
    243     * Example: descending order
    244     * </p>
    245     * <ul>
    246     *   <li>this contains elements [7, 5, 3, 1]
    247     *   <li>other contains elements [8, 6, 4, 2]
    248     * </ul>
    249     * <p>
    250     * The returned iterable will traverse the elements in the following
    251     * order: [8, 7, 6, 5, 4, 3, 2, 1]
    252     * </p>
    253     *
    254     * @param comparator  the comparator to define an ordering, may be null,
    255     *   in which case natural ordering will be used
    256     * @param other  the other iterable to collate, may not be null
    257     * @return a new iterable, collating this iterable with the other in natural order
    258     * @throws NullPointerException if other is null
    259     * @see org.apache.commons.collections4.iterators.CollatingIterator
    260     */
    261    public FluentIterable<E> collate(final Iterable<? extends E> other,
    262                                     final Comparator<? super E> comparator) {
    263        return of(IterableUtils.collatedIterable(comparator, iterable, other));
    264    }
    265
    266    /**
    267     * Checks if the object is contained in this iterable.
    268     *
    269     * @param object  the object to check
    270     * @return true if the object is contained in this iterable, false otherwise
    271     */
    272    public boolean contains(final Object object) {
    273        return IterableUtils.contains(iterable, object);
    274    }
    275
    276    /**
    277     * Traverses an iterator of this iterable and adds all elements
    278     * to the provided collection.
    279     *
    280     * @param collection  the collection to add the elements
    281     * @throws NullPointerException if collection is null
    282     */
    283    public void copyInto(final Collection<? super E> collection) {
    284        Objects.requireNonNull(collection, "collection");
    285        CollectionUtils.addAll(collection, iterable);
    286    }
    287
    288    /**
    289     * This method fully traverses an iterator of this iterable and returns
    290     * a new iterable with the same contents, but without any reference
    291     * to the originating iterables and/or iterators.
    292     * <p>
    293     * Calling this method is equivalent to:
    294     * </p>
    295     * <pre>
    296     *   FluentIterable&lt;E&gt; someIterable = ...;
    297     *   FluentIterable.of(someIterable.toList());
    298     * </pre>
    299     *
    300     * @return a new iterable with the same contents as this iterable
    301     */
    302    public FluentIterable<E> eval() {
    303        return of(toList());
    304    }
    305
    306    /**
    307     * Returns a new FluentIterable whose iterator will only return
    308     * elements from this iterable matching the provided predicate.
    309     *
    310     * @param predicate  the predicate used to filter elements
    311     * @return a new iterable, providing a filtered view of this iterable
    312     * @throws NullPointerException if predicate is null
    313     */
    314    public FluentIterable<E> filter(final Predicate<? super E> predicate) {
    315        return of(IterableUtils.filteredIterable(iterable, predicate));
    316    }
    317
    318    /**
    319     * Applies the closure to all elements contained in this iterable.
    320     *
    321     * @param closure  the closure to apply to each element, may not be null
    322     * @throws NullPointerException if closure is null
    323     */
    324    public void forEach(final Closure<? super E> closure) {
    325        IterableUtils.forEach(iterable, closure);
    326    }
    327
    328    /**
    329     * Gets the element at the provided position in this iterable.
    330     * In order to return the element, an iterator needs to be traversed
    331     * up to the requested position.
    332     *
    333     * @param position  the position of the element to return
    334     * @return the element
    335     * @throws IndexOutOfBoundsException if the provided position is outside the
    336     *   valid range of this iterable: [0, size)
    337     */
    338    public E get(final int position) {
    339        return IterableUtils.get(iterable, position);
    340    }
    341
    342    /**
    343     * Checks if this iterable is empty.
    344     *
    345     * @return true if this iterable does not contain any elements, false otherwise
    346     */
    347    public boolean isEmpty() {
    348        return IterableUtils.isEmpty(iterable);
    349    }
    350
    351    /** {@inheritDoc} */
    352    @Override
    353    public Iterator<E> iterator() {
    354        return iterable.iterator();
    355    }
    356
    357    /**
    358     * Returns a new FluentIterable whose iterator will return at most
    359     * the provided maximum number of elements from this iterable.
    360     *
    361     * @param maxSize  the maximum number of elements
    362     * @return a new iterable, providing a bounded view of this iterable
    363     * @throws IllegalArgumentException if maxSize is negative
    364     */
    365    public FluentIterable<E> limit(final long maxSize) {
    366        return of(IterableUtils.boundedIterable(iterable, maxSize));
    367    }
    368
    369    /**
    370     * Returns a new FluentIterable whose iterator will loop infinitely
    371     * over the elements from this iterable.
    372     *
    373     * @return a new iterable, providing a looping view of this iterable
    374     */
    375    public FluentIterable<E> loop() {
    376        return of(IterableUtils.loopingIterable(iterable));
    377    }
    378
    379    /**
    380     * Returns a new FluentIterable whose iterator will traverse the
    381     * elements from this iterable in reverse order.
    382     *
    383     * @return a new iterable, providing a reversed view of this iterable
    384     */
    385    public FluentIterable<E> reverse() {
    386        return of(IterableUtils.reversedIterable(iterable));
    387    }
    388
    389    /**
    390     * Returns the number of elements that are contained in this iterable.
    391     * In order to determine the size, an iterator needs to be traversed.
    392     *
    393     * @return the size of this iterable
    394     */
    395    public int size() {
    396        return IterableUtils.size(iterable);
    397    }
    398
    399    /**
    400     * Returns a new FluentIterable whose iterator will skip the first
    401     * N elements from this iterable.
    402     *
    403     * @param elementsToSkip  the number of elements to skip
    404     * @return a new iterable, providing a view of this iterable by skipping
    405     *   the first N elements
    406     * @throws IllegalArgumentException if elementsToSkip is negative
    407     */
    408    public FluentIterable<E> skip(final long elementsToSkip) {
    409        return of(IterableUtils.skippingIterable(iterable, elementsToSkip));
    410    }
    411
    412    /**
    413     * Returns an array containing all elements of this iterable by traversing
    414     * its iterator.
    415     *
    416     * @param arrayClass  the class of array to create
    417     * @return an array of the iterable contents
    418     * @throws ArrayStoreException if arrayClass is invalid
    419     */
    420    public E[] toArray(final Class<E> arrayClass) {
    421        return IteratorUtils.toArray(iterator(), arrayClass);
    422    }
    423
    424    /**
    425     * Returns a mutable list containing all elements of this iterable
    426     * by traversing its iterator.
    427     * <p>
    428     * The returned list is guaranteed to be mutable.
    429     * </p>
    430     *
    431     * @return a list of the iterable contents
    432     */
    433    public List<E> toList() {
    434        return IterableUtils.toList(iterable);
    435    }
    436
    437    /** {@inheritDoc} */
    438    @Override
    439    public String toString() {
    440        return IterableUtils.toString(iterable);
    441    }
    442
    443    /**
    444     * Returns a new FluentIterable whose iterator will return all elements
    445     * of this iterable transformed by the provided transformer.
    446     *
    447     * @param <O>  the output element type
    448     * @param transformer  the transformer applied to each element
    449     * @return a new iterable, providing a transformed view of this iterable
    450     * @throws NullPointerException if transformer is null
    451     */
    452    public <O> FluentIterable<O> transform(final Transformer<? super E, ? extends O> transformer) {
    453        return of(IterableUtils.transformedIterable(iterable, transformer));
    454    }
    455
    456    /**
    457     * Returns a new FluentIterable whose iterator will return a unique view
    458     * of this iterable.
    459     *
    460     * @return a new iterable, providing a unique view of this iterable
    461     */
    462    public FluentIterable<E> unique() {
    463        return of(IterableUtils.uniqueIterable(iterable));
    464    }
    465
    466    /**
    467     * Returns a new FluentIterable whose iterator will return an unmodifiable
    468     * view of this iterable.
    469     *
    470     * @return a new iterable, providing an unmodifiable view of this iterable
    471     */
    472    public FluentIterable<E> unmodifiable() {
    473        return of(IterableUtils.unmodifiableIterable(iterable));
    474    }
    475
    476    /**
    477     * Returns a new FluentIterable whose iterator will traverse
    478     * the elements of this iterable and the other iterable in
    479     * alternating order.
    480     *
    481     * @param other  the other iterable to interleave, may not be null
    482     * @return a new iterable, interleaving this iterable with others
    483     * @throws NullPointerException if other is null
    484     */
    485    public FluentIterable<E> zip(final Iterable<? extends E> other) {
    486        return of(IterableUtils.zippingIterable(iterable, other));
    487    }
    488
    489    /**
    490     * Returns a new FluentIterable whose iterator will traverse
    491     * the elements of this iterable and the other iterables in
    492     * alternating order.
    493     *
    494     * @param others  the iterables to interleave, may not be null
    495     * @return a new iterable, interleaving this iterable with others
    496     * @throws NullPointerException if either of the provided iterables is null
    497     */
    498    public FluentIterable<E> zip(final Iterable<? extends E>... others) {
    499        return of(IterableUtils.zippingIterable(iterable, others));
    500    }
    501
    502}