2017-08-18 46 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