Java异常处理的最佳实践

Gua*_*ang 9 java exception-handling

我最近写了下面的代码; 它使用了很多异常处理.我认为它使代码看起来非常难以理解.我可以通过捕获泛型异常来缩短代码,例如

catch (Exception e){
    e.printStackTrace();
}
Run Code Online (Sandbox Code Playgroud)

但我也听说过捕获一般异常不是一个好的编码实践.

public class DataAnalyzerTester {
    /**
     * @param args args[0] stores the filename
     * @exception NoSuchElementException if user attempts to access empty list element
     * @exception ArithmeticException if user attempts to divide by 0
     * @exception ArrayIndexOutOfBoundsException if user supplied less than 3 arguments
     * @exception IOException problems with creating and writing files
     * @exception RuntimeException if user attempts to pass empty list to constructor
     */
    public static void main(String[] args) {

    try{
        //some code

    } catch (NoSuchElementException e) {
        System.out.println("Accessing element that does not exist: " + e.toString());
    } catch (ArithmeticException e) {
        System.out.println("Division by zero: " + e.toString());
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("Please supply a command line arguement that specifies your file path: " + e.toString());
    } catch (IOException e) {
        System.out.println("Other IO errors: " + e.toString());
    } catch (RuntimeException e) {
        System.out.println(e.toString());
    } 
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否有更好,更清晰的方法来捕获多个异常.

Mak*_*oto 15

首先,除非你有非常充分的理由,永远也赶不上RuntimeException,ExceptionThrowable.这些将赶上抛出任何东西,而且Throwable会抓住一切,即使是那些你没有的东西的意思捉,像OutOfMemoryError.

其次,避免捕获运行时异常,除非它直接阻碍程序的关键操作.(但是说真的,如果有人看到你抓到了NullPointerException,他们完全有权在你身上打电话给你.)你唯一需要注意的例外是那些你需要处理的例外.在您的例外列表中,您唯一应该打扰的是IOException.其余的是没有足够的测试或草率编码的结果; 那些不应该在您的应用程序的正常运行时间内发生.

第三,在Java 7中,如果异常是互斥的,您可以为异常执行多捕获语句.链接的示例很好地解释了它,但是如果你遇到抛出an IOException和an的代码SQLException,你可以像这样处理它:

try {
    // Dodgy database code here
catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
}
Run Code Online (Sandbox Code Playgroud)

这会清理一些事情,因为你没有笨拙和庞大的异常链.

  • “记录并抛出”是有问题的做法,因为它会导致在多个级别上重复记录。 (2认同)

Ste*_*n C 7

首先,"最佳实践"建议的问题在于它倾向于过度简化问题和答案.然后有人(像你一样)出现并注意到它是矛盾的.

国际海事组织,最佳做法是采取"最佳做法"建议和经常使用这一短语怀疑的人.尝试自己理解真正的问题,并得出自己的结论......而不是仅仅依靠别人告诉你什么是"最佳实践".


那么这里的问题是什么?这是声明:

但我也听说过捕获一般异常不是一个好的编码实践.

实际上,捕获通用异常通常不是很好的编码实践Exception.但在某些情况下这是正确的做法.你的例子就是适当的例子.

为什么?

好吧,让我们看一下捕捉Exception是一个坏主意的情况:

    public void doSomething(...) {
        try {
            doSomethingElse(...);
        } catch (Exception ex) {
            // log it ... and continue
        }
    }
Run Code Online (Sandbox Code Playgroud)

为什么这是一个坏主意?因为这catch将抓住并处理意外的异常; 即您(开发人员)认为不可能的例外,或者您甚至没有考虑的例外情况.没关系...但是代码会记录异常,并继续运行,好像什么都没发生一样.

这是真正的问题...... 试图从意外的异常中恢复.

(从不捕获通用异常)的(所谓的)"最佳实践"建议涉及该问题,但是以粗略的方式处理边缘情况.其中一个边缘情况是,如果您立即关闭应用程序,捕获(并记录)一般异常就行了......就像您正在做的那样.

    public void main(...) {
        try {
            // ...
        } catch (Exception ex) {
            // log exception
            System.err.println("Fatal error; see log file");
            System.exit(1);
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在将其与你问题中的(假定的)良好练习版本进行对比.有什么不同?

  1. 您的版本产生了更多用户友好/警报更少的诊断......在某种程度上.
  2. 您的版本代码明显更多.
  3. 您的版本对于尝试诊断问题的人没有帮助,因为没有记录堆栈跟踪.

与1和2的对应点是:

  1. 您可以花费无限的时间为应用程序进行"用户友好"诊断,但仍然无法帮助那些不能或不会理解的用户......
  2. 它还取决于典型用户是谁.

正如您所看到的,这比"捕获通用异常是不良做法"更加微妙.

  • 如果您询问工程师,例如 EE,他会告诉您没有“最佳实践”这样的东西。手头的任务只有最好的解决方案,这取决于无数的预算:价格、成本、功耗、尺寸、所需的使用寿命……一系列因素在您的职业生涯中可能永远不会再出现。 (2认同)
  • ... 或者您迄今为止在职业生涯中从未遇到过的。另请阅读:http://www.satisfice.com/blog/archives/27 ... (2认同)