Java异常机制
Java有自己一套处理异常的框架,框架内的继承关系也很清晰,Throwable是所有的Error类和所有的Exception类的基类,Error可能是编译期间出现错误或者系统错误,程序并不去处理这种错误;Exception可能是运行时出现的异常或者检查程序时出现的异常,运行时出现的异常(RuntimeException,如NullPointerException、ArrayIndexOutOfBoundsException等)在编程时可以去捕获也可以不去捕获,而检查程序时出现的异常(如SQLException、IOException、ConcurrentModificationException等)则必须要去捕获,因此Java中处理不同类型的错误或异常都有对应的异常实现类。
检查程序时出现的异常,这类异常是发生在编译期间的,编译器会去强制捕获异常,所以编码的时候必须要捕获异常。捕获异常的方式大致有两种:使用关键字throw或throws、使用try-catch-finally语句,使用这些关键字处理异常还是挺简单的,但捕获异常过程中的一些细节也值得注意。
throw或throws关键字
throw关键字:
用于方法体中,用来抛出一个实际的异常对象。使用throw抛自定义异常时,需要使用try-catch语句块 或者 throws关键字捕获异常,举例说明:
// throw定义异常 + throws捕获异常
public class TestController1 {
public static void main(String[] args) throws CustomException {
String strSpace = "123 4569";
if (strSpace.contains(" "))
throw new CustomException("自定义异常----->字符串不能有空格");
}
}
// throw定义异常 + try-catch捕获异常
public class TestController2 {
public static void main(String[] args){
try {
String strNull = null;
if (strNull == null)
throw new CustomException("自定义异常----->字符串不能为null");
} catch (CustomException e) {
e.printStackTrace();
}
}
}
// 自定义异常类
class CustomException extends Exception {
public CustomException() {}
public CustomException(String msg) {super(msg);}
public CustomException(Throwable cases) {super(cases);}
}
throws关键字:
用于方法声明处,用来声明该方法可能发生的异常类型,可以有多个异常类型,用来强制调用该方法时处理这些异常。
try-catch-finally语句
一个完整的try-catch-finally结构如下:
try{
//try语句块
}catch(SomeException1 e){
//catch语句块1
}catch(SomeException2 e){
//catch语句块2
}catch(SomeExceptionN e){
//catch语句块n
}finally{
//finally语句块
}
try语句块:
- try块的作用是监控代码执行,当它捕获到异常后,跳转到catch块并交由catch块处理异常;
- try块未捕获异常,会跳转到finally块继续执行代码。
catch语句块:
- catch块处理try块捕获的异常,要么自己处理该异常,要么往上抛该异常;
- catch块中根据异常对象e中的printStackTrace() 或 fillInStackTrace() 可以打印异常信息;
- 可以有多个catch块,处理异常时按顺序匹配到哪一个就使用哪一个,一个catch块可以有多个异常,用|分割(Java7之后);
- 多个catch块要注意异常子类间有无继承关系,可以合并为1个,合并后的异常可以代表所有的异常子类,如合并为Expection;
- 对于运行时异常,可以省略不写catch块,但受检异常必须要写catch块。
finally语句块:
- finally块无论是否发生异常均可省略不写,但写的话,里面的代码一定会得到执行(除非此时发生了系统退出 或 JVM退出);
- finally块通常用于清理和释放资源,如关闭IO流,关闭JDBC连接等。
try-with-resource(带资源的try语句):
- 它是Java7支持的功能,语法格式如下,注意要求的资源对象本身实现了AutoCloseable 接口,这样系统在执行时就会调用它们的close()方法关闭资源连接,代替了finally块关闭资源的功能;
try(资源语句){
//监控执行代码;
}catch{
//处理异常语句;
}
- 带资源的try语句本质上也是一颗语法糖,通过下面的一个文件复制的例子来分析:
// TestController.java源码,使用文件输入输出流实现文件内容的复制
public class TestController {
public static void main(String[] args) {
// 文件内容复制
copyFile("E:\\test\\today-log.txt","E:\\test\\yesterday-log.txt");
}
public static void copyFile(String src, String dst) {
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[1024];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用这种try带资源的语句可以简化原先冗长而又各种关闭资源的try-catch-finally语句,整个世界看着干净多了!经过编译的字节码文件是什么样的呢,来看下:
// TestController.class
public class TestController {
public TestController() {
}
public static void main(String[] args) {
copyFile("E:\\test\\today-log.txt", "E:\\test\\yesterday-log.txt");
}
public static void copyFile(String src, String dst) {
try {
InputStream in = new FileInputStream(src);
Throwable var3 = null;
try {
OutputStream out = new FileOutputStream(dst);
Throwable var5 = null;
try {
byte[] buf = new byte[1024];
int n;
while((n = in.read(buf)) >= 0) {
out.write(buf, 0, n);
}
} catch (Throwable var31) {
var5 = var31;
throw var31;
} finally {
if (out != null) {
if (var5 != null) {
try {
out.close();
} catch (Throwable var30) {
var5.addSuppressed(var30);
}
} else {
out.close();
}
}
}
} catch (Throwable var33) {
var3 = var33;
throw var33;
} finally {
if (in != null) {
if (var3 != null) {
try {
in.close();
} catch (Throwable var29) {
var3.addSuppressed(var29);
}
} else {
in.close();
}
}
}
} catch (Exception var35) {
var35.printStackTrace();
}
}
}
从Java编译器编译生成的字节码可以看出:输入输出流的资源需要用finally块关闭,流先定义后关闭(先进后出)。整个用于处理业务的代码就几行,底层把精力主要放在了流的异常处理和资源释放上。
相比较try-catch-finally语句而言,带资源的try语句显得更加简洁和实用。
小结一下
本篇重点分析了Java中捕获异常的方式,及捕获过程中注意的一些细节,实际上更重要的是要懂得如何自定义异常。学以致用,想一想在项目中怎么去统一声明异常,有了这些基础就想必很简单了。关于异常使用的指导原则,推荐去看一看《Effective Java 中文版(原书第3版)》,这本书描述的还不错,不积硅步无以至千里,点滴付出终将有所收获,共同进步~