实现java.lang.Iterator时如何处理异常

2022-09-01 12:11:35

java.lang.Iterator 接口有 3 种方法:、 和 。为了实现只读迭代器,您必须为其中 2 个提供实现:和 。hasNextnextremovehasNextnext

我的问题是这些方法不声明任何异常。因此,如果我在迭代进程中的代码声明异常,则必须将迭代代码包含在 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);
        }
    }

    ...
}

答案 1

例如,应将异常作为自定义运行时异常(而不是通用异常)重新抛出。此外,还可以尝试异常隧道SomethingBadRuntimeException

而且我确信,通过检查异常来强制客户处理异常是一种不好的做法。它只是污染了你的代码,或者强迫用运行时的异常包装异常,或者强制处理它们来代替调用但不集中。我的策略是尽可能避免使用已检查的异常。考虑一下Closable.close()上的IOException:它是有用还是方便?这种情况非常罕见,但世界上每个Java开发人员都被迫处理它。大多数情况下,它充其量是吞咽或记录的。想象一下,这会增加多少代码大小!有一些关于检查异常的帖子来自他们的黑暗面:

  1. “Java 需要检查异常吗?”作者:Bruce Eckel
  2. The Problem with Check Exceptions A Conversation with Anders Hejlsberg, by Bill Venners with Bruce Eckel
  3. Java 设计缺陷,C2 维基

在某些情况下,检查的异常会来救援。但在我看来,它们很少见,通常涉及某些特定模块的实现。而且他们不会给很多利润。


答案 2

我已经实现了很多迭代器,有时是在带有检查异常迭代器之上的(ResultSet在概念上是一个记录迭代器,InputStream y在概念上是一个字节迭代器)等等。它非常非常好,很方便(你可以为很多事情实现管道和过滤器架构)。

如果你更喜欢声明你的异常,那么声明一种新类型的迭代器(ExceptionIterator,它就像Runnable和Callable)。你可以使用它或你的代码,但你不能用外部组件(Java类库或3d参与方库)来编写它。

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

运行时异常并不那么可怕。以身作则。Hibernate使用它们来实现代理和类似的东西。他们必须排除数据库异常,但不能在 List 的实现中声明它们。