设为首页 加入收藏

TOP

Java异常处理的9个最佳实践(二)
2018-08-31 18:27:07 】 浏览:397
Tags:Java 异常 处理 最佳 实践
抛出 NumberFormatException 。

try {
    new Long("xyz");
} catch (NumberFormatException e) {
    log.error(e);
}

NumberFormatException 的类名已经告诉了你问题的类型。所以异常信息只需要返回导致问题的输入字符串就行了。如果异常类的名字不能表明其含义,那么你还需要在异常信息中提供必要的解释信息。

17:17:26,386 ERROR TestExceptionHandling:52 - java.lang.NumberFormatException: For input string: "xyz"

5、优先捕获具体的异常

大多数 IDE 都能帮你做到这点。当你尝试优先捕获不那么具体的异常时, IDE 会报告给你这是一个不能到达的代码块。

这个问题的原因是只有第一个匹配到异常的 catch 块才会被执行。所以,如果你先 catch 了一个 IllegalArgumentException ,你将永远无法到达处理更具体异常 NumberFormatException 的 catch 块中,因为 NumberFormatException 是 IllegalArgumentException 的子类。

所以,请优先捕获更具体的异常,并把不那么具体的 catch 块放在后面。

在下面你可以看到这样的一个 try-catch 语句示例。第一个 catch 处理所有的 NumberFormatExceptions 异常,第二个 catch 处理 NumberFormatException 异常以外的 illegalargumentexception 异常。

public void catchMostSpecificExceptionFirst() {
    try {
        doSomething("A message");
    } catch (NumberFormatException e) {
        log.error(e);
    } catch (IllegalArgumentException e) {
        log.error(e)
    }
}

6、不要捕获 Throwable

Throwable 是所有 exceptions 和 errors 的父类。虽然你可以在 catch 子句中使用它,但你应该永远别这样做!

如果你在 catch 子句中使用了 Throwable ,它将不仅捕获所有异常,还会捕获所有错误。这些错误是由 JVM 抛出的,用来表明不打算由应用处理的严重错误。 OutOfMemoryError 和 StackOverflowError 就是典型的例子,这两种情况都是由一些超出应用控制范围的情况导致的,无法处理。

所以,最好不要在 catch 中使用 Throwable ,除非你能确保自己处于一些特定情况下,比如你自己足以处理错误,又或被要求处理错误。

public void doNotCatchThrowable() {
    try {
        // do something
    } catch (Throwable t) {
        // don't do this!
    }
}

7、不要忽略异常

你分析过只有用例的第一部分代码被执行的 bug 报告吗?

这通常是由于忽略异常而导致的。开发者可能十分确定这个异常不会被抛出,然后添加了一个无法处理或无法记录这个异常的 catch 。当你找到这个 catch 时,你很可能会发现这么一句著名的注释: “This will never happen”。

public void doNotIgnoreExceptions() {
    try {
        // do something
    } catch (NumberFormatException e) {
        // this will never happen
    }
}

没错,你可能就是在分析一个永远也不会发生的问题。

所以,请你务必不要忽略异常。你不知道代码在将来会经历怎样的改动。有些人可能会误删异常事件的验证,而完全没意识到这会产出问题。或者抛出异常的代码被修改了,相同的类被抛出了多个异常,而调用它们的代码并不能阻止这些异常发生。

你至少应该把日志信息打印出来,告诉那些无意识下错误操作的人需要检查这里。

public void logAnException() {
    try {
        // do something
    } catch (NumberFormatException e) {
        log.error("This should never happen: " + e);
    }
}

8、不要同时打印并抛出异常

这可能是本文中最常被忽略的一条实践准则了。你可以在许多代码片段甚至库中发现这个问题,异常被捕获,打印,再被重新抛出。

try {
    new Long("xyz");
} catch (NumberFormatException e) {
    log.error(e);
    throw e;
}

这样也许会很直观地看到被打印的异常,异常再被重新抛出,调用者也能很好地处理它。但这样会使多个错误信息被同个异常给打印出来。

17:44:28,945 ERROR TestExceptionHandling:65 - java.lang.NumberFormatException: For input string: "xyz"
Exception in thread "main" java.lang.NumberFormatException: For input string: "xyz"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.(Long.java:965)
at com.stackify.example.TestExceptionHandling.logAndThrowException(TestExceptionHandling.java:63)
at com.stackify.example.TestExceptionHandling.main(TestExceptionHandling.java:58)

额外的信息并不能提供更多的错误细节。如第4条准则中所述,异常信息应该准确描述异常事件。 Stack Trace (堆栈追踪)会告诉你异常在哪个类、哪个方法、哪个行中被抛出。

如果你需要添加额外的信息,你应该将异常捕获并包装在自定义的的异常中,但要确保遵循下面的第9条实践准则。

public void wrapException(String input) throws MyBusinessException {
    try {
        // do something
    } catch (NumberFormatException e) {
        throw new MyBusinessException("A message that describes the error.", e);
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇一次Java内存泄漏调试的有趣经历 下一篇SpringBoot | 第十四章:基于Dock..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目