【问题标题】:Best practice for Java exception handlingJava 异常处理的最佳实践
【发布时间】:2015-09-13 00:52:01
【问题描述】:

我最近写了以下代码;它使用了大量的异常处理。我认为它使代码看起来非常不可读。我可以通过捕获通用异常来缩短代码,例如

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

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

【问题讨论】:

  • 对不起,我复制粘贴的时候不小心把它删了
  • 您的问题似乎是在寻求一种万能的解决方案,而我认为这种解决方案不存在。异常处理细节将取决于程序本身的需求和结构。
  • 好吧,我会说您捕获了一个一般异常,然后使用 if 语句来确定哪个异常是哪个异常并执行相应的操作。这样你只需要一个捕获。 (如果这是你想要的)
  • 一篇关于这个主题的好文章:stackify.com/best-practices-exceptions-java

标签: java exception-handling


【解决方案1】:

首先,除非您有非常充分的理由,否则永远不要抓住RuntimeExceptionExceptionThrowable。它们会捕捉到大部分抛出的东西,Throwable 会捕捉到所有东西,即使是那些你不想捕捉的东西,比如OutOfMemoryError.

其次,避免捕获运行时异常,除非它直接妨碍程序的关键操作。 (但说真的,如果有人看到你抓住了NullPointerException,他们完全有权叫你出来。)你应该打扰的唯一例外是那些你需要处理的例外。在您的例外列表中,您应该打扰的唯一一个是IOException。其余的都是测试不够,或者编码草率的结果;这些不应该在您的应用程序的正常运行时发生。

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

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

这会稍微清理一下,因为您无需捕获笨重且庞大的异常链。

【讨论】:

  • 感谢您为我解决问题。我完全同意你的看法。似乎我太依赖异常了。像 ArrayIndexOutOfBoundsException 和 NoSuchElementException 之类的东西,我不应该依赖异常来完成这项工作..
  • 劝阻人们不要在高层次上使用 catch 似乎不是很好的 IMO。我们应该鼓励人们理解异常而不是忽视它们。而且您的“非常好的理由”被夸大了,无论如何您通常只登录异常,并且在某种程度上,如果您至少发现意外异常,您很可能总是想记录,我们不应该告诉人们这是不好的做法这样做。捕捉 throwable 很糟糕,我给你这个,但捕捉 RuntimeException 我希望经常看到。
  • “Log and throw”是有问题的做法,因为它会导致在多个级别上重复记录。
【解决方案2】:

首先,“最佳实践”建议的问题在于它倾向于过度简化问题和答案。然后有人(比如你自己)出现并注意到这是矛盾的1

IMO,最佳做法是听取“最佳做法”建议,并且经常使用该短语的人怀着健康的怀疑态度。尝试自己了解真正的问题,并得出自己的结论……而不是仅仅依靠别人告诉你什么是“最佳实践”。

1 - 或者更糟......他们没有注意到矛盾、边缘情况等,并且盲目地遵循所谓的“最佳实践”。有时,他们会发现自己处于黑暗中,因为“最佳实践”建议不合适。


那么这里的问题是什么?就是这样的说法:

但我也听说捕获泛型异常并不是一个好的编码习惯。

事实上,通常捕获像Exception 这样的通用异常并不是一个好的编码习惯。但在某些情况下这样做是正确的。你的例子是合适的。

为什么?

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

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

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

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

“从不捕获一般异常”的(所谓的)“最佳实践”建议处理了这个问题,但以一种不处理边缘情况的粗略方式。一种极端情况是,如果您立即关闭应用程序,那么捕获(和记录)一般异常是可以的……就像您正在做的那样。

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

现在将其与您问题中的(假定的)良好实践版本进行对比。有什么区别?

  1. 您的版本产生了更用户友好/更少令人担忧的诊断......在一定程度上。
  2. 您的版本明显更多代码。
  3. 您的版本对试图诊断问题的人没有帮助,因为堆栈跟踪没有记录。

1 和 2 的对应点是:

  1. 您可以花费无限的时间来磨练应用程序的“用户友好”诊断,但仍然无法帮助那些无法或不会理解的用户......
  2. 这还取决于典型用户是谁。

如您所见,这比“捕获通用异常是不好的做法”要微妙得多。

【讨论】:

  • 只有在执行预期捕获除错误之外的所有内容的异常层次结构时,捕获通用异常才是一个好习惯。例如,从最具体的异常到不太具体的异常,最后是异常。但在所有情况下,它都可能是一种信息丢失选项。更具体的异常可能带有一般异常类没有的细节。那时,您已经丢失了可能有助于某人进行故障分析的信息。
  • 您是否应该这样做取决于上下文。如果你只是给他们完整的堆栈跟踪......并且不要用可能掩盖真正问题的“有用”的东西使代码复杂化,那么正在做故障分析的人是最好的
  • 如果你问工程师,例如EE,他会告诉您没有“最佳实践”之类的东西。对于手头的任务,只有最佳解决方案,这取决于无数的预算:价格、成本、功耗、尺寸、所需的寿命,......在你的职业生涯中可能永远不会再出现的一系列因素。跨度>
  • ... 或者您迄今为止在职业生涯中从未遇到过的。另请阅读:satisfice.com/blog/archives/27 ...
  • 值得解释。当我们真的不想花时间去理解时,我们都可能会被“最佳实践”抓住。
猜你喜欢
  • 2011-12-09
  • 2018-01-03
  • 1970-01-01
  • 1970-01-01
  • 2017-05-11
  • 2013-05-09
  • 2011-11-10
  • 1970-01-01
  • 2013-04-22
相关资源
最近更新 更多