2017-08-18 31 views
1

我正在尝试为我创建的集合编写自定义迭代器。我对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; 
    } 
} 

这似乎罚款由我,下一个()返回下一个值,当没有更多抛出异常。如果有更多的值要迭代,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,还是抛出Exception? Javadoc说next()应该抛出一个异常,但是当我将鼠标悬停在Eclipse的overriden方法next()上时,签名不会显示抛出NoSuchElementException,所以我对合同的内容非常困惑。我完成后返回null看起来很奇怪,因为集合可能包含空元素。

感谢您的帮助。

+0

为什么你在'next()'的实现中循环'hasNext()'?您应该只检查是否有没有while循环的下一个元素。 – dpr

+0

我想我是这么做的,因为这是逻辑检查Iterator是否可以返回更多元素的地方,以避免代码重复并在if(current user1661303

+0

@ user1661303逻辑没有意义,next()应该返回一个值(不循环)。而且这段代码总是会抛出一个异常,因为在遍历所有元素之后,最终抛出一个异常无论如何都是 – nafas

回答

1

变化

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

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

啊。好。我几乎看到你在说什么,但我没看到我的例子中的while循环如何遍历Set中的元素。它是不是只是迭代自然数直到它遇到Set中的元素,或达到极限然后抛出异常? 举例来说,当前是3.一个调用next()然后应该增加它到4,然后增加到5,然后看到它是一个素数,并返回它的权利?不遍历整个Set。也许我在这里错过了一些东西。 – user1661303

+0

这也是我的第一个想法,但这不能解决问题。该循环需要计算下一个素数。 – dpr

+0

@dpr但循环应该在iteratator之外是不是? – Valentun

1

假设您的代码返回的最后一个主要是7。那么current将是7,这显然是< 10。所以hasNext()将返回true。然而,没有更多的素数大于7但小于10,因此下一次拨打next()将产生NoSuchElementException。目前你的代码只能工作,如果max是首要的。

您需要验证,hasNext()中有一个额外的素数。

+0

啊。得到它了。感谢角落案例的解释。现在我明白了 :) – user1661303