为什么是Java’;s异常处理语句不应被视为非局部分支的一般机制?
阅读Herbert Schildt:完整参考第10章异常处理 异常处理提供了一种强大的机制来控制复杂的程序 具有许多动态运行时特性。重要的是要考虑尝试、投掷和接球 作为处理程序逻辑中错误和异常边界条件的干净方法。 与其他一些使用错误返回码表示失败的语言不同,Java 使用异常。因此,当一个方法可能失败时,让它抛出一个异常。这是一个清洁工 处理故障模式的方法。 最后一点:Java的异常处理语句不应被视为通用语句 非局部分支的机制。如果您这样做,它只会混淆您的代码并使其无效 很难维持 他所说的“非局部分支”是什么意思?请用一个很好的例子来详细说明 请注意,这个问题是在coderanch上提出的,但那里的答案主要基于个人为什么是Java’;s异常处理语句不应被视为非局部分支的一般机制?,java,exception-handling,Java,Exception Handling,阅读Herbert Schildt:完整参考第10章异常处理 异常处理提供了一种强大的机制来控制复杂的程序 具有许多动态运行时特性。重要的是要考虑尝试、投掷和接球 作为处理程序逻辑中错误和异常边界条件的干净方法。 与其他一些使用错误返回码表示失败的语言不同,Java 使用异常。因此,当一个方法可能失败时,让它抛出一个异常。这是一个清洁工 处理故障模式的方法。 最后一点:Java的异常处理语句不应被视为通用语句 非局部分支的机制。如果您这样做,它只会混淆您的代码并使其无效 很难维持 他所说的“非局
因此,它没有给出一个基于根的答案(我无法通过那边的讨论阐明这一点)。这里是一个本地分支的示例:
void foo() {
if (someCondition) {
doSomething();
} else {
doSomethingElse();
}
}
分支很容易理解,对吗?之所以如此简单,是因为所有分支逻辑都是在foo
中定义的。可以说是本地的。这意味着,将根据someCondition
检查一个条件并选择其路径,但分支不会逃逸foo
。只要看一下这个方法,您就知道代码流可能是什么样子
现在想想这个可读性较差的实现:
void foo() {
if(bar()) {
// branch is handled by bar
} else {
doSomethingElse();
}
}
boolean bar() {
if(somethingWrong) {
return false;
}
doSomething();
}
这是不太可读的。但为什么呢?如果从foo
调用方法bar
,则控制流由bar
处理<但是,code>bar可能会执行意外操作,并且仍然依赖foo
来处理此意外情况。这不是一个好的做法,因为您在foo
和bar
之间分配连接的逻辑,其中一个位置的更改可能导致另一个位置的错误行为。这在某种程度上是异常在堆栈中被处理得太深时所做的。您甚至可以通过添加更多中间方法来扩展上述示例的复杂性。因此,这本书建议,保持局部分支,因为这通常更易于人类阅读和追踪,我同样认为这是一个好主意。查看上述代码的基于异常的实现,以更直观地了解这一点:
void foo() {
try {
bar()
} catch(SomeException e) {
doSomethingElse();
}
}
boolean bar() {
if(somethingWrong) {
throw new SomeException();
}
doSomething();
}
显然,这个分布式分支比
if
-else
语句更容易出错。例如,使用NumberFormatException测试用户的输入是否为数字。我认为这与设置和捕获异常的计算复杂性有关,而不是更传统的流控制。但我不能详细说明,这就是为什么这是一个注释而不是答案。我认为“Java的异常处理语句不应该被视为非局部分支的一般机制”表示使用异常冒泡机制通过调用调用堆栈上的catch
块中的其他函数来分支到其他函数(类似于使用goto
语句进行非本地分支)。这打破了传统的控制流程,使得逻辑难以理解和维护。coderanch上的答案似乎表明了同样的事情。你确定这就是Herbert Schildt所说的非局部分支吗?或者还有更多。我只是在猜测什么会迫使我在程序中使用第二个版本(上面可读性较差的版本)?@ShirgillAnsari,因为分支中的处理非常复杂,需要自己的方法甚至类。事实上,Replace Conditional with polymorphics重构完全消除了if
语句,并要求为不同的行为创建单独的类。@ShirgillAnsari是的,我很确定这就是它的意思。非局部分支总是考虑分布在方法之间的分支。在Java中,这只能通过异常实现。