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 }