ExtendedIterator.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.iterators;

  18. import java.util.Collections;
  19. import java.util.Iterator;
  20. import java.util.function.Consumer;
  21. import java.util.function.Function;
  22. import java.util.function.Predicate;
  23. import java.util.stream.Stream;

  24. import org.apache.commons.collections4.IteratorUtils;

  25. /**
  26.  * Extends Iterator functionality to include operations commonly found on streams (for example filtering, concatenating, mapping). It also provides convenience methods
  27.  * for common operations.
  28.  *
  29.  * @param <T> The type of object returned from the iterator.
  30.  * @since 4.5.0-M3
  31.  */
  32. public final class ExtendedIterator<T> implements IteratorOperations<T> {

  33.     /**
  34.      * Create an ExtendedIterator returning the elements of <code>it</code>. If <code>it</code> is itself an ExtendedIterator, return that; otherwise wrap
  35.      * <code>it</code>.
  36.      *
  37.      * @param <T> The type of object returned from the iterator.
  38.      * @param it The iterator to wrap.
  39.      * @return An Extended iterator wrapping {@code it}
  40.      */
  41.     public static <T> ExtendedIterator<T> create(final Iterator<T> it) {
  42.         return it instanceof ExtendedIterator<?> ? (ExtendedIterator<T>) it : new ExtendedIterator<>(it, false);
  43.     }

  44.     /**
  45.      * Creates an ExtendedIterator wrapped round a {@link Stream}. The extended iterator does not permit <code>.remove()</code>.
  46.      * <p>
  47.      * The stream should not be used directly. The effect of doing so is undefined.
  48.      * </p>
  49.      *
  50.      * @param <T> The type of object returned from the iterator.
  51.      * @param stream the Stream to create an iterator from.
  52.      * @return an Extended iterator on the {@code stream} iterator.
  53.      */
  54.     public static <T> ExtendedIterator<T> create(final Stream<T> stream) {
  55.         return new ExtendedIterator<>(stream.iterator(), true);
  56.     }

  57.     /**
  58.      * Creates an ExtendedIterator wrapped round <code>it</code>, which does not permit <code>.remove()</code> even if <code>it</code> does.
  59.      *
  60.      * @param <T> The type of object returned from the iterator.
  61.      * @param it The Iterator to wrap.
  62.      * @return an Extended iterator on {@code it}
  63.      * @throws UnsupportedOperationException if remove() is called on the resulting iterator.
  64.      */
  65.     public static <T> ExtendedIterator<T> createNoRemove(final Iterator<T> it) {
  66.         return new ExtendedIterator<>(it, true);
  67.     }

  68.     /**
  69.      * Creates an empty Extended iterator.
  70.      *
  71.      * @return An empty Extended iterator.
  72.      */
  73.     public static ExtendedIterator<?> emptyIterator() {
  74.         return new ExtendedIterator<>(Collections.emptyIterator(), false);
  75.     }

  76.     /**
  77.      * Flattens an iterator of iterators into an Iterator over the next level values. Similar to list splicing in lisp.
  78.      *
  79.      * @param <T> The type of object returned from the iterator.
  80.      * @param iterators An iterator of iterators.
  81.      * @return An iterator over the logical concatenation of the inner iterators.
  82.      */
  83.     public static <T> ExtendedIterator<T> flatten(final Iterator<Iterator<T>> iterators) {
  84.         return create(IteratorUtils.chainedIterator(iterators));
  85.     }

  86.     /**
  87.      * Set to <code>true</code> if this wrapping doesn't permit the use of {@link #remove()}, otherwise removal is delegated to the base iterator.
  88.      */
  89.     private final boolean throwOnRemove;

  90.     /** The base iterator that we wrap */
  91.     private final Iterator<? extends T> base;

  92.     /**
  93.      * Initialize this wrapping with the given base iterator and remove-control.
  94.      *
  95.      * @param base          the base iterator that this iterator wraps
  96.      * @param throwOnRemove true if .remove() must throw an exception
  97.      */
  98.     private ExtendedIterator(final Iterator<? extends T> base, final boolean throwOnRemove) {
  99.         this.base = base;
  100.         this.throwOnRemove = throwOnRemove;
  101.     }

  102.     /**
  103.      * Chains the {@code other} iterator to the end of this one.
  104.      *
  105.      * @param other the other iterator to extend this iterator with.
  106.      * @return A new iterator returning the contents of {@code this} iterator followed by the contents of {@code other} iterator.
  107.      * @param <X> The type of object returned from the other iterator.
  108.      */
  109.     public <X extends T> ExtendedIterator<T> andThen(final Iterator<X> other) {
  110.         if (base instanceof IteratorChain) {
  111.             ((IteratorChain<T>) base).addIterator(other);
  112.             return this;
  113.         }
  114.         return new ExtendedIterator<>(new IteratorChain<>(base, other), throwOnRemove);
  115.     }

  116.     /**
  117.      * Filter this iterator using a predicate. Only items for which the predicate returns {@code true} will be included in the result.
  118.      *
  119.      * @param predicate The predicate to filter the items with.
  120.      * @return An iterator filtered by the predicate.
  121.      */
  122.     public ExtendedIterator<T> filter(final Predicate<T> predicate) {
  123.         return new ExtendedIterator<>(new FilterIterator<>(this, predicate::test), throwOnRemove);
  124.     }

  125.     @Override
  126.     public void forEachRemaining(final Consumer<? super T> action) {
  127.         base.forEachRemaining(action);
  128.     }

  129.     @Override
  130.     public boolean hasNext() {
  131.         return base.hasNext();
  132.     }

  133.     /**
  134.      * Map the elements of the iterator to a now type.
  135.      *
  136.      * @param function The function to map elements of {@code <T>} to type {@code <U>}.
  137.      * @return An Extended iterator that returns a {@code <U>} for very {@code <T>} in the original iterator.
  138.      * @param <U> The object type to return.
  139.      */
  140.     public <U> ExtendedIterator<U> map(final Function<T, U> function) {
  141.         return new ExtendedIterator<>(new TransformIterator<>(this, function::apply), false);
  142.     }

  143.     @Override
  144.     public T next() {
  145.         return base.next();
  146.     }

  147.     @Override
  148.     public void remove() {
  149.         if (throwOnRemove) {
  150.             throw new UnsupportedOperationException();
  151.         }
  152.         base.remove();
  153.     }
  154. }