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 */
017 package org.apache.commons.collections.iterators;
018
019 import java.util.Collection;
020 import java.util.Iterator;
021 import java.util.NoSuchElementException;
022
023 import org.apache.commons.collections.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 Commons Collections 3.0
036 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
037 *
038 * @author <a href="mailto:joncrlsn@users.sf.net">Jonathan Carlson</a>
039 * @author Stephen Colebourne
040 */
041 public class LoopingIterator implements ResettableIterator {
042
043 /** The collection to base the iterator on */
044 private Collection collection;
045 /** The current iterator */
046 private Iterator iterator;
047
048 /**
049 * Constructor that wraps a collection.
050 * <p>
051 * There is no way to reset an Iterator instance without recreating it from
052 * the original source, so the Collection must be passed in.
053 *
054 * @param coll the collection to wrap
055 * @throws NullPointerException if the collection is null
056 */
057 public LoopingIterator(Collection coll) {
058 if (coll == null) {
059 throw new NullPointerException("The collection must not be null");
060 }
061 collection = coll;
062 reset();
063 }
064
065 /**
066 * Has the iterator any more elements.
067 * <p>
068 * Returns false only if the collection originally had zero elements, or
069 * all the elements have been {@link #remove removed}.
070 *
071 * @return <code>true</code> if there are more elements
072 */
073 public boolean hasNext() {
074 return (collection.size() > 0);
075 }
076
077 /**
078 * Returns the next object in the collection.
079 * <p>
080 * If at the end of the collection, return the first element.
081 *
082 * @throws NoSuchElementException if there are no elements
083 * at all. Use {@link #hasNext} to avoid this error.
084 */
085 public Object next() {
086 if (collection.size() == 0) {
087 throw new NoSuchElementException("There are no elements for this iterator to loop on");
088 }
089 if (iterator.hasNext() == false) {
090 reset();
091 }
092 return iterator.next();
093 }
094
095 /**
096 * Removes the previously retrieved item from the underlying collection.
097 * <p>
098 * This feature is only supported if the underlying collection's
099 * {@link Collection#iterator iterator} method returns an implementation
100 * that supports it.
101 * <p>
102 * This method can only be called after at least one {@link #next} method call.
103 * After a removal, the remove method may not be called again until another
104 * next has been performed. If the {@link #reset} is called, then remove may
105 * not be called until {@link #next} is called again.
106 */
107 public void remove() {
108 iterator.remove();
109 }
110
111 /**
112 * Resets the iterator back to the start of the collection.
113 */
114 public void reset() {
115 iterator = collection.iterator();
116 }
117
118 /**
119 * Gets the size of the collection underlying the iterator.
120 *
121 * @return the current collection size
122 */
123 public int size() {
124 return collection.size();
125 }
126
127 }