项目管理这些事儿程序员

Java异常处理最佳实践

2020-03-15  本文已影响0人  梦孤
59059b1620f8a_610.jpg

我们为什么要做异常处理

异常处理的一些约束

异常的处理依赖编程语言的机制,所以也会有一些语言层面的约束

异常处理的原则

异常的相关概念

怎么处理异常?

我们所有处理异常的方式,都是为上面的第一点和第二点服务的,同时受第三点的约束。

对异常进行文档说明

如果方法上有抛出异常,则在方法注释中需要说明异常在说明情况下回抛出;

/**
 * This method does something extremely useful ...
 *
 * @param input
 * @throws MyBusinessException if ... happens
 */
public void doSomething(String input) throws MyBusinessException {
    ...
}

对抛出的异常进行明确的说明&包装异常时不要抛弃原始异常

private void fireException(){
    try {
        throw new NullPointerException();
    } catch (NullPointerException e) {
        // 异常信息中提供尽可能多的对定位问题有帮助的信息
        throw new BizException("没有找到匹配商品,id="+prodId,e);
    }
}

使用标准异常(JDK&Spring)

如果使用内建的异常可以解决问题,就不要定义自己的异常。Java API 提供了上百种针对不同情况的异常类型,在开发中首先尽可能使用 Java API 提供的异常,如果标准的异常不能满足你的要求,这时候创建自己的定制异常。尽可能得使用标准异常有利于新加入的开发者看懂项目代码。

NullPointerException 处理

SpringMVC统一处理异常

@ControllerAdvice // 通过注解拦截所有@RequestMapping
public class GlobalExceptionHandler {
    ...
}

只从方法中抛出相关异常

相关性对于保持应用程序清洁非常重要。 一种尝试读取文件的方法; 如果抛出NullPointerException,那么它不会给用户任何相关的信息。 相反,如果这种异常被包裹在自定义异常中,则会更好。 NoSuchFileFoundException则对该方法的用户更有用。


一些异常处理的典型反例

不要捕获 Throwable

Throwable 是所有异常和错误的超类。你可以在 catch 子句中使用它,但是你永远不应该这样做!

如果在 catch 子句中使用 Throwable ,它不仅会捕获所有异常,也将捕获所有的错误。JVM 抛出错误,指出不应该由应用程序处理的严重问题。 典型的例子是 OutOfMemoryError 或者 StackOverflowError。两者都是由应用程序控制之外的情况引起的,无法处理。

所以,最好不要捕获 Throwable ,除非你确定自己处于一种特殊的情况下能够处理错误。

在调用RPC、二方包、或动态生成类的相关方法时,捕捉异常必须使用Throwable类来进行拦截。 说明:通过反射机制来调用方法,如果找不到方法,抛出NoSuchMethodException。什么情况会抛出NoSuchMethodError呢?二方包在类冲突时,仲裁机制可能导致引入非预期的版本使类的方法签名不匹配,或者在字节码修改框架(比如:ASM)动态创建或修改类时,修改了相应的方法签名。这些情况,即使代码编译期是正确的,但在代码运行期时,会抛出NoSuchMethodError。

不要忽略异常

很多时候,开发者很有自信不会抛出异常,因此写了一个catch块,但是没有做任何处理或者记录日志。

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

不要记录并抛出异常

不要记录并抛出异常,这会给同一个异常输出多条日志。

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

不要使用异常控制程序的流程

不应该使用异常控制应用的执行流程,例如,本应该使用if语句进行条件判断的情况下,你却使用异常处理,这是非常不好的习惯,会严重影响应用的性能。

不要直接catch大段代码,并抛出大异常

catch时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码。对于非稳定代码的catch尽可能进行区分异常类型,再做对应的异常处理。 说明:对大段代码进行try-catch,使程序无法根据不同的异常做出正确的应激反应,也不利于定位问题,这是一种不负责任的表现。 正例:用户注册的场景中,如果用户输入非法字符,或用户名称已存在,或用户输入密码过于简单,在程序上作出分门别类的判断,并提示给用户。

上一篇 下一篇

猜你喜欢

热点阅读