一、Java引入异常的目的
对于不支持异常的语言,为了处理一些意想不到的错误,需要对每个方法前后的调用加上设置和检查错误的代码,这样将正常的流程和异常的流程混杂在一起,不利于代码的阅读和维护。
引入异常之后,就可以将正常完成任务的代码和错误检查的代码分离,代码更容易编写和阅读维护。
二、Java异常类图
Java源码中的异常相关类的关系如下图:
Throwable是所有异常类的基类,图片中列出它的部分属性和方法。detailMessage用来描述具体的异常信息;cause记录产生的异常原因;stackTrace记录异常链;getMessage方法用来获取描述异常信息的字符串detailMessage;getCause方法用来返回抛出异常的原因,如果 cause 不存在或未知,则返回 null;printStackTrace方法将对象的堆栈跟踪输出至错误输出流
它有两个继承类:Error类和Exception类,这两个类没有多的属性,只是重载了几个构造方法。其中Error及其子类是程序无法处理的严重错误,比如Java虚拟机运行错误(Virtual MachineError);Exception及其子类是程序可以处理的异常。
Exception类下按照继承关系又分为两大部分:1.RuntimeException,它的子类如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,是可以处理也可以不处理的
2.Exception类下其他的子类,属于checked exceptions,比如IOException、SQLException等,是必须进行处理的异常,如果不处理,程序就不能编译通过。按照是否受检查可以分为:
1.可查的异常(checked exceptions),包括Error类及其子类和Exception类下的非Runtimeexception子类
2.不可查的异常(unchecked exceptions),即Runtimeexception
三、对异常的处理方式
处理异常有两种方式:
1.抛出异常:自己不处理,向上抛给调用者处理
a.主动抛出(throw 关键字,用在方法内部)
在程序中,开发人员可以通过throw new MyException();
主动抛出一个异常
b.被动抛出(throws关键字,用在方法声明后面)
对于checked exceptions中的非Error子类的类来说,在程序中必须对其进行处理,如果不想在此捕获,就通过throws来向上抛出这个异常method p() throws IOException
2.捕获异常:自己通过try…catch语句处理
try…catch…finally语句中catch和finally为可选,但不能一个都不选只用try语句,编码时可以写catch多个异常,运行时会按照先后顺序catch其中的某一个,所以先catch的异常不能是后catch的异常的父类,这样就永远无法catch后面的子异常;
程序不退出的话,finally中的代码块是永远会运行的,即使在try或者catch中有return,也会继续往下执行完finally中的代码块。如果try中退出虚拟机(System.exit()),则finally中的代码不执行。一般在finally中关闭程序打开的资源。
四、自定义异常
开发人员一般可以通过让类继承Exception来自定义应用中的异常,可以对应用中的具体规则进行处理,对异常信息统一记录等。