2010-02-05 84 views
25

java.lang.Iterator接口有3种方法:hasNext,nextremove。为了实现一个只读的迭代器,你要为那些2提供一个实现:hasNextnext执行java.lang.Iterator时如何处理异常

我的问题是,这些方法不声明任何异常。因此,如果我的代码在迭代过程中声明异常,我必须将我的迭代代码放在try/catch块中。

我目前的政策已经重新抛出封闭在RuntimeException例外。但是这有问题,因为检查的异常会丢失,客户端代码不再可以明确地捕获这些异常。

我怎样才能解决这个限制在迭代器类?

这里是为了清晰起见,示例代码:

class MyIterator implements Iterator 
{ 
    @Override 
    public boolean hasNext() 
    { 
     try 
     { 
      return implementation.testForNext(); 
     } 
     catch (SomethingBadException e) 
     { 
      throw new RuntimeException(e); 
     } 
    } 

    @Override 
    public boolean next() 
    { 
     try 
     { 
      return implementation.getNext(); 
     } 

     catch (SomethingBadException e) 
     { 
      throw new RuntimeException(e); 
     } 
    } 

    ... 
} 

回答

9

,我实现了很多迭代器,有时与检查的异常迭代器顶部(ResultSet是概念上记录的迭代,为InputStreamÿ概念字节迭代器)等。这非常非常好用(你可以实现很多东西的管道过滤器体系结构)。

如果您希望声明您的例外,则声明新类型的Iterator(ExceptionIterator,它将像Runnable和Callable)。您可以一起使用它或您的代码,但不能将它与外部组件(Java类库或三维方库)组合使用。

但是,如果您更喜欢使用超标准接口(如迭代器)在任何地方使用它们,那么请使用Iterator。如果你知道你的例外将是停止你的处理的条件,或者你不介意很多...使用它们。

运行时异常都没有那么可怕。举例说明。 Hibernate使用它们来实现代理和类似的东西。他们必须去除数据库异常,但不能在List的实现中声明它们。

+1

另一种选择,如果你无法控制用户界面的客户端代码:创建登记例外通过getter或一些地方入店的迭代器,或拨打一个回调接口,或者是你控制,并可以在任何地方显示错误。如果这对您有用,您可以创建一个“CatcherIterator”,它简单地包装一个运行时异常thrower迭代器,并捕获所有可能的异常,将它们重定向到属性或回调接口。 – helios 2010-02-05 08:27:52

1

如果您的实施没有你为什么要使用它通过Iterator接口所需的性能,?

我看多的RuntimeException没有其他解决办法(与它的问题)。

11

你应该重新抛出异常,因为自定义运行时例外,不是通用的一个,例如SomethingBadRuntimeException。此外,您可以尝试exception tunneling

而且我保证,迫使客户端,使它们检查处理异常是一种不好的做法。它只是污染你的代码或强制包装运行时的异常或强制处理它们,而不是呼叫,但不集中。我的政策是尽可能避免使用检查过的异常。考虑IOExceptionClosable.close():是否有用或方便?当它是情况是非常罕见的,但在世界上每一个Java开发者不得不对付它。最常见的情况是吞咽或记录最好。并想象这会增加多少code size! 有关于他们的阴暗面检查的异常一些帖子:

  1. "Does Java need Checked Exceptions?" by Bruce Eckel
  2. The Trouble with Checked Exceptions A Conversation with Anders Hejlsberg, by Bill Venners with Bruce Eckel
  3. Java Design Flaws, C2 wiki

在有些情况下,当检查的异常来抢救。但在我看来,它们很罕见,通常关注某个特定模块的实现。而且他们没有多少利润。

3

正如有人谁喜欢的Java检查的异常,我觉得现在的问题(Java的设计缺陷,如果你愿意)是标准库不支持泛型迭代器类型,其中next方法抛出检查异常。

Sesame的代码库有一个名为Iterable的Iterator变体类,它就是这样做的。 签名如下:

 
Interface Iteration<E,X extends Exception> 

Type Parameters: 
    E - Object type of objects contained in the iteration. 
    X - Exception type that is thrown when a problem occurs during iteration. 

这似乎是芝麻,其中指定的子类所使用的有限的上下文工作的“修复”异常类型参数。但是,(当然)不符合标准集合类型,Java 5的新for循环语法等进行整合。

2

hasNext真的不应该抛出一个异常 - 它应该检查它是确定以继续并在此基础上返回一个布尔值(我会记录与一个记录任何潜在的例外)。如果下一次失败,我会抛出一个RuntimeException(并用记录器记录检查的异常)。下一步不应该在正常情况下失败,如果测试是确定,如果测试失败,你不应该调用next(因此运行时除外)。

1

这个问题被问得很久以前,但我想有一个图案反馈可能是有用的这里。额外的接口或ExceptionHandler类可以其实现迭代器,并且可以通过在客户端被实现为期望的解决异常的类内组成。

public interface ExceptionHandler { 
    // Log, or rethrow, or ignore... 
    public Object handleException(Exception e); 
} 

实现类可以这样做这些:

public class ExceptionRethrower implements ExceptionHandler { 
    @Override 
    public Object handleException(Exception e) { 
     throw new RuntimeException(e); 
    } 
} 

public class ExceptionPrinter implements ExceptionHandler { 
    @Override 
    public Object handleException(Exception e) { 
     System.err.println(e); 
     return e; 
    } 
} 

对于从文件中读取一个迭代器,代码可能是这个样子:

public class MyReaderIterator implements Iterator<String> { 
    private final BufferedReader reader; 
    private final ExceptionHandler exceptionHandler; 
    public MyReaderIterator(BufferedReader r, ExceptionHandler h) { 
     reader = r; 
     exceptionHandler = h; 
    } 
    @Override 
    public String next() { 
     try { 
      return reader.readLine(); 
     } catch (IOException ioe) { 
      Object o = exceptionHandler.handleException(ioe); 
      // could do whatever else with o 
      return null; 
     } 
    } 
    // also need to implement hasNext and remove, of course 
} 

中,人们怎么想?这是值得的这种间接的层面,还是它是一个分层违规,只是简单太复杂?接口的名称可能不完全合适的(也许ExceptionProcessor或ExceptionInterceptor,因为它可以与互动,但不完全处理该异常,但仍需要在成它是由类的一些处理)。

我同意,这一切似乎只是一种变通方法给Iterator.next()未声明中抛出异常的事实,让我松了发电机和Python的异常模型。

0

我usally使用

@Override 
void remove() { 
    throws new UnsupportedOperationException("remove method not implemented"); 
} 

注:UnsupportedOperationException异常是一个RuntimeException

既然你properbly瞄准像

for (IterElem e : iterable) 
    e.action(); 

,你就会没事

1

如果你真的不想使用运行时异常,可以使用NoSuchElementException。你被允许使用它重写next()方法,因为它是宣布 Iterator定义被抛出(这个我试过和代码编译)。但是你应该考虑它是否为语义上对你的情况有效。

+0

我认为这是抛出迭代器错误 – smac89 2015-06-30 21:46:05

+0

'NoSuchElementException'是'RuntimeException'最好例外。你也可以创建你自己的'RuntimeException'的自定义扩展,它会是一样的,对吧? – boumbh 2015-10-19 09:27:44

-1

在我的脑海里,迭代器是为了迭代,他们的目的不是要计算,因此在next()方法没有throws

你问如何使用界面做一些它不是设计的。

不过,如果Iterator旨在通过自己使用(这通常是一个坏的假设),你可以定义一个公共safeNext()方法是这样的:

public Element safeNext() throws YourCheckedException { 
    ... 
} 

@Override 
public Element next() { 
    try { 
     return safeNext(); 
    } catch (YourException e) { 
     throw new YourRuntimeException("Could not fetch the next element", e); 
    } 
} 

然后,当使用Iterator即可选择使用safeNext()和处理检查异常,或者,你会与任何迭代器使用next()

简而言之,你不能同时拥有迭代器接口的便利性(你不能指望Iterable对象将使用safeNext()方法)和检查的异常抛出。