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    *      https://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.lang.reflect.Array;
20  import java.util.Iterator;
21  import java.util.NoSuchElementException;
22  
23  import org.apache.commons.collections4.ResettableIterator;
24  
25  /**
26   * Implements an {@link Iterator Iterator} over any array.
27   * <p>
28   * The array can be either an array of object or of primitives. If you know
29   * that you have an object array, the
30   * {@link ObjectArrayIterator ObjectArrayIterator}
31   * class is a better choice, as it will perform better.
32   * </p>
33   * <p>
34   * The iterator implements a {@link #reset} method, allowing the reset of
35   * the iterator back to the start if required.
36   * </p>
37   *
38   * @param <E> The type of elements returned by this iterator.
39   * @since 1.0
40   */
41  public class ArrayIterator<E> implements ResettableIterator<E> {
42  
43      /** The array to iterate over */
44      final Object array;
45  
46      /** The start index to loop from */
47      final int startIndex;
48  
49      /** The end index to loop to */
50      final int endIndex;
51  
52      /** The current iterator index */
53      int index;
54  
55      /**
56       * Constructs an ArrayIterator that will iterate over the values in the
57       * specified array.
58       *
59       * @param array The array to iterate over.
60       * @throws IllegalArgumentException if {@code array} is not an array.
61       * @throws NullPointerException if {@code array} is {@code null}
62       */
63      public ArrayIterator(final Object array) {
64          this(array, 0);
65      }
66  
67      /**
68       * Constructs an ArrayIterator that will iterate over the values in the
69       * specified array from a specific start index.
70       *
71       * @param array  The array to iterate over.
72       * @param startIndex  The index to start iterating at.
73       * @throws IllegalArgumentException if {@code array} is not an array.
74       * @throws NullPointerException if {@code array} is {@code null}
75       * @throws IndexOutOfBoundsException if the index is invalid
76       */
77      public ArrayIterator(final Object array, final int startIndex) {
78          this(array, startIndex, Array.getLength(array));
79      }
80  
81      /**
82       * Constructs an ArrayIterator that will iterate over a range of values
83       * in the specified array.
84       *
85       * @param array  The array to iterate over.
86       * @param startIndex  The index to start iterating at.
87       * @param endIndex  The index to finish iterating at.
88       * @throws IllegalArgumentException if {@code array} is not an array.
89       * @throws NullPointerException if {@code array} is {@code null}
90       * @throws IndexOutOfBoundsException if either index is invalid
91       */
92      public ArrayIterator(final Object array, final int startIndex, final int endIndex) {
93          this.array = array;
94          this.startIndex = startIndex;
95          this.endIndex = endIndex;
96          this.index = startIndex;
97  
98          final int len = Array.getLength(array);
99          checkBound(startIndex, len, "start");
100         checkBound(endIndex, len, "end");
101         if (endIndex < startIndex) {
102             throw new IllegalArgumentException("End index must not be less than start index.");
103         }
104     }
105 
106     /**
107      * Checks whether the index is valid or not.
108      *
109      * @param bound  The index to check
110      * @param len  The length of the array
111      * @param type  The index type (for error messages)
112      * @throws IndexOutOfBoundsException if the index is invalid
113      */
114     protected void checkBound(final int bound, final int len, final String type) {
115         if (bound > len) {
116             throw new ArrayIndexOutOfBoundsException("Attempt to make an ArrayIterator that " + type + "s beyond the end of the array. ");
117         }
118         if (bound < 0) {
119             throw new ArrayIndexOutOfBoundsException("Attempt to make an ArrayIterator that " + type + "s before the start of the array. ");
120         }
121     }
122 
123     /**
124      * Gets the array that this iterator is iterating over.
125      *
126      * @return The array this iterator iterates over.
127      */
128     public Object getArray() {
129         return array;
130     }
131 
132     /**
133      * Gets the end index to loop to.
134      *
135      * @return The end index
136      * @since 4.0
137      */
138     public int getEndIndex() {
139         return endIndex;
140     }
141 
142     /**
143      * Gets the start index to loop from.
144      *
145      * @return The start index
146      * @since 4.0
147      */
148     public int getStartIndex() {
149         return startIndex;
150     }
151 
152     /**
153      * Returns true if there are more elements to return from the array.
154      *
155      * @return true if there is a next element to return
156      */
157     @Override
158     public boolean hasNext() {
159         return index < endIndex;
160     }
161 
162     /**
163      * Returns the next element in the array.
164      *
165      * @return The next element in the array
166      * @throws NoSuchElementException if all the elements in the array
167      *  have already been returned
168      */
169     @Override
170     @SuppressWarnings("unchecked")
171     public E next() {
172         if (!hasNext()) {
173             throw new NoSuchElementException();
174         }
175         return (E) Array.get(array, index++);
176     }
177 
178     /**
179      * Always throws {@link UnsupportedOperationException}.
180      *
181      * @throws UnsupportedOperationException Always thrown.
182      */
183     @Override
184     public void remove() {
185         throw new UnsupportedOperationException("remove() method is not supported");
186     }
187 
188     /**
189      * Resets the iterator back to the start index.
190      */
191     @Override
192     public void reset() {
193         index = startIndex;
194     }
195 
196 }