异常+信令结束迭代器:为什么它在Java中是坏的而在Python中是正常的?

Jas*_*n S 12 python java exception

我真的很困惑:Java中的标准方法是仅在"异常"条件下抛出异常,而不是使用它们来表示迭代器结束.

示例:Effective Java,第57项("仅针对特殊情况使用例外")和JavaSpecialists新闻通讯162:

流量控制

我们永远不应该导致一个可以预防的例外.我已经看到代码而不是检查边界,假设数据是正确的,然后捕获RuntimeExceptions:

这是一个坏代码的例子(请不要像这样编码):

public class Antipattern1 {
   public static void main(String[] args) {
     try {
       int i = 0;
       while (true) {
         System.out.println(args[i++]);
       }
     } catch (ArrayIndexOutOfBoundsException e) {
       // we are done
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

而在Python中使用这个习惯标准的,例如StopIteration:

例外StopIteration

由迭代器的next()方法引发,表示没有其他值.这是从Exception而不是StandardError派生的,因为这在其正常应用程序中不被视为错误.

为什么它对Java不好但对Python有好处?

Pet*_*rin 7

Python和Java有很多不同的异常方法.在Python中,异常是正常的.在Python词汇表中查找EAFP(更容易请求宽恕而不是权限).还要检查维基百科的内容.

StopIteration只是EAFP的一个例子 - 只需继续从迭代器中获取下一个东西,如果失败,则处理错误.

如果代码在非本地出口处更具可读性,则在Python中使用异常.你不写支票,如果事情没有成功,你只需处理失败.对它来说绝对没有什么可耻的,事实上它是鼓励的.与Java不同.


现在针对StopIteration的特定情况:考虑生成器函数.

def generator():
    yield 1
    print('Side effect')
    yield 2
Run Code Online (Sandbox Code Playgroud)

为了支持某种has_next()方法,生成器必须检查下一个值,print2被要求之前触发.必须在迭代器中记住值(或引发的异常).如果has_next被调用两次,则只有第一个会触发副作用.或者,即使不需要,也可以预先计算下一个值.

我发现了Python的语义 - 只有在需要下一个值时才进行计算 - 这是最好的选择.

当然Java没有可恢复的生成器,所以这里很难比较.但是有一些传闻证据表明StopIteration比hasNext()更好地概括.