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 * https://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 */ 017package org.apache.commons.collections4.iterators; 018 019import java.lang.reflect.Array; 020import java.util.Iterator; 021import java.util.NoSuchElementException; 022 023import org.apache.commons.collections4.ResettableIterator; 024 025/** 026 * Implements an {@link Iterator Iterator} over any array. 027 * <p> 028 * The array can be either an array of object or of primitives. If you know 029 * that you have an object array, the 030 * {@link ObjectArrayIterator ObjectArrayIterator} 031 * class is a better choice, as it will perform better. 032 * </p> 033 * <p> 034 * The iterator implements a {@link #reset} method, allowing the reset of 035 * the iterator back to the start if required. 036 * </p> 037 * 038 * @param <E> The type of elements returned by this iterator. 039 * @since 1.0 040 */ 041public class ArrayIterator<E> implements ResettableIterator<E> { 042 043 /** The array to iterate over */ 044 final Object array; 045 046 /** The start index to loop from */ 047 final int startIndex; 048 049 /** The end index to loop to */ 050 final int endIndex; 051 052 /** The current iterator index */ 053 int index; 054 055 /** 056 * Constructs an ArrayIterator that will iterate over the values in the 057 * specified array. 058 * 059 * @param array The array to iterate over. 060 * @throws IllegalArgumentException if {@code array} is not an array. 061 * @throws NullPointerException if {@code array} is {@code null} 062 */ 063 public ArrayIterator(final Object array) { 064 this(array, 0); 065 } 066 067 /** 068 * Constructs an ArrayIterator that will iterate over the values in the 069 * specified array from a specific start index. 070 * 071 * @param array The array to iterate over. 072 * @param startIndex The index to start iterating at. 073 * @throws IllegalArgumentException if {@code array} is not an array. 074 * @throws NullPointerException if {@code array} is {@code null} 075 * @throws IndexOutOfBoundsException if the index is invalid 076 */ 077 public ArrayIterator(final Object array, final int startIndex) { 078 this(array, startIndex, Array.getLength(array)); 079 } 080 081 /** 082 * Constructs an ArrayIterator that will iterate over a range of values 083 * in the specified array. 084 * 085 * @param array The array to iterate over. 086 * @param startIndex The index to start iterating at. 087 * @param endIndex The index to finish iterating at. 088 * @throws IllegalArgumentException if {@code array} is not an array. 089 * @throws NullPointerException if {@code array} is {@code null} 090 * @throws IndexOutOfBoundsException if either index is invalid 091 */ 092 public ArrayIterator(final Object array, final int startIndex, final int endIndex) { 093 this.array = array; 094 this.startIndex = startIndex; 095 this.endIndex = endIndex; 096 this.index = startIndex; 097 098 final int len = Array.getLength(array); 099 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}