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.iterators; 018 019import java.util.Collection; 020import java.util.Iterator; 021import java.util.NoSuchElementException; 022 023import org.apache.commons.collections4.ResettableIterator; 024 025/** 026 * An Iterator that restarts when it reaches the end. 027 * <p> 028 * The iterator will loop continuously around the provided elements, unless 029 * there are no elements in the collection to begin with, or all the elements 030 * have been {@link #remove removed}. 031 * <p> 032 * Concurrent modifications are not directly supported, and for most collection 033 * implementations will throw a ConcurrentModificationException. 034 * 035 * @since 3.0 036 */ 037public class LoopingIterator<E> implements ResettableIterator<E> { 038 039 /** The collection to base the iterator on */ 040 private final Collection<? extends E> collection; 041 /** The current iterator */ 042 private Iterator<? extends E> iterator; 043 044 /** 045 * Constructor that wraps a collection. 046 * <p> 047 * There is no way to reset an Iterator instance without recreating it from 048 * the original source, so the Collection must be passed in. 049 * 050 * @param coll the collection to wrap 051 * @throws NullPointerException if the collection is null 052 */ 053 public LoopingIterator(final Collection<? extends E> coll) { 054 if (coll == null) { 055 throw new NullPointerException("The collection must not be null"); 056 } 057 collection = coll; 058 reset(); 059 } 060 061 /** 062 * Has the iterator any more elements. 063 * <p> 064 * Returns false only if the collection originally had zero elements, or 065 * all the elements have been {@link #remove removed}. 066 * 067 * @return <code>true</code> if there are more elements 068 */ 069 @Override 070 public boolean hasNext() { 071 return collection.size() > 0; 072 } 073 074 /** 075 * Returns the next object in the collection. 076 * <p> 077 * If at the end of the collection, return the first element. 078 * 079 * @return the next object 080 * @throws NoSuchElementException if there are no elements 081 * at all. Use {@link #hasNext} to avoid this error. 082 */ 083 @Override 084 public E next() { 085 if (collection.size() == 0) { 086 throw new NoSuchElementException("There are no elements for this iterator to loop on"); 087 } 088 if (iterator.hasNext() == false) { 089 reset(); 090 } 091 return iterator.next(); 092 } 093 094 /** 095 * Removes the previously retrieved item from the underlying collection. 096 * <p> 097 * This feature is only supported if the underlying collection's 098 * {@link Collection#iterator iterator} method returns an implementation 099 * that supports it. 100 * <p> 101 * This method can only be called after at least one {@link #next} method call. 102 * After a removal, the remove method may not be called again until another 103 * next has been performed. If the {@link #reset} is called, then remove may 104 * not be called until {@link #next} is called again. 105 */ 106 @Override 107 public void remove() { 108 iterator.remove(); 109 } 110 111 /** 112 * Resets the iterator back to the start of the collection. 113 */ 114 @Override 115 public void reset() { 116 iterator = collection.iterator(); 117 } 118 119 /** 120 * Gets the size of the collection underlying the iterator. 121 * 122 * @return the current collection size 123 */ 124 public int size() { 125 return collection.size(); 126 } 127 128}