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.ListIterator; 021import java.util.NoSuchElementException; 022 023import org.apache.commons.collections4.ResettableListIterator; 024 025/** 026 * Implements a {@link ListIterator} over an 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 {@link ObjectArrayListIterator} 030 * class is a better choice, as it will perform better. 031 * </p> 032 * <p> 033 * This iterator does not support {@link #add(Object)} or {@link #remove()}, as the array 034 * cannot be changed in size. The {@link #set(Object)} method is supported however. 035 * </p> 036 * 037 * @param <E> The type of elements returned by this iterator. 038 * @see org.apache.commons.collections4.iterators.ArrayIterator 039 * @see java.util.Iterator 040 * @see java.util.ListIterator 041 * @since 3.0 042 */ 043public class ArrayListIterator<E> extends ArrayIterator<E> 044 implements ResettableListIterator<E> { 045 046 /** 047 * Holds the index of the last item returned by a call to {@code next()} 048 * or {@code previous()}. This is set to {@code -1} if neither method 049 * has yet been invoked. {@code lastItemIndex} is used to implement 050 * the {@link #set} method. 051 */ 052 private int lastItemIndex = -1; 053 054 /** 055 * Constructs an ArrayListIterator that will iterate over the values in the 056 * specified array. 057 * 058 * @param array The array to iterate over 059 * @throws IllegalArgumentException if {@code array} is not an array. 060 * @throws NullPointerException if {@code array} is {@code null} 061 */ 062 public ArrayListIterator(final Object array) { 063 super(array); 064 } 065 066 /** 067 * Constructs an ArrayListIterator that will iterate over the values in the 068 * specified array from a specific start index. 069 * 070 * @param array The array to iterate over 071 * @param startIndex The index to start iterating at 072 * @throws IllegalArgumentException if {@code array} is not an array. 073 * @throws NullPointerException if {@code array} is {@code null} 074 * @throws IndexOutOfBoundsException if the start index is out of bounds 075 */ 076 public ArrayListIterator(final Object array, final int startIndex) { 077 super(array, startIndex); 078 } 079 080 /** 081 * Constructs an ArrayListIterator that will iterate over a range of values 082 * in the specified array. 083 * 084 * @param array The array to iterate over 085 * @param startIndex The index to start iterating at 086 * @param endIndex The index (exclusive) to finish iterating at 087 * @throws IllegalArgumentException if {@code array} is not an array. 088 * @throws IndexOutOfBoundsException if the start or end index is out of bounds 089 * @throws IllegalArgumentException if end index is before the start 090 * @throws NullPointerException if {@code array} is {@code null} 091 */ 092 public ArrayListIterator(final Object array, final int startIndex, final int endIndex) { 093 super(array, startIndex, endIndex); 094 } 095 096 /** 097 * This iterator does not support modification of its backing collection, and so will 098 * always throw an {@link UnsupportedOperationException} when this method is invoked. 099 * 100 * @param o The element to add 101 * @throws UnsupportedOperationException always thrown. 102 * @see java.util.ListIterator#set 103 */ 104 @Override 105 public void add(final Object o) { 106 throw new UnsupportedOperationException("add() method is not supported"); 107 } 108 109 /** 110 * Returns true if there are previous elements to return from the array. 111 * 112 * @return true if there is a previous element to return 113 */ 114 @Override 115 public boolean hasPrevious() { 116 return index > startIndex; 117 } 118 119 /** 120 * Gets the next element from the array. 121 * 122 * @return The next element 123 * @throws NoSuchElementException if there is no next element 124 */ 125 @Override 126 @SuppressWarnings("unchecked") 127 public E next() { 128 if (!hasNext()) { 129 throw new NoSuchElementException(); 130 } 131 lastItemIndex = index; 132 return (E) Array.get(array, index++); 133 } 134 135 /** 136 * Gets the next index to be retrieved. 137 * 138 * @return The index of the item to be retrieved next 139 */ 140 @Override 141 public int nextIndex() { 142 return index - startIndex; 143 } 144 145 /** 146 * Gets the previous element from the array. 147 * 148 * @return The previous element 149 * @throws NoSuchElementException if there is no previous element 150 */ 151 @Override 152 @SuppressWarnings("unchecked") 153 public E previous() { 154 if (!hasPrevious()) { 155 throw new NoSuchElementException(); 156 } 157 lastItemIndex = --index; 158 return (E) Array.get(array, index); 159 } 160 161 /** 162 * Gets the index of the item to be retrieved if {@link #previous()} is called. 163 * 164 * @return The index of the item to be retrieved next 165 */ 166 @Override 167 public int previousIndex() { 168 return index - startIndex - 1; 169 } 170 171 /** 172 * Resets the iterator back to the start index. 173 */ 174 @Override 175 public void reset() { 176 super.reset(); 177 lastItemIndex = -1; 178 } 179 180 /** 181 * Sets the element under the cursor. 182 * <p> 183 * This method sets the element that was returned by the last call 184 * to {@link #next()} of {@link #previous()}. 185 * </p> 186 * <p> 187 * <strong>Note:</strong> {@link ListIterator} implementations that support 188 * {@code add()} and {@code remove()} only allow {@code set()} to be called 189 * once per call to {@code next()} or {@code previous} (see the {@link ListIterator} 190 * Javadoc for more details). Since this implementation does 191 * not support {@code add()} or {@code remove()}, {@code set()} may be 192 * called as often as desired. 193 * </p> 194 * 195 * @param o The element to set 196 * @throws IllegalStateException if {@link #next()} or {@link #previous()} has not been called 197 * before {@link #set(Object)} 198 * @see java.util.ListIterator#set 199 */ 200 @Override 201 public void set(final Object o) { 202 if (lastItemIndex == -1) { 203 throw new IllegalStateException("must call next() or previous() before a call to set()"); 204 } 205 206 Array.set(array, lastItemIndex, o); 207 } 208 209}