qwe*_*rty 14 syntax exception-handling
我可以检查输入,如果是用户的无效输入,我可以使用简单的"if条件"打印"输入无效,请重新输入"(如果输入无效).
这种方法"如果有可能发生故障,使用if条件验证它,然后在遇到故障时指定正确的行为......"对我来说似乎已经足够了.
如果我基本上可以用这种方法覆盖任何类型的失败(除以零等),为什么我需要这个整个异常处理机制(异常类和对象,检查和取消选中等)?
假设你有一些输入func1
调用func2
.
现在,假设func2
由于某种原因失败了.
你的建议是处理内部的失败func2
,然后返回func1
.
如何func1
"知道"发生了什么错误(如果有的话)func2
以及如何从这一点开始?
想到的第一个解决方案是func2
将返回的错误代码,通常,零值将表示"OK",而其他(非零)值中的每个将表示已发生的特定错误.
这种机制的问题在于它限制了您添加/处理新错误代码的灵活性.
使用异常机制,您有一个通用Exception
对象,可以扩展到任何特定类型的异常.在某种程度上,它类似于错误代码,但它可以包含更多信息(例如,错误消息字符串).
当然,你仍然可以争辩说," try/catch
那么,那是什么呢?为什么不简单地归还这个对象?".
幸运的是,这个问题已经在这里得到了非常详细的回答:
在C++中,使用异常和try/catch而不仅仅返回错误代码有什么好处?
一般而言,错误代码的异常有两个主要优点,两者都是正确编码的不同方面:
除了例外,程序员必须处理它或者"向上"抛出它,而使用错误代码,程序员可能会错误地忽略它.
使用异常机制,您可以编写更"干净"的代码并将所有内容"自动处理",并且使用错误代码,您必须实现"乏味" switch/case
,可能在"调用堆栈"中的每个函数中.
与返回代码相比,异常是一种处理异常执行流的更面向对象的方法。返回码的缺点是您必须使用“特殊”值来表示不同类型的特殊结果,例如:
public double calculatePercentage(int a, int b) {
if (b == 0) {
return -1;
}
else {
return 100.0 * (a / b);
}
}
Run Code Online (Sandbox Code Playgroud)
上面的方法使用返回码-1表示失败(因为它不能除以零)。这会起作用,但是您的调用代码需要了解此约定,例如,可能会发生这种情况:
public double addPercentages(int a, int b, int c, int d) {
double percentage1 = calculatePercentage(a, b);
double percentage2 = calculatePercentage(c, c);
return percentage1 + percentage2;
}
Run Code Online (Sandbox Code Playgroud)
乍一看,上面的代码看起来不错。但是,当b或d为零时,结果将是意外的。computePercentage将返回-1并将其添加到其他可能不正确的百分比中。编写addPercentages的程序员直到测试它之前,直到他真正检查结果的有效性时,才意识到该代码中存在错误。
除例外,您可以执行以下操作:
public double calculatePercentage(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Second argument cannot be zero");
}
else {
return 100.0 * (a / b);
}
}
Run Code Online (Sandbox Code Playgroud)
调用此方法的代码将在不进行异常处理的情况下进行编译,但是如果使用不正确的值运行,它将停止。这通常是首选的方法,因为它让程序员决定是否以及在何处处理异常。
如果要强制程序员处理此异常,则应使用检查的异常,例如:
public double calculatePercentage(int a, int b) throws MyCheckedCalculationException {
if (b == 0) {
throw new MyCheckedCalculationException("Second argument cannot be zero");
}
else {
return 100.0 * (a / b);
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,calculatePercentage必须在其方法签名中声明异常。必须像这样声明已检查的异常,并且调用代码必须捕获它们或在其自己的方法签名中声明它们。
我认为许多Java开发人员目前都同意检查异常是位侵入性的,因此大多数API最近都倾向于使用非检查异常。
上面检查的异常可以这样定义:
public class MyCheckedCalculationException extends Exception {
public MyCalculationException(String message) {
super(message);
}
}
Run Code Online (Sandbox Code Playgroud)
如果您正在开发具有多个类和方法的组件,而其他几个组件使用了此类,并且想要使您的API(包括异常处理)非常清晰,那么创建这样的自定义异常类型就很有意义。
(请参阅Throwable类层次结构)