Java 在foreach循环中正确处理NoTouchElementException?
当迭代器引发NoTouchElementException并停止循环执行时,为什么foreach循环不考虑 让我解释一下 通常,迭代器需要提供两个重要的方法:hasNext和next。如果没有更多的元素可迭代,则下一个方法可以引发NoTouchElementException。hasNext方法更像是一个语法建议,只是为了让代码更好一点。重要的方法是next,这是一种应该做任何工作的方法,如果有的话,但不是hasNext,它需要在没有假设hasNext已经被预先调用的情况下实现 让我们假设我们有以下情况:Java 在foreach循环中正确处理NoTouchElementException?,java,iterator,loops,Java,Iterator,Loops,当迭代器引发NoTouchElementException并停止循环执行时,为什么foreach循环不考虑 让我解释一下 通常,迭代器需要提供两个重要的方法:hasNext和next。如果没有更多的元素可迭代,则下一个方法可以引发NoTouchElementException。hasNext方法更像是一个语法建议,只是为了让代码更好一点。重要的方法是next,这是一种应该做任何工作的方法,如果有的话,但不是hasNext,它需要在没有假设hasNext已经被预先调用的情况下实现 让我们假设我们有
final Iterator<String> bogusIt01 = new Iterator<String>() {
public boolean hasNext() {
return true;
}
public String next() {
throw new NoSuchElementException("no such element");
}
public void remove() {
throw new UnsupportedOperationException("cannot remove element");
}
};
final Iterable<String> bogusPr01 = new Iterable<String>() {
public Iterator<String> iterator() {
return bogusIt01;
}
};
for (@SuppressWarnings("unused") String string:bogusPr01) {
// pass
}
这样的设计是不可能的,尽管对我来说很有意义
有更好的方法吗?来自Javadoc for
如果迭代包含更多元素,则返回true。(换句话说,如果next()将返回元素而不是引发异常,则返回true。)
一般来说,如果您未能按照指定的API进行操作,JVM不会试图猜测它应该做什么,也不会执行变通方法。相反,它将生成您得到的异常或错误
如果您正在包装一个可能导致异常的迭代器,您应该抛出该异常,或者如果您觉得最好假装它从未发生过(这在IMHO中不太可能),那么您必须在调用next()之前检查这一点
来自Javadoc的
如果迭代包含更多元素,则返回true。(换句话说,如果next()将返回元素而不是引发异常,则返回true。)
一般来说,如果您未能按照指定的API进行操作,JVM不会试图猜测它应该做什么,也不会执行变通方法。相反,它将生成您得到的异常或错误
如果您正在包装一个可能导致异常的迭代器,您应该抛出该异常,或者如果您觉得最好假装它从未发生过(这在IMHO中不太可能),那么您必须在调用next()之前检查这一点
此代码的问题在于,如果对
hasNext
的上一次调用返回true,则迭代器不应从getNext
引发NoTouchElementException
。你可以考虑这样做:
public boolean hasNext() {
return iterator1.hasNext();
}
public Object next() {
if (!iterator1.hasNext()) {
throw new NoSuchElementException("no such element");
}
Object nextValue = iterator1.next();
try {
// do something that could raise exception
} catch (Exception e) {
return this.next();
}
return productValue;
}
public void remove() {
throw new UnsupportedOperationException("cannot remove element");
}
在hasNext
中,从底层迭代器获取下一个适当的元素,并将其缓存,直到下一次调用next
。从next
返回缓存的值。如果缓存的值为null,则不会调用hasNext
,然后可以适当地抛出NSEE
您可能需要考虑的另一个选项是使用番石榴的<代码>迭代。转换或<代码>列表。转换< /代码>。这是为了获取一个
Iterable
,并对每个元素执行一些转换。您可以为任何无法转换的值返回null
,并使用谓词执行Iterables.filter
。notNull
谓词
删除非null元素
使用番石榴,上述代码为:
Function<A, B> myFunction = new Function<A,B>(){
public B apply(A input){
try{ // do work
return new B();
catch(Exception e){ return null; }
}
}
Iterable<A> inputList = ...;
Iterable<B> newList = Iterables.filter(
Iterables.transform(inputList, myFunction),
Predicates.notNull());
for (B b : newList)...
函数myFunction=新函数(){
公共B应用(A输入){
试着做工作
返回新的B();
catch(异常e){returnnull;}
}
}
Iterable inputList=。。。;
Iterable newList=Iterables.filter(
转换(inputList,myFunction),
谓词。notNull());
对于(B:新列表)。。。
<代码> <代码>的问题是,<代码> Iterator <代码>不应该从 GETNeX中抛出<代码> NouChelEngultExvuts<代码> >如果之前调用<代码>下一次返回true。您可以考虑这样做:
public boolean hasNext() {
return iterator1.hasNext();
}
public Object next() {
if (!iterator1.hasNext()) {
throw new NoSuchElementException("no such element");
}
Object nextValue = iterator1.next();
try {
// do something that could raise exception
} catch (Exception e) {
return this.next();
}
return productValue;
}
public void remove() {
throw new UnsupportedOperationException("cannot remove element");
}
在hasNext
中,从底层迭代器获取下一个适当的元素,并将其缓存到下一次调用next
之前。从next
返回缓存值。如果缓存值为null,则不会调用hasNext
,然后可以适当地抛出NSEE
您可能需要考虑的另一个选项是使用番石榴的<>代码> Itdiabor。转换<代码> >代码>列表。转换<代码> >。
谓词.notNull
谓词
删除非null元素
使用番石榴,上述代码为:
Function<A, B> myFunction = new Function<A,B>(){
public B apply(A input){
try{ // do work
return new B();
catch(Exception e){ return null; }
}
}
Iterable<A> inputList = ...;
Iterable<B> newList = Iterables.filter(
Iterables.transform(inputList, myFunction),
Predicates.notNull());
for (B b : newList)...
函数myFunction=新函数(){
公共B应用(A输入){
试着做工作
返回新的B();
catch(异常e){returnnull;}
}
}
Iterable inputList=。。。;
Iterable newList=Iterables.filter(
转换(inputList,myFunction),
谓词。notNull());
对于(B:新列表)。。。
以下内容如何
import java.util.Iterator;
public class BreakingIterator<T> implements Iterator<T> {
private Iterator<T> iterator;
private T nextValue;
private RuntimeException nextException;
/* -------------------------------------------------------------------- */
public BreakingIterator(Iterator<T> iterator) {
this.iterator = iterator;
this.nextValue = null;
this.nextException = null;
}
/* -------------------------------------------------------------------- */
public boolean hasNext() {
if (this.iterator.hasNext()) {
try {
this.nextValue = this.iterator.next();
} catch (RuntimeException e) {
this.nextValue = null;
this.nextException = e;
return false;
}
return true;
} else {
return false;
}
}
public T next() {
if (this.nextException != null) {
throw this.nextException;
} else {
return this.nextValue;
}
}
public void remove() {
this.iterator.remove();
}
}
import java.util.Iterator;
公共类BreakingIterator实现了迭代器{
私有迭代器;
私有下一价值;
私有运行时异常nextException;
/* -------------------------------------------------------------------- */
公共中断迭代器(迭代器迭代器){
this.iterator=迭代器;
this.nextValue=null;
this.nextException=null;
}
/* -------------------------------------------------------------------- */
公共布尔hasNext(){
if(this.iterator.hasNext()){
试一试{
this.nextValue=this.iterator.next();
}捕获(运行时异常e){
this.nextValue=null;
this.nextException=e;
返回false;
}
返回true;
}否则{
返回false;
}
}
公共交通工具{
if(this.nextException!=null)