Java异常处理的最佳实践

时间:2015-09-13 00:52:02

标签: java exception-handling

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

catch (Exception e){
    e.printStackTrace();
}

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

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());
    } 
    }
}

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

2 个答案:

答案 0 :(得分:14)

首先,除非您有 非常 充分理由,永远不会抓住RuntimeExceptionExceptionThrowable 。这些内容会捕获大部分内容,Throwable会抓住 所有内容 ,即使是那些意味着的内容捕获,如OutOfMemoryError

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

第三,在Java 7中,如果异常是互斥的,您可以为异常执行multi-catch语句。链接的示例很好地解释了它,但如果您遇到同时抛出IOExceptionSQLException的代码,您可以像这样处理它:

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

这可以清理一些事情,因为你不会有笨拙和巨大的例外链接。

答案 1 :(得分:7)

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

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

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

  

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

事实上,捕捉Exception等通用异常是通常良好的编码习惯。但在某些情况下这是正确的做法。你的例子就是适当的例子。

为什么?

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

    public void doSomething(...) {
        try {
            doSomethingElse(...);
        } catch (Exception ex) {
            // log it ... and continue
        }
    }

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

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

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

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

现在将问题与(假设的)良好练习版本进行对比。有什么区别?

  1. 您的版本可以产生更多用户友好/警报更少的诊断......直到某一点。
  2. 您的版本代码明显增多。
  3. 您的版本对于尝试诊断问题的人没有帮助,因为不会记录堆栈跟踪。
  4. 与1和2的对应点是:

    1. 你可以花费无限的时间来磨练用户友好的"对应用程序进行诊断,但仍无法帮助那些无法理解或无法理解的用户...
    2. 这还取决于典型用户是谁。
    3. 正如你所看到的,这远比#34更加微妙;捕捉一般异常是不好的做法"。