Я пытаюсь написать собственный итератор для набора, который я сделал. Я немного запутался в контракте на интерфейс Iterable. Он имеет три метода: next(), hasNext() и remove(). Мой набор неизменяем, поэтому я планирую создать исключение UnsupportedOperationException для метода remove(). Это еще так называемая "ленивая генерация", т.е. элементы не хранятся в памяти, а создаются по мере необходимости, но это ни тут, ни там.
Javadoc для метода next() Iterator выглядит следующим образом:
E next()
Returns the next element in the iteration.
Returns:
the next element in the iteration
Throws:
NoSuchElementException - if the iteration has no more elements
а для hasNext() это:
boolean hasNext()
Returns true if the iteration has more elements. (In other words, returns
true if next() would return an element rather than throwing an exception.)
Следуя этим правилам, я начал реализовывать свой Set и Iterator, получив следующее:
import java.util.AbstractSet;
import java.util.Iterator;
public class PrimesBelow extends AbstractSet<Integer>{
int max;
int size;
public PrimesBelow(int max) {
this.max = max;
}
@Override
public Iterator<Integer> iterator() {
return new SetIterator<Integer>(this);
}
@Override
public int size() {
if(this.size == -1){
System.out.println("Calculating size");
size = calculateSize();
}else{
System.out.println("Accessing calculated size");
}
return size;
}
private int calculateSize() {
int c = 0;
for(Integer p: this)
c++;
return c;
}
public static void main(String[] args){
PrimesBelow primesBelow10 = new PrimesBelow(10);
for(int i: primesBelow10)
System.out.println(i);
System.out.println(primesBelow10);
}
}
.
import java.util.Iterator;
import java.util.NoSuchElementException;
public class SetIterator<T> implements Iterator<Integer> {
int max;
int current;
public SetIterator(PrimesBelow pb) {
this.max= pb.max;
current = 1;
}
@Override
public boolean hasNext() {
if(current < max) return true;
else return false;
}
@Override
public Integer next() {
while(hasNext()){
current++;
if(isPrime(current)){
System.out.println("returning "+current);
return current;
}
}
throw new NoSuchElementException();
}
private boolean isPrime(int a) {
if(a<2) return false;
for(int i = 2; i < a; i++) if((a%i)==0) return false;
return true;
}
}
На мой взгляд, это нормально, next() возвращает следующее значение и выдает исключение, когда его больше нет. hasNext() должен возвращать true, если есть еще значения для перебора, и false в противном случае. Однако вывод основного цикла таков:
returning 2
2
returning 3
3
returning 5
5
returning 7
7
Exception in thread "main" java.util.NoSuchElementException
at SetIterator.next(SetIterator.java:27)
at SetIterator.next(SetIterator.java:1)
at PrimesBelow.main(PrimesBelow.java:38)
Таким образом, кажется, что исключение не обрабатывается в цикле for each. Как мне написать собственный итератор, который я могу использовать, чтобы это работало? Я попытался вернуть null вместо того, чтобы генерировать исключение, но это просто дает исключение NullPointerException.
Должен ли я возвращать ноль, когда итератор завершен, или генерировать исключение? Javadoc говорит, что next() должен генерировать исключение, но когда я наводил курсор на переопределенный метод next() в Eclipse, подпись не показывает генерацию NoSuchElementException, поэтому я очень запутался в том, что говорит контракт. Мне кажется очень странным возвращать null, когда я закончу, поскольку коллекция потенциально может содержать нулевые элементы.
Спасибо за помощь.
hasNext()
в своей реализацииnext()
? Вы должны только проверить, есть ли следующий элемент без цикла while. - person dpr   schedule 18.08.2017