Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
例外情况+;发出迭代器结束的信号:为什么Java中的迭代器不好而Python中的迭代器正常?_Java_Python_Exception - Fatal编程技术网

例外情况+;发出迭代器结束的信号:为什么Java中的迭代器不好而Python中的迭代器正常?

例外情况+;发出迭代器结束的信号:为什么Java中的迭代器不好而Python中的迭代器正常?,java,python,exception,Java,Python,Exception,我真的很困惑:Java中的标准方法是只在“异常”条件下抛出异常,而不使用它们来表示迭代器的结束 示例:有效Java,第57项(“仅在例外情况下使用例外”),以及: 流量控制 我们决不应该造成一个本来可以预防的例外情况。我见过这样的代码:不检查边界,而是假设数据是正确的,然后捕获运行时异常: 下面是一个错误代码的示例(请不要这样编写代码): 然而,在Python中使用此习语是标准的,例如: 异常停止迭代 由迭代器的next()方法引发,表示没有其他值。这是从Exception而非StandardE

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

示例:有效Java,第57项(“仅在例外情况下使用例外”),以及:

流量控制

我们决不应该造成一个本来可以预防的例外情况。我见过这样的代码:不检查边界,而是假设数据是正确的,然后捕获运行时异常:

下面是一个错误代码的示例(请不要这样编写代码):

然而,在Python中使用此习语是标准的,例如:

异常停止迭代

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


为什么它对Java不好而对Python好呢?

Java有时也会这样:“所有方法的实现都使用而不是返回值。”在这种情况下,无法使用通常的哨兵值,
-1
StopIteration
存在于Python中,用于对任何序列进行简单迭代


使用异常来实现这一点是一种设计选择,它与Java的异常思维并不矛盾。当没有更多元素时调用迭代器的
next()
方法是一种异常情况,在
for
循环中在幕后捕获该异常是一种非常简单的方法,可以实现“获取项直到没有剩余项为止”。Python和Java处理异常的方法截然不同。在Python中,异常是正常的。在Python词汇表中查找(请求原谅比请求许可更容易)。还要检查你要说什么

StopIteration只是EAFP的一个例子——继续,从迭代器中获取下一个内容,如果失败,处理错误

如果代码在非本地出口时可读性更好,那么在Python中可以使用异常。你不会开支票,如果事情不顺利,你只会处理失败。这绝对没有什么可耻的,事实上这是被鼓励的。与Java不同


现在对于一个特殊的停止迭代的例子:考虑。 要支持某种类型的
has_next()
方法,生成器必须检查下一个值,在请求
2
之前触发
打印。必须在迭代器中记住该值(或引发的异常)。如果调用了两次
has_next
,则只有第一个会触发副作用。或者下一个值总是可以预先计算的,即使它不是必需的

我发现Python的语义——只在需要下一个值时计算——是最好的选择


当然,Java没有可恢复的生成器,所以很难在这里进行比较。但是有一些轶事证据表明StopIteration比hasNext()概括得更好。

对此没有正确或错误的答案。异常处理是一种中立的控制流构造,它的最佳使用取决于上下文和样式

在本例中,Java和Python都做了相同的事情,原因相同:
Java.util.Iterator
使用
NoTouchElementException
来表示迭代器的结束。这在两种语言中都是很好的风格:出于各种原因,使用特殊的sentinel返回值的替代方法要差得多

作为经验法则,每当编写一个函数,它希望发出不止一种控制流返回时,应该考虑使用异常。这包括异常错误情况,但异常信号的良好使用当然不限于此。

没有什么可以阻止您使用java中的异常, 它看起来很难看,至少对java开发人员来说是这样

主要原因是异常的StackTrace非常昂贵, 而且,java开发人员可能会稍微关心一点 比Python开发人员更关注计算资源的使用

Java也是一种相当“干净”的语言——有些人会说它是原教旨主义的, 这就是为什么它是一门好语言的原因之一。(*见评论)

无论如何。原教旨主义者(和一些普通人)认为,对正常流程使用异常不是正确的方法…:-)

但除此之外,最近的jvm检测到您正在生成大量堆栈跟踪
对于相同的代码点,实际上会在没有异常的情况下“过一段时间”抛出异常,以加快速度。

不建议使用它的原因是,在java中,异常处理的处理和恢复成本通常很高。当抛出异常时,它会导致jvm返回正在执行的操作,以提供堆栈跟踪,这对性能来说从来都不是一件好事。简而言之,这是语言误用——通常会有一种更干净、更有效的处理逻辑的方法。考虑下面的代码:

try {

    int x = service.getValue();

    if(x > 5)
        throw new NumberTooBigException("Too Big");
    else
        throw new NumberTooSmallException("Too Small");

} catch (NumberTooBigException e) {

    System.out.println("i think it's too big...");

} catch (NumberTooSmallException e) {

    System.out.println("i think it's too small...");

}
更好的方法是使用java的预期控制逻辑:

if(x > 5)
    System.out.println("i think it's too big...");
else
    System.out.println("i think it's too small...");
从比较这两个代码段可以看出,异常处理有点荒谬——对于示例的意图来说,这是一种过分的处理。对于您发布的示例,更好的方法如下:

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
    }
  }
}
String[] args = {"one", "two", "three"};
for(String arg : args)
    System.out.println(args);
}

异常更适合于出现问题时使用,例如IOException(“设备上没有剩余空间”)、ClassNotFoundException(“找不到要运行的代码”)或NoRouteToHostException(“无法连接到主机”)。

Java捕获执行堆栈中的异常非常缓慢:

如果您在控制流传递中使用异常
null
作为
Throwable
。否则,将通过
super
调用的层次结构调用以下标准Java库代码:

public Throwable() {
    fillInStackTrace();
}

public synchronized Throwable fillInStackTrace() {
    if (stackTrace != null ||
        backtrace != null /* Out of protocol state */ ) {
        fillInStackTrace(0);
        stackTrace = UNASSIGNED_STACK;
    }
    return this;
}

private native Throwable fillInStackTrace(int dummy);

在Python中也会出现类似的用例,但事实并非如此——在Python中,您并不局限于单一的返回类型
public Throwable() {
    fillInStackTrace();
}

public synchronized Throwable fillInStackTrace() {
    if (stackTrace != null ||
        backtrace != null /* Out of protocol state */ ) {
        fillInStackTrace(0);
        stackTrace = UNASSIGNED_STACK;
    }
    return this;
}

private native Throwable fillInStackTrace(int dummy);