为什么我们需要异常处理?

qwe*_*rty 14 syntax exception-handling

我可以检查输入,如果是用户的无效输入,我可以使用简单的"if条件"打印"输入无效,请重新输入"(如果输入无效).

这种方法"如果有可能发生故障,使用if条件验证它,然后在遇到故障时指定正确的行为......"对我来说似乎已经足够了.

如果我基本上可以用这种方法覆盖任何类型的失败(除以零等),为什么我需要这个整个异常处理机制(异常类和对象,检查和取消选中等)?

bar*_*nos 5

假设你有一些输入func1调用func2.

现在,假设func2由于某种原因失败了.

你的建议是处理内部的失败func2,然后返回func1.

如何func1"知道"发生了什么错误(如果有的话)func2以及如何从这一点开始?

想到的第一个解决方案是func2将返回的错误代码,通常,零值将表示"OK",而其他(非零)值中的每个将表示已发生的特定错误.

这种机制的问题在于它限制了您添加/处理新错误代码的灵活性.

使用异常机制,您有一个通用Exception对象,可以扩展到任何特定类型的异常.在某种程度上,它类似于错误代码,但它可以包含更多信息(例如,错误消息字符串).

当然,你仍然可以争辩说," try/catch那么,那是什么呢?为什么不简单地归还这个对象?".

幸运的是,这个问题已经在这里得到了非常详细的回答:

在C++中,使用异常和try/catch而不仅仅返回错误代码有什么好处?

一般而言,错误代码的异常有两个主要优点,两者都是正确编码的不同方面:

  1. 除了例外,程序员必须处理它或者"向上"抛出它,而使用错误代码,程序员可能会错误地忽略它.

  2. 使用异常机制,您可以编写更"干净"的代码并将所有内容"自动处理",并且使用错误代码,您必须实现"乏味" switch/case,可能在"调用堆栈"中的每个函数中.


Adr*_*ter 5

与返回代码相比,异常是一种处理异常执行流的更面向对象的方法。返回码的缺点是您必须使用“特殊”值来表示不同类型的特殊结果,例如:

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类层次结构