摘要
本文注意关于 JAVA 异常和日志的使用方法及注意事项。
概述
JAVA 中的异常处理,比别的语言都要优秀。使用异常和日志的目的是为了便于后续的维护。
JAVA 中的异常要求:
-
异常应当描述导致当前异常发生的原因
-
需跟进异常栈快速定位到异常发生的位置
-
结合异常描述和异常栈解决异常
异常的分类
Error
Exception
RuntimeExcepotion unChecked
可预测异常;
需捕捉异常;
可投出异常;
Checked
引起注意型;
坦然处置型;
异常使用的原则
非必要时候,不要使用异常
因为异常会消耗资源。没有必要的情况下,不需要异常。
使用描述性消息抛出异常
能够给异常一个详细的信息,这样可以更好的处理异常。
力所能及的异常一定要处理
处理本层的异常,不要随便抛出
忽略异常要有理有据
JAVA 中处理异常的过程
JAVA 中处理异常使用的是 try ... catch 。当程序发生异常时,会实例化异常,如果有 try,则经过 try ... catch 处理异常,如果没有 try ... catch ,则由 JVM 进行处理
使用 try ... finally 处理异常
catch
catch语句的参数包括一个异常类型和异常对象,异常类型必须为Throwabled的子类。
catch语句可以有多个,分别处理不同类的异常。运行时,系统从上到下分别对每个catch语句处理的异常类型进行检测,直到找到类型相匹配的catch语句。
这里的类型匹配指的是catch所处理的异常类型与生成的异常对象完全一致或者是它的父类,所以catch语句的排序顺序应该是从特殊到一般。
finally
无论try程序块抛不抛出异常,无论catch有没有捕获到异常,finally程序块都要被执行。 它提供了统一的出口,通常可以进行资源的清除工作,如关闭打开的文件等。
throws
throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常。对大多数Exception子类来说,Java编译器会强迫你声明在一个成员函数中抛出的异常的类型。
如果异常的类型是Error或 RuntimeException,或它们的子类,这个规则不起作用,因为这在程序的正常部分中是不期待出现的。 如果你想明确地抛出一个RuntimeException,你必须用throws语句来声明它的类型。
throw
throw总是出现在函数体中,用来抛出一个异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。
try ... finally 中的return
写在 try 或 catch 中的return语句不会真的从函数中跳出,而是执行 finally 块。上级调用函数能够获取到的只是 finally 中的返回值,try 或者 catch 中的 return 语句只是转移控制权的作用。
使用 try ... with resource 处理异常
使用 try ... with resource 的情况:
-
需要资源清理;
-
需要在特定的时刻进行资源清理;
在 JDK 1.7 之前,关闭资源的代码要写在 finally 代码块中,所以在 finally 中又具有了异常嵌套。而这样会增加代码的复杂程度。
当使用 try ... with resource 之后,就不需要再单独考虑 catch 中的代码
public static void main(String[] args) {
try(FileInputStream inputStream = new FileInputStream(new File("test"))) {
System.out.println(inputStream.read())
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
特殊异常
NPE(空指针异常) 场景及其处理对策
级联调用时易产生NPE
使用 Optional 优雅防止 NPE
foreach 遍历集合的异常
不要在 foreach 循环里进行元素的 remove / add 操作
foreach 是一个语法糖。
在 foreach 中不能使用 remove 的根本原因:
foreach 实际上是由 iterator 进行底层实现的。如果在 foreach 中修改的次数,和实际修改的次数不一样时,就会出现异常。
foreach 循环会自动跳过遍历空集合,如果对于有 null 值的集合,碰到 null 时需要注意 NPE。
foreach 或者 for 循环中抛出异常的影响:
如果抛出异常,则后续的操作就不会再进行。如果抛出异常,则前面的操作全都白进行了。
正确的做法是:将 foreach 中的异常整理出来之后,集中抛出。
结论
在平时的开发中,并没有很在乎 JAVA 中的异常和日志。常常认为这些操作属于浪费时间。当时当前后端出现 bug 的时候,无法找到 bug,才会意识到异常的重要性。
接下来的工作:
-
阅读 JAVA 编程思想,中异常的操作
-
完善日志处理部分