Java异常体系结构
Java中所有的异常都有一个老祖宗(万恶之源),这个老祖宗就是Throwable类,所有的不正常类都继承于它,这个老祖宗Throwable类主要有两个大儿子:Error类(硬伤,程序终结者)、Exception类。
Exception类也就是我们通常说的异常,导致这个异常的原因一般可能是编码本身有问题、或者环境、用户操作输入等出现问题。
Exception类有很多儿子,比如RuntimeException异常以及其他异常,这个RuntimeException异常是一个非检查异常,而其他的异常被称为检查异常。
非检查异常比如:空指针异常(NullPointerException)、数组下标越界异常(ArrayIndexOutOfBoundsException)、类型转换异常(ClassCastException)、算数异常(ArithmeticException)等等,这些运行时异常的出现,绝大部分说明了代码本身有问题,需要改进代码。
引起检查异常的原因也是多种多样的,比如:文件异常(IOException)、SQL异常(SQLException)等等各种想不到的奇葩原因,跟运行时异常不同,这种检查异常需要你手动的捕获他们,并添加相应的异常处理语句
处理异常
在Java中,我们一般用 try-catch 以及 try-catch-finally 来捕获并处理异常。
try-catch基本语法:
try{
// 一些会抛出异常的方法
}catch(Exception e){
//处理该异常的代码块
}
try 会抛出很多种类型的异常应该怎么办呢?
这时可以用多重catch语句块来对不同异常进行处理,在使用多重catch语句块的时候,要注意先子类后父类的顺序。
一般来说,try-catch语句块处理完异常之后还要有一些善后工作,比如说关闭连接、关闭一些打开的文件等,这时候就可以用finally语句块来做这件事情。
try{
// 一些会抛出异常的方法
}catch(Exception e){
// 处理该异常的代码块
}catch(Exception2 e){
// 处理Exception2的代码块
}finally{
// 最终将要执行的一些代码
}
Java中的异常抛出以及自定义异常
Java中的异常抛出需要用到两个关键字:throw 和 throws
throw – 将产生的异常抛出(动作)
throws – 声明将要抛出何种类型的异常(声明)
public void 方法名(参数列表)throws 异常列表{
//调用会抛出异常的方法或者
throw new Exception("巴拉巴拉巴拉");
}
自定义异常:
public class DrunkException extends Exception{
// 添加一个无参的构造器
public DrunkException(){
}
// 添加一个含参的构造器,使其直接调用父类的构造器
public DrunkException(String message){
super(message);
}
}
Java中的异常链
有时候我们可以把捕获的异常包装成一个新的异常,然后在新的异常里添加对原始异常类的引用,再把这个新异常抛出。详情看下例子
public class ChainTest {
/*
* test1(): 抛出“喝大了”异常
* test2(): 调用test1(),捕获“喝大了”异常,并且包装成运行时异常,继续抛出
* main方法中,调用test2(),尝试捕获test2()方法中抛出的异常
* */
public static void main(String[] args) {
ChainTest ct = new ChainTest();
try {
ct.test2();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public void test1() throws DrunkException {
throw new DrunkException("喝车别开酒!");
}
public void test2() {
try {
test1();
}catch(DrunkException e) {
// TODO: handle exception
RuntimeException newEx =
new RuntimeException("行车不规范,亲人两行泪");
newEx.initCause(e);
throw newEx;
}
}
}
以上程序的运行结果为: