Set的自定义写入迭代器会在for-each循环中抛出异常

时间:2017-08-18 12:11:56

标签: java foreach iterator nosuchelementexception

我正在尝试为我制作的Set编写一个自定义迭代器。我对Interface Iterable的合同有点困惑。它有三个方法:next(),hasNext()和remove()。我的设置是不可变的,所以我计划为方法remove()抛出UnsupportedOperationException。它也被称为"懒惰生成"即元素不是存储在存储器中,而是在需要时创建,但这不是在这里也不是在那里。

Iterator的next()方法的javadoc如下:

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)

所以似乎在每个循环中都没有处理异常。如何编写可以使用的自定义迭代器以使其有效?我尝试返回null而不是抛出异常但只是给出了NullPointerException。

Iterator完成后应该返回null,还是抛出异常? Javadoc说next()应该抛出一个Exception但是当我将鼠标悬停在Eclipse中的override(方法)next()时,签名不会显示抛出NoSuchElementException,所以我对合同所说的内容非常困惑。我完成后返回null似乎很奇怪,因为集合可能包含null元素。

感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

更改

while(hasNext()) {
    //...
}
throw new NoSuchElementException();

if(hasNext()) {
    //...
} else {
    throw new NoSuchElementException();
}

答案 1 :(得分:1)

假设您的代码返回的最后一个素数为7。然后current将是7,显然是< 10。因此hasNext()将返回true。但是,没有更多素数大于7但小于10,因此下一次调用next()将产生NoSuchElementException。目前,只有max是素数时,您的代码才有效。

您需要验证hasNext()中还有其他素数。