前言
先完成Java异常入门,再完成Java进阶。
一、自动关闭资源
JVM不回收硬件资源(如I/O资源),那是OS做的事,JVM会回收堆内存中对象所占用的资源。
平时I/O流出现IOException时,就会停止执行下面的代码,导致I/O流不能关闭。所以用Finally去回收。
public void testCheckedException() {
FileReader reader = null;
try {
reader = new FileReader("d:\\a.txt");
char ch = (char) reader.read();
} catch (FileNotFoundException e) {
//打印栈轨迹
e.printStackTrace();
//打印栈中信息
StackTraceElement[] els = e.getStackTrace();
for(StackTraceElement el : els){
System.out.println("异常发生的类:"+ el.getClassName());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在JDK1.7之后,出现try_with_resources机制:
只要继承了AutoCloseable类的类,都可以在try语句块退出时,自动调用close方法关闭资源流。
public void testCheckedException2() {
try(FileReader reader = new FileReader("d:\\a.txt"); FileOutputStream fos = new FileOutputStream("d:\\a.txt")) {
char ch = (char) reader.read();
} catch (FileNotFoundException e) {
//打印栈轨迹
e.printStackTrace();
//打印栈中信息
StackTraceElement[] els = e.getStackTrace();
for(StackTraceElement el : els){
System.out.println("异常发生的类:"+ el.getClassName());
}
} catch (IOException e) {
e.printStackTrace();
}
}
二、多异常捕获
当try语句中出现多种异常时,
1)可以用 | 来隔开。
2)如果一个catch语句块处理的异常类型超过一个(两类异常没有继承关系),那么被catch的参数变量隐式的变为final变量,在catch语句块中无法再将其赋值,即不能把当前的对象引用去指向其它对象。
public void testCheckedException2() {
try(FileReader reader = new FileReader("d:\\a.txt"); FileOutputStream fos = new FileOutputStream("d:\\a.txt")) {
char ch = (char) reader.read();
int num = 2 / 0;
} catch (IOException | ArithmeticException e) {
//打印栈轨迹
e.printStackTrace();
//打印栈中信息
StackTraceElement[] els = e.getStackTrace();
for(StackTraceElement el : els){
System.out.println("异常发生的类:"+ el.getClassName());
}
}
}
三、异常处理嵌套
能用多catch语句替代异常处理嵌套吗?
public void embedException() {
try {
//程序A
try {
//程序B
} catch (RuntimeException e) {
//程序C
} finally {
//程序D
}
//程序E
} catch (Exception e) {
//程序F
} finally {
//程序G
}
}
public void embedException2() {
try {
//程序A
//程序B
} catch (RuntimeException e) {
//程序C
} catch (Exception e) {
//程序F
} finally {
//程序D,以前的finally语句。
//程序E
//程序G
}
}
1)无异常:ABDEG
2)A 异常:AFG
注:A 异常,后面的BDE都将不会执行
3)B 异常:ABCDEG,当内层没有catch捕获到时,执行外层catch,又是另一种执行路径。
4)总结:当异常发生时,将停止后面的执行语句,处理完毕后,方可执行处理完毕后的语句。Finally语句必须执行。
四、catch + throws来包装异常
public void packException() throws Exception {
try {
int n = 2 / 0;
} catch (ArithmeticException e) {
throw new Exception("除数不能为0");
}
}
五、异常链追踪信息
捕获异常后再抛出异常,并希望把原始造成异常的异常信息保存并传递下去,被称作异常链。
public void packException2() throws Exception {
try {
int n = 2 / 0;
} catch (ArithmeticException e) {
throw new Exception("除数不能为0",e);
}
}
/**
* Constructs a new exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public Exception(String message, Throwable cause) {
super(message, cause);
}
六、友好的throws语句
public void friendlyThrows() throws IOException {
try (FileReader reader = new FileReader("d:\\a.txt")){
//操作文件
}catch (Exception e){
//操作异常
throw e;
}
}
当我们catch到Exception时,然后throw出去,Java编译器会细致检查实际异常,然后throws出真实异常IOException.
总结
1)自动关闭资源
2)多异常捕获
3)异常处理嵌套
4)catch + throws来包装异常
5)异常链追踪信息
6)友好的throws语句