Java的异常处理

Java的异常处理

基本介绍

异常对象都是派生于Throwable类的一个实例,如果我们的内置的异常类不能满足需求,我们可以自定义异常进行处理

所有的异常都是由Throwable继承而来的,在下一层分为两个部分:

  • Error类
  • Exception类

其中,Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误

而我们重点关注的是Exception层次结构。这个层次结构又分解为了两个部分:

  • RuntimeException
  • 其他异常

划分标准为:由程序错误导致的异常属于RuntimeException;而我们的程序本身没有错误,但是由于像IO错误这类问题导致的异常属于其他异常。

通常,我们的RuntimeException包含以下:

  • 错误的指令转换,数组的访问越界,访问null指针

不是派生于RuntimeException的异常包含以下:

  • 试图在文件的尾部后面读取数据,试图打开一个不存在的文件,试图根据指定的字符查找Class对象

总结:

我们将Error和RuntimeException的所有异常称为非受查异常,而将所有的其他异常称为受查异常

异常的处理机制

对于异常,我们有两种处理机制:

  • 在定义的方法上声明所有可能抛出的受查异常,而我们的非受查异常要么不可控制,要么就应该避免发生。如果方法没有声明所有可能发生的受查异常,编译器就会发出一个错误信息

  • 捕获异常

继承中关于异常需要注意的点

如果我们的子类中覆盖了父类的一个方法,那么子类中声明的异常不能比父类声明的异常更通用,就是说子类方法中可以抛出的异常范围应该小于我们的父类,或者根本不抛出异常,如果我们的父类没有抛出异常,而必须保证我们的子类也不会抛出任何的受查异常。

异常的捕获

如果我们的异常发生的时候没有在任何地方进行捕获,那么程序就会终止执行,并在我们的控制台打印出我们的异常信息,其中就包括我们的异常的类型和堆栈的内容。此时我们可以使用捕获异常的方式进行处理:

try {
    //代码块
}catch(Exception e) {
    //异常的处理
}finally {
    //资源的释放
} 

其中的执行的流程:

  • 如果我们的try语句块的任何代码抛出了一个在catch子句中说明的异常类,那么:

    • 程序就会跳过try语句块的其余代码
    • 程序将会执行catch子句中的处理器代码
  • 如果我们的try语句块的任何代码抛出了一个在catch子句中没有声明的异常类,那么这个方法就会立即退出!!!

此时我们也可以使用在方法上声明需要抛出的异常:

public void readFile(String filename) throws IOException {
    ...
} 

此时我们就会将这个异常进行传递,传递给调用这个方法的上层处理器进行处理,但是这个规则在有些场景中是不适用的:

  • 父子类异常处理机制中,如果编写了一个覆盖了父类的方法,而这个方法又没有抛出异常,那么这个方法就必须捕获方法代码中的每一个受查异常我们不允许子类的throws说明符中出现超过父类方法中所列出的异常类的范围。

捕获多个异常

我们可以同时捕获多个异常,即我们在一个try代码块种可以捕获多个异常类型,并对不同的类型的异常进行不同的处理。

捕获多个异常的时候,我们的异常变量隐含为final变量

finally子句

当我们进行抛出一个异常,就会终止方法中剩余代码的处理,并退出这个方法的执行。此时我们可以使用finally子句进行资源的回收。

不管是否有异常发生,我们的finally子句中的代码都会被执行。

细节点:
  • 当我们的finally子句中包含return语句的时候,将会出现一种意向不到的结果。假设此时我们得try语句块中有return语句,此时在方法返回之前,我们的finally子句的内容将会被执行。

    public class TestFinally {
        public static void main(String[] args) {
            int res = find(2);
            System.out.println(res);
        }
    
        private static int find(int n) {
            try {
                int r = n * n;
                return r;
            }finally {
                System.out.println("finally 代码块");
            }
        }
    }
    
    输出结果:
    finally 代码块
    4
    
  • 如果上面的代码除了我们的try语句块中存在return语句,我们的finally子句中也存在一个return语句,此时我们finally语句中的return返回值将会覆盖原始的返回值

    public class TestFinally {
        public static void main(String[] args) {
            int res = find(2);
            System.out.println(res);
        }
    
        private static int find(int n) {
            try {
                int r = n * n;
                return r;
            }finally {
                System.out.println("finally 代码块");
                if (n == 2) return 0;
            }
        }
    }
    
    输出结果:
    finally 代码块
    0
    

堆栈轨迹(stack trace)

堆栈轨迹(stack trace)是一种方法调用过程的列表,它包含了程序执行过程中的方法调用的特定位置。

我们可以使用Thread.getAllStackTrace方法,它可以产生所有线程的堆栈轨迹。

异常代码测试

举例:我们的本地D盘下1.txt文件不存在,此时由于FileNotFoundExceptionIOException的子类,故匹配了FileNotFoundException的catch子句,只会打印e1,不会打印e2的异常信息

public class TestIO {
    public static void main(String[] args) {
        ObjectInputStream inputStream = null;
        try {
            inputStream = new ObjectInputStream(new FileInputStream("D:\\1.txt"));
            Object object = inputStream.readObject();
        } catch (FileNotFoundException e1) {
            System.out.println("FileNotFoundException");
            e1.printStackTrace();
        } catch (IOException e2) {
            System.out.println("IOException");
            e2.printStackTrace();
        } catch (ClassNotFoundException e3) {
            System.out.println("ClassNotFoundException");
            e3.printStackTrace();
        }finally {
            /*
            * public interface ObjectInput extends DataInput, AutoCloseable
            * ObjectInputStream底层实现了AutoCloseable接口,在try代码块退出的时候,会自动调用inputStream.close()方法
            * */
        }

    }
}

输出结果:

FileNotFoundException
java.io.FileNotFoundException: D:\1.txt (系统找不到指定的文件。)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at java.io.FileInputStream.<init>(FileInputStream.java:93)
	at com.feng.io.TestIO.main(TestIO.java:15)

同时,我们的ObjectInputStream底层实现了ObjectInput接口,而我们的ObjectInput接口实现了AutoCloseable接口,它的内部包含一个close()方法,这个方法会声明为抛出一个IOException,它会在我们的try语句块退出的时候,自动的调用close方法,帮我们关闭资源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值