LoopingIterator.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.Collection;
  19. import java.util.Iterator;
  20. import java.util.NoSuchElementException;
  21. import java.util.Objects;

  22. import org.apache.commons.collections4.ResettableIterator;

  23. /**
  24.  * An Iterator that restarts when it reaches the end.
  25.  * <p>
  26.  * The iterator will loop continuously around the provided elements, unless
  27.  * there are no elements in the collection to begin with, or all the elements
  28.  * have been {@link #remove removed}.
  29.  * </p>
  30.  * <p>
  31.  * Concurrent modifications are not directly supported, and for most collection
  32.  * implementations will throw a ConcurrentModificationException.
  33.  * </p>
  34.  *
  35.  * @param <E> the type of elements returned by this iterator.
  36.  * @since 3.0
  37.  */
  38. public class LoopingIterator<E> implements ResettableIterator<E> {

  39.     /** The collection to base the iterator on */
  40.     private final Collection<? extends E> collection;
  41.     /** The current iterator */
  42.     private Iterator<? extends E> iterator;

  43.     /**
  44.      * Constructor that wraps a collection.
  45.      * <p>
  46.      * There is no way to reset an Iterator instance without recreating it from
  47.      * the original source, so the Collection must be passed in.
  48.      * </p>
  49.      *
  50.      * @param collection  the collection to wrap
  51.      * @throws NullPointerException if the collection is null
  52.      */
  53.     public LoopingIterator(final Collection<? extends E> collection) {
  54.         this.collection = Objects.requireNonNull(collection, "collection");
  55.         reset();
  56.     }

  57.     /**
  58.      * Has the iterator any more elements.
  59.      * <p>
  60.      * Returns false only if the collection originally had zero elements, or
  61.      * all the elements have been {@link #remove removed}.
  62.      * </p>
  63.      *
  64.      * @return {@code true} if there are more elements
  65.      */
  66.     @Override
  67.     public boolean hasNext() {
  68.         return !collection.isEmpty();
  69.     }

  70.     /**
  71.      * Returns the next object in the collection.
  72.      * <p>
  73.      * If at the end of the collection, return the first element.
  74.      * </p>
  75.      *
  76.      * @return the next object
  77.      * @throws NoSuchElementException if there are no elements
  78.      *         at all.  Use {@link #hasNext} to avoid this error.
  79.      */
  80.     @Override
  81.     public E next() {
  82.         if (collection.isEmpty()) {
  83.             throw new NoSuchElementException("There are no elements for this iterator to loop on");
  84.         }
  85.         if (!iterator.hasNext()) {
  86.             reset();
  87.         }
  88.         return iterator.next();
  89.     }

  90.     /**
  91.      * Removes the previously retrieved item from the underlying collection.
  92.      * <p>
  93.      * This feature is only supported if the underlying collection's
  94.      * {@link Collection#iterator()} method returns an implementation
  95.      * that supports it.
  96.      * </p>
  97.      * <p>
  98.      * This method can only be called after at least one {@link #next} method call.
  99.      * After a removal, the remove method may not be called again until another
  100.      * next has been performed. If the {@link #reset} is called, then remove may
  101.      * not be called until {@link #next} is called again.
  102.      * </p>
  103.      */
  104.     @Override
  105.     public void remove() {
  106.         iterator.remove();
  107.     }

  108.     /**
  109.      * Resets the iterator back to the start of the collection.
  110.      */
  111.     @Override
  112.     public void reset() {
  113.         iterator = collection.iterator();
  114.     }

  115.     /**
  116.      * Gets the size of the collection underlying the iterator.
  117.      *
  118.      * @return the current collection size
  119.      */
  120.     public int size() {
  121.         return collection.size();
  122.     }

  123. }