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