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