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 19 import java.util.Collection; 20 import java.util.Iterator; 21 import java.util.NoSuchElementException; 22 import java.util.Objects; 23 24 import org.apache.commons.collections4.ResettableIterator; 25 26 /** 27 * An Iterator that restarts when it reaches the end. 28 * <p> 29 * The iterator will loop continuously around the provided elements, unless 30 * there are no elements in the collection to begin with, or all the elements 31 * have been {@link #remove removed}. 32 * </p> 33 * <p> 34 * Concurrent modifications are not directly supported, and for most collection 35 * implementations will throw a ConcurrentModificationException. 36 * </p> 37 * 38 * @param <E> the type of elements returned by this iterator. 39 * @since 3.0 40 */ 41 public class LoopingIterator<E> implements ResettableIterator<E> { 42 43 /** The collection to base the iterator on */ 44 private final Collection<? extends E> collection; 45 /** The current iterator */ 46 private Iterator<? extends E> iterator; 47 48 /** 49 * Constructor that wraps a collection. 50 * <p> 51 * There is no way to reset an Iterator instance without recreating it from 52 * the original source, so the Collection must be passed in. 53 * </p> 54 * 55 * @param collection the collection to wrap 56 * @throws NullPointerException if the collection is null 57 */ 58 public LoopingIterator(final Collection<? extends E> collection) { 59 this.collection = Objects.requireNonNull(collection, "collection"); 60 reset(); 61 } 62 63 /** 64 * Has the iterator any more elements. 65 * <p> 66 * Returns false only if the collection originally had zero elements, or 67 * all the elements have been {@link #remove removed}. 68 * </p> 69 * 70 * @return {@code true} if there are more elements 71 */ 72 @Override 73 public boolean hasNext() { 74 return !collection.isEmpty(); 75 } 76 77 /** 78 * Returns the next object in the collection. 79 * <p> 80 * If at the end of the collection, return the first element. 81 * </p> 82 * 83 * @return the next object 84 * @throws NoSuchElementException if there are no elements 85 * at all. Use {@link #hasNext} to avoid this error. 86 */ 87 @Override 88 public E next() { 89 if (collection.isEmpty()) { 90 throw new NoSuchElementException("There are no elements for this iterator to loop on"); 91 } 92 if (!iterator.hasNext()) { 93 reset(); 94 } 95 return iterator.next(); 96 } 97 98 /** 99 * Removes the previously retrieved item from the underlying collection. 100 * <p> 101 * This feature is only supported if the underlying collection's 102 * {@link Collection#iterator()} method returns an implementation 103 * that supports it. 104 * </p> 105 * <p> 106 * This method can only be called after at least one {@link #next} method call. 107 * After a removal, the remove method may not be called again until another 108 * next has been performed. If the {@link #reset} is called, then remove may 109 * not be called until {@link #next} is called again. 110 * </p> 111 */ 112 @Override 113 public void remove() { 114 iterator.remove(); 115 } 116 117 /** 118 * Resets the iterator back to the start of the collection. 119 */ 120 @Override 121 public void reset() { 122 iterator = collection.iterator(); 123 } 124 125 /** 126 * Gets the size of the collection underlying the iterator. 127 * 128 * @return the current collection size 129 */ 130 public int size() { 131 return collection.size(); 132 } 133 134 }