ArrayIndexOutOfBoundsException при перечислении массива в итераторе с увеличением шага перечисления
У нас есть массив на 400 чисел: 0, 0.5,...199.5, 200. В итераторе этот массив перебирается и, в зависимости от указанной в main скорости перечисления (speed), меняется шаг итерации. Speed - число, которое будет прибавляться в классе-итераторе к index, от чего будет зависеть шаг перебора. Далее в консоль должен выводиться этот массив, но с другим шагом. Если в классе-итераторе указать return pointList[index++], то с итерацией проблем нет, но, при указании любого speed, даже равного 1, программа выкидывает ArrayIndexOutOfBoundsException: 400 и указывает, что ошибка в строке класса-итератора:return pointList[index += speed] и в main в строке System.out.println(iterator.next());
Вот сижу, туплю, не могу разобраться, в чём дело. Поэтому, пожалуйста, дайте каких-нибудь наводок или намеков, в чем может быть проблема?
Полный код итератора:
public class PointIterator<Double> implements Iterator<Double> {
private int index;
private int speed;
private Double[] pointList;
public PointIterator(Double[] pointList){
this.pointList = pointList;
}
public boolean hasNext() {
if(index < pointList.length){
return true;
}else {
return false;
}
}
public Double next() {
if(this.hasNext()) {
return pointList[index += speed];
}else {
throw new NoSuchElementException();
}
}
public void changeSpeed(int speed){
this.speed = speed;
Фрагмент кода из main:
PointIterator iterator = harmonica.iterator(); //в классе Harmonica создаётся массив на 400 элементов и реализуется итератор, в нём проблем не наблюдается.
iterator.changeSpeed(1); //сюда передаётся наше значение speed
System.out.println("Array's length: " + harmonica.getPositionLength() + "\n");
while (iterator.hasNext()){
System.out.println(iterator.next());
}
Ответы (3 шт):
Здесь
public boolean hasNext() {
if(index < pointList.length){
return true;
}else {
return false;
}
}
hasNext() будет возвращать true когда следующего элемента уже не будет. Например массив размером 10. Его последний индекс 9.
hasNext() для индекса 9 вернет true, потому что 9 < 10, не смотря что элементов с индексом большим 9 не существует.
Кроме того, при определении наличия следующего элемента необходимо также учитывать шаг.
Вообще так делать нельзя. Разумеется, вы можете задать шаг (скорость). Проблема в том, метод next в итераторе не должен ничего проверять. Он должен возвращать следующий элемент. Для прверки есть метод hasNext. А теперь представьте ситуацию классического использования итератора :
while(iterator.hasNext()){
//здесь я меняю шаг
iterator.next();
}
В этом случае hasNext уже вернул true, для этого ему нужно знать шаг, однако в цикле вы его изменили (после проверки). Рано или поздно вы получите исключение. Мало того, ваши коллеги за такую "имплементацию" точно спасибо не скажут. Все знают, что такое итератор и каково его ожидаемое поведение. Поэтому имплементация итератора должна быть примерно такой:
import java.util.Iterator;
public class PointIterator<Double> implements Iterator<Double> {
private int cursor = 0;
private int step;
private int stepChanges;
private final Double[] array;
public PointIterator(Double[] array, int step) {
this.step = step;
this.stepChanges = step;
this.array = array;
}
@Override
public boolean hasNext() {
step = stepChanges;
return cursor + step < array.length;
}
@Override
public Double next() {
Double next = array[cursor];
cursor += step;
return next;
}
public void changeSpeed(int step){
this.stepChanges = step;
}
}
Помимо того, что hasNext() имеет не верное условие, о чем сказали в другом ответе, ещё и метод делает проверку без учета текущего шага, что может привести к вылету за пределы массива на этапе работы метода next() в момент внутренней проверки:
if(this.hasNext()) {
return pointList[index += speed];
}
Что в общем-то можно исправить если уж делаете класс-обертку в методе hasNext(), но опять таки это действительно очень не интуитивная реализация метода.