![Java无难事:详解Java编程核心思想与技术](https://wfqqreader-1252317822.image.myqcloud.com/cover/59/35011059/b_35011059.jpg)
8.2 捕获异常
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_7.jpg?sign=1739285009-7OFNbjSGG0MMlVDJsk0V2Pa3McwMOzEE-0-7d7b669f8f47d293ac3dbb0b3372e119)
扫码看视频
当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码,并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。如果Java运行时系统找不到可以捕获异常的代码,则运行时系统将终止,相应的Java程序也将退出。最终Java运行时系统将异常的相关信息输出到System.err中,就如图8-1所示的那样。
那么如何捕获异常呢?在Java中,捕获异常需要使用catch关键字,而后紧跟catch关键字的语句块就是错误处理代码。捕获异常犹如狩猎,无法发现猎物就谈不上捕猎,所以在catch语句块的前面需要一个try语句块来监视异常的抛出。try语句块就是try关键字跟随的语句块,其中是可能引发异常的代码。如下所示:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_8.jpg?sign=1739285009-udqUhwmzJDZpiIdDYQwrqFmpvFDB5LRX-0-aaf7243910f7f0301979af41e3d15e85)
这就是Java中异常处理的模式:先监视(try)后捕获(catch)。至于异常本身,它也是一个对象,有它自己的类型,所以我们的catch需要指定一个异常的类型。当程序在运行期间出现一个错误时,Java运行时系统会在对象堆中创建一个异常类型的对象,并在指定的catch语句块中赋给匹配的异常类型的变量(上例中的e1和e2)。
下面修改代码8.1,添加异常捕获代码,如代码8.2所示。
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_9.jpg?sign=1739285009-aCRD77v2Pctx2LeCXh7NRpBRyi3RQ0CE-0-c77229c9ac3dd8c8f0fd8762bdb4f228)
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_10.jpg?sign=1739285009-HsVDC3S9o7bWbOVbDAq2HoQbmbTnLMbz-0-daa7d3b00968977a3f6f4415a85e53fe)
程序运行的结果为:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_11.jpg?sign=1739285009-WM7r1o7iAjuaYgNtLWWzUuCtHqzpvr9o-0-575ed8d000fa13c744547c1d7f13102f)
终于不用看到“奇怪”的异常信息了。这就是异常捕获的好处,可以给用户更友好的提示信息,并且程序在捕获了异常后,还可以继续运行。
提示:在java.lang.System类中有三个静态对象:out、err和in,分别代表标准输出流、标准错误输出流和标准输入流,out对象和err对象的类型都是java.io.PrintStream,因此它们的方法都是一样的。
所有异常类的基类都是Throwable,在这个类中有三个常用的方法,用于输出异常的相关信息,如下所示:
● public String getMessage()
返回异常对象的详细信息。
● public String toString()
返回异常对象的简短描述。
● public void printStackTrace()
将异常对象的栈跟踪信息打印到标准的错误流(System.err对象)中。
下面修改代码8.2,使用上述三个方法,输出异常的相关信息,如代码8.3所示。
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_12.jpg?sign=1739285009-Pu5bzlm44uP7fiTu6soTPOBq6rWPR9HJ-0-95451239ce688a3c97d16973a6efd74d)
注意,printStackTrace方法本身就是输出异常的栈跟踪信息,因此不需要、也不能调用System.err.println。
程序运行的结果为:
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_13.jpg?sign=1739285009-NQCoIn0OSsz17BkJrjV31tjOBIVMTUWV-0-9bbf70e686ea21b2e06882dba3f31607)
从输出结果可以看到:(1)toString方法所谓的异常对象简短描述,其信息比getMessage方法要更详细;(2)printStackTrace方法输出的信息很全面,包含了异常发生时的栈跟踪信息,这与没有进行异常捕获时,Java运行时系统输出的信息是一样的。
在实际开发时,可以根据需要选择这三个方法中的一个来获取或输出异常信息,当然也可以像代码8.2那样,给出错误提示信息。
一段代码可能会引发多种异常,因此捕获异常的catch语句可以有多个,我们看代码8.4。
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_14.jpg?sign=1739285009-EoGGRaXitdIPMRDItEzD6OYFsQJylDYv-0-169db22f2156fd287fc0b9f7347bcee1)
编译ExcepTest.java,编译器提示错误如图8-3所示。
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_15.jpg?sign=1739285009-Vg2XcAzqYsCBmxt83EUzjm3sHeASMb0m-0-876b90db41295f1ae2655d8178c93377)
图8-3 因catch异常类型顺序错误而引发错误
引起这个错误的原因是:Exception类是所有异常类的基类,因此不管抛出何种异常,catch(Exception e)都能进行捕获,异常捕获机制是,只要发现了有匹配的,就不会再执行后面的catch语句,因此catch(ArithmeticException ae)就成了摆设,编译器发现了这个问题,就报告错误了。
因此,在使用多个catch语句捕获异常时,要将特殊的、具体的异常类型(派生类)放前面,一般化的异常类型(基类)放后面。修改代码8.4,如代码8.5所示。
![img](https://epubservercos.yuewen.com/AD1899/18685354708165706/epubprivate/OEBPS/Images/txt008_16.jpg?sign=1739285009-7YmIMFvY3kInpbPc6TUadYRw0IJt6kSX-0-e3361df75a099ea54f4d198daec27240)
再次编译运行,一切正常。