为 Set 自定义编写的迭代器在 for-each 循环中抛出异常
Custom written Iterator for a Set throws Exception in for-each loop
我正在尝试为我制作的 Set 编写一个定制的迭代器。我对 Interface Iterable 的契约有点困惑。它具有三个方法:next()、hasNext() 和 remove()。我的集合是不可变的,所以我计划为方法 remove() 抛出 UnsupportedOperationException。它也被称为 "lazily generated" 即元素不存储在内存中而是在需要时创建,但它既不存在也不存在。
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() return 下一个值并在没有更多值时抛出异常。如果有更多的值要迭代,hasNext() 应该 return 为真,否则为假。然而,主循环的输出是这样的:
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 循环中没有处理异常。如何编写一个我可以使用的自定义 Iterator 才能使其正常工作?我尝试 returning null 而不是抛出异常,但这只会给出 NullPointerException。
当 Iterator 完成时,我应该 return null 还是抛出异常?
Javadoc 说 next() 应该抛出异常,但是当我将鼠标悬停在 Eclipse 中覆盖的方法 next() 上时,签名不显示抛出 NoSuchElementException 所以我对合同说的很困惑。完成后 return null 对我来说似乎很奇怪,因为集合可能包含 null 元素。
感谢您的帮助。
改变
while(hasNext()) {
//...
}
throw new NoSuchElementException();
至
if(hasNext()) {
//...
} else {
throw new NoSuchElementException();
}
假设您的代码 return 编辑的最后一个素数是 7
。然后 current
将是 7
显然是 < 10
。所以 hasNext()
将 return true
。然而,没有更多的素数大于 7
但小于 10
,因此下一次调用 next()
将产生 NoSuchElementException
。目前,您的代码仅在 max
是素数时才有效。
您需要验证 hasNext()
中是否还有一个可用的素数。
我正在尝试为我制作的 Set 编写一个定制的迭代器。我对 Interface Iterable 的契约有点困惑。它具有三个方法:next()、hasNext() 和 remove()。我的集合是不可变的,所以我计划为方法 remove() 抛出 UnsupportedOperationException。它也被称为 "lazily generated" 即元素不存储在内存中而是在需要时创建,但它既不存在也不存在。
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() return 下一个值并在没有更多值时抛出异常。如果有更多的值要迭代,hasNext() 应该 return 为真,否则为假。然而,主循环的输出是这样的:
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 循环中没有处理异常。如何编写一个我可以使用的自定义 Iterator 才能使其正常工作?我尝试 returning null 而不是抛出异常,但这只会给出 NullPointerException。
当 Iterator 完成时,我应该 return null 还是抛出异常? Javadoc 说 next() 应该抛出异常,但是当我将鼠标悬停在 Eclipse 中覆盖的方法 next() 上时,签名不显示抛出 NoSuchElementException 所以我对合同说的很困惑。完成后 return null 对我来说似乎很奇怪,因为集合可能包含 null 元素。
感谢您的帮助。
改变
while(hasNext()) {
//...
}
throw new NoSuchElementException();
至
if(hasNext()) {
//...
} else {
throw new NoSuchElementException();
}
假设您的代码 return 编辑的最后一个素数是 7
。然后 current
将是 7
显然是 < 10
。所以 hasNext()
将 return true
。然而,没有更多的素数大于 7
但小于 10
,因此下一次调用 next()
将产生 NoSuchElementException
。目前,您的代码仅在 max
是素数时才有效。
您需要验证 hasNext()
中是否还有一个可用的素数。