View Javadoc

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 }