异常处理全面解析
checked和unchecked异常
-
checked 异常(检查型异常)在源代码里必须显式地捕获或者抛出,否则编译器会提示你进行相应的操作;而 unchecked 异常(非检查型异常)就是所谓的运行时异常,通常是可以通过编码进行规避的,并不需要显式地捕获或者抛出。
-
NoClassDefFoundError:程序在编译时可以找到所依赖的类,但是在运行时找不到指定的类文件,导致抛出该错误;原因可能是 jar 包缺失或者调用了初始化失败的类。
-
ClassNotFoundException:当动态加载 Class 对象的时候找不到对应的类时抛出该异常;原因可能是要加载的类不存在或者类名写错了。
throw和throws
1)throws关键字用于声明异常,它的作用和try-catch相似;而throw关键字用于显式的抛出异常。
throws ArithmeticException;
2)throws关键字后面跟的是异常的名字;而throw关键字后面跟的是异常的对象。
throw new ArithmeticException("算术异常");
3)throws关键字出现在方法签名上,而throw关键字出现在方法体里。
4)throws关键字在声明异常的时候可以跟多个,用逗号隔开;而throw关键字每次只能抛出一个异常。
- 如果有好几个类似的方法都可能出现异常,如果为每个方法都加上try-catch,就会显得非常繁琐。一个解决办法就是,使用throws关键字,在方法签名上声明可能会抛出的异常,然后在调用该方法的地方使用try-catch进行处理。
public static void main(String args[]){
try {
myMethod1();
} catch (ArithmeticException e) {
// 算术异常
} catch (NullPointerException e) {
// 空指针异常
}
}
public static void myMethod1() throws ArithmeticException, NullPointerException{
// 方法签名上声明异常
}
try-catch-finally
-
一个
try
块后面可以跟多个catch
块,用来捕获不同类型的异常并做相应的处理,当 try 块中的某一行代码发生异常时,之后的代码就不再执行,而是会跳转到异常对应的 catch 块中执行。 -
如果一个 try 块后面跟了多个与之关联的 catch 块,那么应该把特定的异常放在前面,通用型的异常放在后面,不然编译器会提示错误。
-
finally 块前面必须有 try 块,不要把 finally 块单独拉出来使用。编译器也不允许这样做。
-
finally 块不是必选项,有 try 块的时候不一定要有 finally 块。
-
如果 finally 块中的代码可能会发生异常,也应该使用 try-catch 进行包裹。
-
即便是 try 块中执行了 return、break、continue 这些跳转语句,finally 块也会被执行
-
不执行finally的情况:遇到了死循环;执行了
System. exit()
这行代码。
class MyFinallyReadLineThrow {
public void close() throws Exception {
throw new Exception("close");
}
public void readLine() throws Exception {
throw new Exception("readLine");
}
}
public class Test {
public static void main(String[] args) throws Exception {
MyFinallyReadLineThrow myThrow = null;
try {
myThrow = new MyFinallyReadLineThrow();
// readLine的异常信息丢失
myThrow.readLine();
} finally {
myThrow.close();
}
/*
Exception in thread "main" java.lang.Exception: close
at test.ExceptionTest.MyFinallyReadLineThrow.close(Test.java:5)
at test.ExceptionTest.Test.main(Test.java:21)
*/
}
}
try-with-resources
- 当一个异常被抛出的时候,可能有其他异常因为该异常而被抑制住,从而无法正常抛出。这时可以通过
addSuppressed()
方法把这些被抑制的方法记录下来,然后被抑制的异常就会出现在抛出的异常的堆栈信息中,可以通过getSuppressed()
方法来获取这些异常。这样做的好处是不会丢失任何异常,方便我们进行调试。
package test.ExceptionTest;
class MyFinallyReadLineThrow implements AutoCloseable {
@Override
public void close() throws Exception {
throw new Exception("close");
}
public void readLine() throws Exception {
throw new Exception("readLine");
}
}
public class Test {
public static void main(String[] args) {
try (MyFinallyReadLineThrow myThrow = new MyFinallyReadLineThrow()) {
myThrow.readLine();
} catch (Exception e) {
e.printStackTrace();
}
/*
java.lang.Exception: readLine
at test.ExceptionTest.MyFinallyReadLineThrow.readLine(Test.java:10)
at test.ExceptionTest.Test.main(Test.java:18)
Suppressed: java.lang.Exception: close
at test.ExceptionTest.MyFinallyReadLineThrow.close(Test.java:6)
at test.ExceptionTest.Test.main(Test.java:19)
*/
}
}