【问题标题】:Custom written Iterator for a Set throws Exception in for-each loop自定义编写的 Set 迭代器在 for-each 循环中抛出异常
【发布时间】:2018-01-27 02:58:05
【问题描述】:

我正在尝试为我制作的 Set 编写一个定制的迭代器。我对接口 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)

所以似乎在 for each 循环中没有处理异常。如何编写一个我可以使用的自定义迭代器以便它工作?我尝试返回 null 而不是抛出异常,但这只会给出 NullPointerException。

我应该在迭代器完成时返回 null,还是抛出异常? Javadoc 说 next() 应该抛出一个异常,但是当我将鼠标悬停在 Eclipse 中被覆盖的方法 next() 上时,签名没有显示 throws NoSuchElementException 所以我对合同所说的内容感到非常困惑。完成后返回 null 对我来说似乎很奇怪,因为集合可能包含 null 元素。

感谢您的帮助。

【问题讨论】:

  • 为什么在next() 的实现中循环hasNext()?您应该只检查是否有没有 while 循环的下一个元素。
  • 我想我这样做是因为逻辑是检查迭代器是否可以返回更多元素,以避免代码重复和两次不同的编写 if(current
  • @user1661303 逻辑没有意义,next() 应该返回一个值(而不是循环遍历它)。并且这段代码总是会抛出异常,因为在遍历所有元素之后,不管怎样,你最终都会抛出异常

标签: java foreach iterator nosuchelementexception


【解决方案1】:

改变

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

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

【讨论】:

  • 啊。好的。我几乎明白你在说什么,但我看不到我的示例中的 while 循环如何遍历 Set 中的元素。它不只是遍历自然数,直到它碰到 Set 中的一个元素,或者达到限制然后抛出一个异常?例如说 current 是 3。对 next() 的调用应该将其增加到 4,然后将其增加到 5,然后看到它是一个素数并返回它对吗?不遍历整个 Set。也许我在这里遗漏了一些东西。
  • 这也是我的第一个想法,但这并不能解决问题。需要循环来计算下一个素数。
  • @dpr 但循环应该在迭代器之外不是吗?
  • 这段代码看起来是对的,但是当我运行它时返回 [2, 3, 4, 5, 6, 7, 8, 9, 10] 作为集合。 -编辑
  • @user1661303 如果我的回答对 dpr 来说太重要了,你可以不接受。我只是喜欢帮助别人)
【解决方案2】:

假设您的代码返回的最后一个素数是7。那么current 将是7,这显然是&lt; 10。所以hasNext() 将返回true。然而,没有大于7 但小于10 的素数,所以下一次调用next() 将产生NoSuchElementException。目前,您的代码只有在 max 是素数时才有效。

您需要验证hasNext() 中是否还有一个可用的素数。

【讨论】:

  • 啊。知道了。感谢角落案例的解释。现在我明白了:)
猜你喜欢
  • 2014-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多