Java中的异常
Java中的异常
初识异常
异常是指在程序的运行过程中发生的不正常事件,比如所需要的文件找不到、数据源无法连接、网络连接不通或连接中断、算术被零除运算错误、数组下标越界、空指针异常,类型转换异常等。
下面通过下面的代码来认识程序中的异常:
代码分析:
这段代码中,用户输入2个数字,除数不能为零,正常情况下,运行结果如下:
但是,如果用户没有按照要求进行输入,如果被除数没有输入数字,而是输入了“abc”,则程序将会发生异常,运行结果如下:
输出告诉我们:在ExTest类的main函数中,出现了输入格式不匹配(例如要数字但实际输入不是数字)异常(java.util.InputMismatchException)。
若除数输入为“0”,则程序运行时也将发生异常,运行结果如下:
输出告诉我们:在ExTest类的main函数中,出现了算术错误(被除数被零除)异常(java.lang.ArithmeticException)。
以上代码如果通过if-else语句进行异常处理,有以下缺点。
- 代码臃肿,增加了大量处理异常的代码。
- 浪费时间,有一些时间分散到异常处理上,影响开放效率。
- 很难穷举所有的异常,程序不健壮。
- 异常处理代码和业务代码交织在一起,影响可读性,增加维护难度。
Java提供了专门的异常处理机制,刻服了以上通过if-else来解决的异常的缺点。
异常类
Java中的异常有很多类型,所有类型都有一个共同的父类Throwable。以Throwable为根,Java定义了非常多的异常类,表示各种类型的异常。
Throwable是所有异常的基类,它有两个子类:Error和Exception。
- Error类:表示系统错误或资源不足,如内存溢出、虚拟机错误。由Java系统使用,应用程序不应该抛出这种类型的错误。
- Exception类:表示应用程序错误,如算术被零除运算错误、数组下标越界、空指针异常等。Exception又可分为两大类异常。
运行时异常:包括RuntimeException及其所有子类。不要求程序必须对它们进行处理。
编译(checked)异常(非运行时异常)除了运行时异常外的其他从Exception类继承来的异常类。
以下为一些常见的异常类。
-
NullPointerException
空指针异常,操作一个 null 对象的方法或属性时会抛出这个异常。 -
OutofOutofMemoryError
内存出现异常的一种异常,这不是程序能控制的。 -
IOException
在读写磁盘文件、网络内容的时候经常会生的一种异常,这种异常是受检查异常,需要进行手工捕获。 -
FileNotFoundException
文件找不到异常,如果文件不存在就会抛出这种异常。 -
ClassNotFoundException
类找不到异常,这是在加载类的时候抛出来的,即在类路径下不能加载指定的类。 -
ClassCastException
类转换异常,将一个不是该类的实例转换成这个类就会抛出这个异常。 -
NoSuchMethodException
没有这个方法异常。 -
ArrayIndexOutOfBoundsException
数组下标越界异常。 -
ArithmeticException
算术异常,发生在数字的算术运算时的异常,如一个数字除以 0 就会报这个错。 -
SQLException
SQL异常,操作数据库时发生的异常。
异常处理机制
- 使用try-catch处理异常
代码如下:
这段代码中,我们使用try/catch捕获异常,如果用户按照要求输入正确,程序执行完try语句块的代码,没有发生异常,则catch语句块中的代码被忽略。如果在try语句块中发生异常,那么造成异常的那一行剩下的代码都将被忽略,而相应的catch语句块将会被执行。
如果用户在控制台中输入了被除数为“abc”,运行结果如下:
如果用户在控制台中输入了除数为“0”,运行结果如下:
-
使用try-catch-finally处理异常
代码如下:
try-catch-finally语句块的执行流程大致分为如下两种情况:如果在try语句块中没有发生异常,finally语句块也会被执行。如果try语句块在执行过程中发生异常,无论这种异常能否被catch语句块捕获到,都将执行fianlly语句中的代码。即使在catch语句中存在return语句,finally语句块中的语句也会执行。发生异常时的执行顺序是,先执行catch语句块中return之前的语句,再执行finally语句块中的语句,最后执行catch语句块中的return语句退出。运行结果如下: -
使用多重catch处理异常
代码如下:
这个程序已知在运行时可能会引发多个异常,这时可以在一个try语句块后面跟多个catch语句块分别处理不同的异常。排列顺序必须是从子类到父类,最后一个一般都是Excteption类。 -
使用throws抛出异常
Java中用throws声明某个方法可能抛出的各种异常以通知方法调用者。throws可以同时声明多个异常,异常之间用逗号隔开。
代码如下: -
使用throw抛出异常
代码如下:
运行结果如下:
这里注意一点,throw 和 throws的区别:
a.作用不同:throw用于程序员自行产生并抛出异常,throws用于声明该方法内抛出异常。
b.使用的位置不同:throw位于方法体内部,可以作为单独语句使用;throws必须跟在方法参数列表的后面,不能单独使用。
c.内容不同:throw抛出一个异常对象,是能是一个;throws后面跟异常类,可以跟多个。
-
自定义异常
除了Java API中的异常类型,我们可以自定义异常类。自定义异常类,方法是继承Exception或者RuntimeException。代码如下:
MyException类
Person类
AppExTest类
运行结果如下: -
异常链
在异常处理时,常常会在捕获一个异常后抛出另外一个异常,并且希望把异常原始信息保存下来,这被称为异常链。在JDK1.4以前,程序员必须自己编写代码来保存原始异常信息。JDK1.4推出以后,正好解决了这个问题,它虽然创建了新的异常,但却保留了原有异常的信息。例如:
运行结果如下: