FluentIterable.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.collections4;

  18. import java.util.Arrays;
  19. import java.util.Collection;
  20. import java.util.Comparator;
  21. import java.util.Enumeration;
  22. import java.util.Iterator;
  23. import java.util.List;
  24. import java.util.Objects;

  25. import org.apache.commons.collections4.iterators.SingletonIterator;

  26. /**
  27.  * A FluentIterable provides a powerful yet simple API for manipulating
  28.  * Iterable instances in a fluent manner.
  29.  * <p>
  30.  * A FluentIterable can be created either from an Iterable or from a set
  31.  * of elements. The following types of methods are provided:
  32.  * </p>
  33.  * <ul>
  34.  *   <li>fluent methods which return a new {@code FluentIterable} instance,
  35.  *       providing a view of the original iterable (for example filter(Predicate));
  36.  *   <li>conversion methods which copy the FluentIterable's contents into a
  37.  *       new collection or array (for example toList());
  38.  *   <li>utility methods which answer questions about the FluentIterable's
  39.  *       contents (for example size(), anyMatch(Predicate)).
  40.  *   <li>
  41.  * </ul>
  42.  * <p>
  43.  * The following example outputs the first 3 even numbers in the range [1, 10]
  44.  * into a list:
  45.  * </p>
  46.  * <pre>
  47.  * List&lt;String&gt; result =
  48.  *   FluentIterable
  49.  *       .of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
  50.  *       .filter(new Predicate&lt;Integer&gt;() {
  51.  *                   public boolean evaluate(Integer number) {
  52.  *                        return number % 2 == 0;
  53.  *                   }
  54.  *              )
  55.  *       .transform(TransformerUtils.stringValueTransformer())
  56.  *       .limit(3)
  57.  *       .toList();
  58.  * </pre>
  59.  * The resulting list will contain the following elements:
  60.  * <pre>[2, 4, 6]</pre>
  61.  *
  62.  * @param <E>  the element type
  63.  * @since 4.1
  64.  */
  65. public class FluentIterable<E> implements Iterable<E> {

  66.     /**
  67.      * Creates a new empty FluentIterable.
  68.      *
  69.      * @param <T>  the element type
  70.      * @return a new empty FluentIterable
  71.      */
  72.     public static <T> FluentIterable<T> empty() {
  73.         return IterableUtils.EMPTY_ITERABLE;
  74.     }

  75.     /**
  76.      * Constructs a new FluentIterable from the provided iterable. If the
  77.      * iterable is already an instance of FluentIterable, the instance
  78.      * will be returned instead.
  79.      * <p>
  80.      * The returned iterable's iterator supports {@code remove()} when the
  81.      * corresponding input iterator supports it.
  82.      * </p>
  83.      *
  84.      * @param <T>  the element type
  85.      * @param iterable  the iterable to wrap into a FluentIterable, may not be null
  86.      * @return a new FluentIterable wrapping the provided iterable
  87.      * @throws NullPointerException if iterable is null
  88.      */
  89.     public static <T> FluentIterable<T> of(final Iterable<T> iterable) {
  90.         Objects.requireNonNull(iterable, "iterable");
  91.         if (iterable instanceof FluentIterable<?>) {
  92.             return (FluentIterable<T>) iterable;
  93.         }
  94.         return new FluentIterable<>(iterable);
  95.     }

  96.     /**
  97.      * Creates a new FluentIterable of the single provided element.
  98.      * <p>
  99.      * The returned iterable's iterator does not support {@code remove()}.
  100.      * </p>
  101.      *
  102.      * @param <T>  the element type
  103.      * @param singleton  the singleton element
  104.      * @return a new FluentIterable containing the singleton
  105.      */
  106.     public static <T> FluentIterable<T> of(final T singleton) {
  107.         return of(IteratorUtils.asIterable(new SingletonIterator<>(singleton, false)));
  108.     }

  109.     /**
  110.      * Creates a new FluentIterable from the provided elements.
  111.      * <p>
  112.      * The returned iterable's iterator does not support {@code remove()}.
  113.      * </p>
  114.      *
  115.      * @param <T>  the element type
  116.      * @param elements  the elements to be contained in the FluentIterable
  117.      * @return a new FluentIterable containing the provided elements
  118.      */
  119.     public static <T> FluentIterable<T> of(final T... elements) {
  120.         return of(Arrays.asList(elements));
  121.     }

  122.     /** A reference to the wrapped iterable. */
  123.     private final Iterable<E> iterable;

  124.     /**
  125.      * Don't allow instances.
  126.      */
  127.     FluentIterable() {
  128.         iterable = this;
  129.     }

  130.     /**
  131.      * Create a new FluentIterable by wrapping the provided iterable.
  132.      * @param iterable  the iterable to wrap
  133.      */
  134.     private FluentIterable(final Iterable<E> iterable) {
  135.         this.iterable = iterable;
  136.     }

  137.     /**
  138.      * Checks if all elements contained in this iterable are matching the
  139.      * provided predicate.
  140.      * <p>
  141.      * A {@code null} or empty iterable returns true.
  142.      * </p>
  143.      *
  144.      * @param predicate  the predicate to use, may not be null
  145.      * @return true if all elements contained in this iterable match the predicate,
  146.      *   false otherwise
  147.      * @throws NullPointerException if predicate is null
  148.      */
  149.     public boolean allMatch(final Predicate<? super E> predicate) {
  150.         return IterableUtils.matchesAll(iterable, predicate);
  151.     }

  152.     /**
  153.      * Checks if this iterable contains any element matching the provided predicate.
  154.      * <p>
  155.      * A {@code null} or empty iterable returns false.
  156.      * </p>
  157.      *
  158.      * @param predicate  the predicate to use, may not be null
  159.      * @return true if at least one element contained in this iterable matches the predicate,
  160.      *   false otherwise
  161.      * @throws NullPointerException if predicate is null
  162.      */
  163.     public boolean anyMatch(final Predicate<? super E> predicate) {
  164.         return IterableUtils.matchesAny(iterable, predicate);
  165.     }

  166.     /**
  167.      * Returns a new FluentIterable whose iterator will first traverse
  168.      * the elements of the current iterable, followed by the provided
  169.      * elements.
  170.      *
  171.      * @param elements  the elements to append to the iterable
  172.      * @return a new iterable, combining this iterable with the elements
  173.      */
  174.     public FluentIterable<E> append(final E... elements) {
  175.         return append(Arrays.asList(elements));
  176.     }

  177.     /**
  178.      * Returns a new FluentIterable whose iterator will first traverse
  179.      * the elements of the current iterable, followed by the elements
  180.      * of the provided iterable.
  181.      *
  182.      * @param other  the other iterable to combine, may not be null
  183.      * @return a new iterable, combining this iterable with other
  184.      * @throws NullPointerException if other is null
  185.      */
  186.     public FluentIterable<E> append(final Iterable<? extends E> other) {
  187.         return of(IterableUtils.chainedIterable(iterable, other));
  188.     }

  189.     /**
  190.      * Returns an Enumeration that will enumerate all elements contained
  191.      * in this iterable.
  192.      *
  193.      * @return an Enumeration over the elements of this iterable
  194.      */
  195.     public Enumeration<E> asEnumeration() {
  196.         return IteratorUtils.asEnumeration(iterator());
  197.     }

  198.     /**
  199.      * Returns a new FluentIterable whose iterator will traverse the
  200.      * elements of the current and provided iterable in natural order.
  201.      * <p>
  202.      * Example: natural ordering
  203.      * </p>
  204.      * <ul>
  205.      *   <li>this contains elements [1, 3, 5, 7]
  206.      *   <li>other contains elements [2, 4, 6, 8]
  207.      * </ul>
  208.      * <p>
  209.      * The returned iterable will traverse the elements in the following
  210.      * order: [1, 2, 3, 4, 5, 6, 7, 8]
  211.      * </p>
  212.      *
  213.      * @param other  the other iterable to collate, may not be null
  214.      * @return a new iterable, collating this iterable with the other in natural order
  215.      * @throws NullPointerException if other is null
  216.      * @see org.apache.commons.collections4.iterators.CollatingIterator
  217.      */
  218.     public FluentIterable<E> collate(final Iterable<? extends E> other) {
  219.         return of(IterableUtils.collatedIterable(iterable, other));
  220.     }

  221.     /**
  222.      * Returns a new FluentIterable whose iterator will traverse the
  223.      * elements of the current and provided iterable according to the
  224.      * ordering defined by a comparator.
  225.      * <p>
  226.      * Example: descending order
  227.      * </p>
  228.      * <ul>
  229.      *   <li>this contains elements [7, 5, 3, 1]
  230.      *   <li>other contains elements [8, 6, 4, 2]
  231.      * </ul>
  232.      * <p>
  233.      * The returned iterable will traverse the elements in the following
  234.      * order: [8, 7, 6, 5, 4, 3, 2, 1]
  235.      * </p>
  236.      *
  237.      * @param comparator  the comparator to define an ordering, may be null,
  238.      *   in which case natural ordering will be used
  239.      * @param other  the other iterable to collate, may not be null
  240.      * @return a new iterable, collating this iterable with the other in natural order
  241.      * @throws NullPointerException if other is null
  242.      * @see org.apache.commons.collections4.iterators.CollatingIterator
  243.      */
  244.     public FluentIterable<E> collate(final Iterable<? extends E> other,
  245.                                      final Comparator<? super E> comparator) {
  246.         return of(IterableUtils.collatedIterable(comparator, iterable, other));
  247.     }

  248.     /**
  249.      * Checks if the object is contained in this iterable.
  250.      *
  251.      * @param object  the object to check
  252.      * @return true if the object is contained in this iterable, false otherwise
  253.      */
  254.     public boolean contains(final Object object) {
  255.         return IterableUtils.contains(iterable, object);
  256.     }

  257.     /**
  258.      * Traverses an iterator of this iterable and adds all elements
  259.      * to the provided collection.
  260.      *
  261.      * @param collection  the collection to add the elements
  262.      * @throws NullPointerException if collection is null
  263.      */
  264.     public void copyInto(final Collection<? super E> collection) {
  265.         Objects.requireNonNull(collection, "collection");
  266.         CollectionUtils.addAll(collection, iterable);
  267.     }

  268.     /**
  269.      * This method fully traverses an iterator of this iterable and returns
  270.      * a new iterable with the same contents, but without any reference
  271.      * to the originating iterables and/or iterators.
  272.      * <p>
  273.      * Calling this method is equivalent to:
  274.      * </p>
  275.      * <pre>
  276.      *   FluentIterable&lt;E&gt; someIterable = ...;
  277.      *   FluentIterable.of(someIterable.toList());
  278.      * </pre>
  279.      *
  280.      * @return a new iterable with the same contents as this iterable
  281.      */
  282.     public FluentIterable<E> eval() {
  283.         return of(toList());
  284.     }

  285.     /**
  286.      * Returns a new FluentIterable whose iterator will only return
  287.      * elements from this iterable matching the provided predicate.
  288.      *
  289.      * @param predicate  the predicate used to filter elements
  290.      * @return a new iterable, providing a filtered view of this iterable
  291.      * @throws NullPointerException if predicate is null
  292.      */
  293.     public FluentIterable<E> filter(final Predicate<? super E> predicate) {
  294.         return of(IterableUtils.filteredIterable(iterable, predicate));
  295.     }

  296.     /**
  297.      * Applies the closure to all elements contained in this iterable.
  298.      *
  299.      * @param closure  the closure to apply to each element, may not be null
  300.      * @throws NullPointerException if closure is null
  301.      */
  302.     public void forEach(final Closure<? super E> closure) {
  303.         IterableUtils.forEach(iterable, closure);
  304.     }

  305.     /**
  306.      * Gets the element at the provided position in this iterable.
  307.      * In order to return the element, an iterator needs to be traversed
  308.      * up to the requested position.
  309.      *
  310.      * @param position  the position of the element to return
  311.      * @return the element
  312.      * @throws IndexOutOfBoundsException if the provided position is outside the
  313.      *   valid range of this iterable: [0, size)
  314.      */
  315.     public E get(final int position) {
  316.         return IterableUtils.get(iterable, position);
  317.     }

  318.     /**
  319.      * Checks if this iterable is empty.
  320.      *
  321.      * @return true if this iterable does not contain any elements, false otherwise
  322.      */
  323.     public boolean isEmpty() {
  324.         return IterableUtils.isEmpty(iterable);
  325.     }

  326.     /** {@inheritDoc} */
  327.     @Override
  328.     public Iterator<E> iterator() {
  329.         return iterable.iterator();
  330.     }

  331.     /**
  332.      * Returns a new FluentIterable whose iterator will return at most
  333.      * the provided maximum number of elements from this iterable.
  334.      *
  335.      * @param maxSize  the maximum number of elements
  336.      * @return a new iterable, providing a bounded view of this iterable
  337.      * @throws IllegalArgumentException if maxSize is negative
  338.      */
  339.     public FluentIterable<E> limit(final long maxSize) {
  340.         return of(IterableUtils.boundedIterable(iterable, maxSize));
  341.     }

  342.     /**
  343.      * Returns a new FluentIterable whose iterator will loop infinitely
  344.      * over the elements from this iterable.
  345.      *
  346.      * @return a new iterable, providing a looping view of this iterable
  347.      */
  348.     public FluentIterable<E> loop() {
  349.         return of(IterableUtils.loopingIterable(iterable));
  350.     }

  351.     /**
  352.      * Returns a new FluentIterable whose iterator will traverse the
  353.      * elements from this iterable in reverse order.
  354.      *
  355.      * @return a new iterable, providing a reversed view of this iterable
  356.      */
  357.     public FluentIterable<E> reverse() {
  358.         return of(IterableUtils.reversedIterable(iterable));
  359.     }

  360.     /**
  361.      * Returns the number of elements that are contained in this iterable.
  362.      * In order to determine the size, an iterator needs to be traversed.
  363.      *
  364.      * @return the size of this iterable
  365.      */
  366.     public int size() {
  367.         return IterableUtils.size(iterable);
  368.     }

  369.     /**
  370.      * Returns a new FluentIterable whose iterator will skip the first
  371.      * N elements from this iterable.
  372.      *
  373.      * @param elementsToSkip  the number of elements to skip
  374.      * @return a new iterable, providing a view of this iterable by skipping
  375.      *   the first N elements
  376.      * @throws IllegalArgumentException if elementsToSkip is negative
  377.      */
  378.     public FluentIterable<E> skip(final long elementsToSkip) {
  379.         return of(IterableUtils.skippingIterable(iterable, elementsToSkip));
  380.     }

  381.     /**
  382.      * Returns an array containing all elements of this iterable by traversing
  383.      * its iterator.
  384.      *
  385.      * @param arrayClass  the class of array to create
  386.      * @return an array of the iterable contents
  387.      * @throws ArrayStoreException if arrayClass is invalid
  388.      */
  389.     public E[] toArray(final Class<E> arrayClass) {
  390.         return IteratorUtils.toArray(iterator(), arrayClass);
  391.     }

  392.     /**
  393.      * Returns a mutable list containing all elements of this iterable
  394.      * by traversing its iterator.
  395.      * <p>
  396.      * The returned list is guaranteed to be mutable.
  397.      * </p>
  398.      *
  399.      * @return a list of the iterable contents
  400.      */
  401.     public List<E> toList() {
  402.         return IterableUtils.toList(iterable);
  403.     }

  404.     /** {@inheritDoc} */
  405.     @Override
  406.     public String toString() {
  407.         return IterableUtils.toString(iterable);
  408.     }

  409.     /**
  410.      * Returns a new FluentIterable whose iterator will return all elements
  411.      * of this iterable transformed by the provided transformer.
  412.      *
  413.      * @param <O>  the output element type
  414.      * @param transformer  the transformer applied to each element
  415.      * @return a new iterable, providing a transformed view of this iterable
  416.      * @throws NullPointerException if transformer is null
  417.      */
  418.     public <O> FluentIterable<O> transform(final Transformer<? super E, ? extends O> transformer) {
  419.         return of(IterableUtils.transformedIterable(iterable, transformer));
  420.     }

  421.     /**
  422.      * Returns a new FluentIterable whose iterator will return a unique view
  423.      * of this iterable.
  424.      *
  425.      * @return a new iterable, providing a unique view of this iterable
  426.      */
  427.     public FluentIterable<E> unique() {
  428.         return of(IterableUtils.uniqueIterable(iterable));
  429.     }

  430.     /**
  431.      * Returns a new FluentIterable whose iterator will return an unmodifiable
  432.      * view of this iterable.
  433.      *
  434.      * @return a new iterable, providing an unmodifiable view of this iterable
  435.      */
  436.     public FluentIterable<E> unmodifiable() {
  437.         return of(IterableUtils.unmodifiableIterable(iterable));
  438.     }

  439.     /**
  440.      * Returns a new FluentIterable whose iterator will traverse
  441.      * the elements of this iterable and the other iterable in
  442.      * alternating order.
  443.      *
  444.      * @param other  the other iterable to interleave, may not be null
  445.      * @return a new iterable, interleaving this iterable with others
  446.      * @throws NullPointerException if other is null
  447.      */
  448.     public FluentIterable<E> zip(final Iterable<? extends E> other) {
  449.         return of(IterableUtils.zippingIterable(iterable, other));
  450.     }

  451.     /**
  452.      * Returns a new FluentIterable whose iterator will traverse
  453.      * the elements of this iterable and the other iterables in
  454.      * alternating order.
  455.      *
  456.      * @param others  the iterables to interleave, may not be null
  457.      * @return a new iterable, interleaving this iterable with others
  458.      * @throws NullPointerException if either of the provided iterables is null
  459.      */
  460.     public FluentIterable<E> zip(final Iterable<? extends E>... others) {
  461.         return of(IterableUtils.zippingIterable(iterable, others));
  462.     }

  463. }