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 (e.g. filter(Predicate));
039 *   <li>conversion methods which copy the FluentIterable's contents into a
040 *       new collection or array (e.g. toList());
041 *   <li>utility methods which answer questions about the FluentIterable's
042 *       contents (e.g. 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     * Returns 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}