Java异常
Java异常分类结构:
java.lang.Throwable 顶层父类
|– Error错误:JVM内部的严重问题,如OOM,程序员无法在代码中处理(如StackOverflowError、OutOfMemoryError)。
|–Exception异常:普通的问题。通过合理的处理,程序还可以回到正常执行流程。要求程序员要进行处理。
|–RuntimeException:未检查异常(unchecked exception)。
这类异常是程序员的逻辑问题,由于程序员的疏忽导致的错误(如数组越界,空指针等)。Java编译器不进行强制要求处理。 也就是说,这类异常在程序中,可以进行处理,也可以不处理。
|–非RuntimeException:已检查异常(checked exception)、编译时异常。
这类异常是由一些外部的偶然因素所引起的。Java编译器强制要求处理。也就是说,程序必须进行对这类异常进行处理,throw,throws或者try catch。
稳定代码:无论如何都不会出错的代码
非稳定代码:可能会出错的代码,需要进行异常捕获
throw和throws的区别:
throw是方法内部抛出异常类对象的关键字
throws则用在方法signature上,表示方法调用者可通过此方法声明向上抛出异常对象
异常的处理:
如果异常在当前方法的处理能力范围之内且没有必要对外透出,那么就直接 捕获异常并做相应处理;否则向上抛出 , 由上层方法或者框架来处理。
无论采用哪种方式处理异常 , 都严禁捕获异常后什么都不做或打印 行日 志了事。如果在方法内部处理异常 , 需要根据不同的业务场景进行定制处理 , 如重试、 回滚等操作。如果向上抛出异常,如上例 所示 , 需要在异常对象中添加上下文参数、 局部变量、运行环境等信息,这样有利于排查问题。
处理异常的最佳实践:
①:当需要向上抛出异常的时候,需根据当前业务场景定义具有业务含义的异常,优先使用行业定义的异常或者团队内部定义好的。
如在使用dubbo进行远程服务调用超时的时候会抛出DubboTimeoutException,而不是直接把RuntimeException抛出
②:请勿在finally代码块中使用return语句,避免返回值的判断变得复杂
③:捕获异常具体的子类,而不是Exception,更不是throwable。这样会捕获所有的错误,包括JVM抛出的无法处理的严重错误
④:切记更别忽视任何一个异常(catch住了不做任何处理),即使现在能确保不影响逻辑的正常运行,但是对于将来谁都无法保证代码会如何改动,别给子集挖坑
⑤:不要使用异常当做控制流程来使用,这是一个很奇葩也很影响性能的做法
⑥:清理资源,释放连接等操作一定要放在finally代码块中,防止内存泄露,如果finally块处理的逻辑比较多且模块化,我们可以封装成工具方法使用,代码会比较简洁
try代码块:
try-catch-finally 是处理异常的三部曲。当存在try时,可以只有catch代码块,也可以只有finally代码块,就是不能单独只有try代码块。
注意:finally代码块是在return表达式后执行的,此时将要return的结果暂存起来,待finally代码块执行结束后再将之前暂存的结果返回。另外,避免在finally块中使用return操作,否则会导致返回值变得不可控。
END.