Java中异常的分类
Java中的异常机制是针对正常运行程序的一个必要补充,一般来说没有加入异常机制,程序也能正常运营,但是,由于入参、程序逻辑的严谨度,总会有期望之外的结果生成,因此加入异常机制的补充,就是为了更好的处理意料之外的结果。
所有异常都继承与Exception类,但是异常本质上分为两种:
检查异常(CheckedException)
顾名思义,这个异常抛出来,我们可以抓住它(也就是传说中的try-catch-finally系列),这类异常通常是在设计者考虑之内的 、可处理异常,譬如常见的SQLException、IOException以及我们调用的一些Api主动抛出的异常等。
捕获异常既然可以捕获处理,那就意味着可以减少对程序正常运行的影响,我们可以在try代码块中编写正常逻辑,在catch代码块中处理相应的异常(这里我们可以选择在本方法内部消化,然后程序继续进行下去;当然,如果本方法处理不了或是不想处理,则可以选则throws将这个异常扔给外层的方法去捕获处理,安逸省事,当然这样也会影响本方法中后续代码的执行),而finally代码块则是提供给我们编写无论正常还是异常都需要执行的代码的,譬如流的关闭,连接的关闭。
非检查异常(RuntimeException)
官方名称叫运行时异常,比较特殊,相对于捕获异常来说,它是意外中意外,没有声明也会在产生时抛出,对于程序来说这类异常是不强制要求捕获,也可以通过编译的,但是发生的时候还是会抛出。
一旦抛出了运行时异常,代表程序存在逻辑上的错误,这些是需要从编码角度来处理,而不是让程序自动处理的;其实从名字上可以看出来,这类异常基本上都是在程序设计、编写中没有到预料的情况,大多属于程序逻辑、运行环境、系统级别的问题导致的,对程序而言就无法进行常规处理或不能继续进行后续处理了,所以中止执行,同时要尽可能的避免。
自定义异常
Exception类是可被继承的,因此我们可以自己定义一个继承自它的异常类,在需要的地方,使用throw(方法中)或throws(方法签名的()号之后)抛出,其实自定义的异常也是一个可捕获异常,但是我们可以自定义异常类内部的一些属性,譬如抛出的信息加入自定义的消息模版等,能DIY的东西都是好东西~
各类异常的使用场景
严格地说,Exception的众多子类自然对应了不同类型的异常,应用场景自然也不尽相同,但是考虑到本人经验上的硬伤,大多数时候对于可捕获的异常都采用了爸爸级的Exception囊括所有的可能性,因为目前遇到的待异常的方法,大多都至抛出一个异常,因此省事的话,只要捕获Exception就足够了;
但是,凡事无绝对,前阵子就遇到过同时抛出三个异常的方法,这时候如果需要对不同的异常进行不同的处理,就需要分别针对每种异常进行捕获处理,譬如同时产生了数据库操作的sql异常和IOException读写流异常产生时,我们需要已经读进内存的流数据进行输出保存,但是如果是数据库操作的异常我们则需要进行事务处理,已经执行的操作进行回滚等。
对于运行时异常,接触比较少,使用不多,因为该异常是直接终止当前程序逻辑执行的,本人大多在web应用中某次需要对数据库做原子操作的,在中间的逻辑校验无法通过时抛出该异常来触发框架的事务管理,回滚数据库操作(譬如Hibernate的Service层)。
异常指不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程。Java通 过API中Throwable类的众多子类描述各种不同的异常。因而,Java异常都是对象,是Throwable子类的实例,描述了出现在一段编码中的 错误条件。当条件生成时,错误将引发异常。
通常,Java的异常(包括Exception和Error)分为可查的异常(checked exceptions)和不可查的异常(unchecked exceptions)。
可查异常(编译器要求必须处置的异常):正确的程序在运行中,很容易出现的、情理可容的异常状况。可查异常虽然是异常状况,但在一定程度上它的发生是可以预计的,而且一旦发生这种异常状况,就必须采取某种方式进行处理。
除了RuntimeException及其子类以外,其他的Exception类及其子类都属于可查异常。这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。
不可查异常(编译器不要求强制处置的异常):包括运行时异常(RuntimeException与其子类)和错误(Error)。
运行时异常都是RuntimeException类及其子类异常。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
在 Java 应用程序中,异常处理机制为:抛出异常,捕捉异常。
** 抛出异常**:当一个方法出现错误引发异常时,方法创建异常对象并交付运行时系统,异常对象中包含了异常类型和异常出现时的程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。
** 捕获异常**:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
对于运行时异常、错误或可查异常,Java技术所要求的异常处理方式有所不同。
由于运行时异常的不可查性,为了更合理、更容易地实现应用程序,Java规定,运行时异常将由Java运行时系统自动抛出,允许应用程序忽略运行时异常。
对于方法运行中可能出现的Error,当运行方法不欲捕捉时,Java允许该方法不做任何抛出声明。因为,大多数Error异常属于永远不能被允许发生的状况,也属于合理的应用程序不该捕捉的异常。
对于所有的可查异常,Java规定:一个方法必须捕捉,或者声明抛出方法之外。也就是说,当一个方法选择不捕捉可查异常时,它必须声明将抛出异常。
能够捕捉异常的方法,需要提供相符类型的异常处理器。所捕捉的异常,可能是由于自身语句所引发并抛出的异常,也可能是由某个调用的方法或者Java运行时 系统等抛出的异常。也就是说,一个方法所能捕捉的异常,一定是Java代码在某处所抛出的异常。简单地说,异常总是先被抛出,后被捕捉的。
任何Java代码都可以抛出异常,如:自己编写的代码、来自Java开发环境包中代码,或者Java运行时系统。无论是谁,都可以通过Java的throw语句抛出异常。
从方法中抛出的任何异常都必须使用throws子句。
捕捉异常通过try-catch语句或者try-catch-finally语句实现。
总体来说,Java规定:对于可查异常必须捕捉、或者声明抛出。允许忽略不可查的RuntimeException和Error。
这篇博文对异常的介绍十分详细,本文中的截取量也比较多,但是主要是因为读完该文之后,发现自己对异常的理解已经是千里之外(某处费玉清歌喉响起),本人一直认为不可检查的异常都是系统级别的异常会直接终止程序,不可以被捕获处理,为了还一直想为什么带事务的框架在抛出运行时异常之后还可以做事务回滚,现在终于豁然开朗了。
其实只要找不到异常处理器的话,异常都会终止程序。
另外,异常的处理是有存在链式结构的,对于一段可能出现的异常的代码,我们可以依次捕获多个异常(即一try多catch),但是类似if..else if..的语法,多个catch只会处理其中一个。
而且,对于catch链中需要注意的是,如果父类异常在前的话,如果抛出的异常是其子类,那么也会被父类的异常处理器捕获(父类异常的catch),平级的异常则不存在这个问题。
PS:所有的异常都可以通过其对象的printStackTrace()方法打印出异常的信息,用于调试
Java常见异常
列出常见异常,其实也是为了方便自己随时回来查看。
在Java中提供了一些异常用来描述经常发生的错误,对于这些异常,有的需要程序员进行捕获处理或声明抛出,有的是由Java虚拟机自动进行捕获处理。Java中常见的异常类:
1. runtimeException子类:
** ** 1、 java.lang.ArrayIndexOutOfBoundsException 数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
2、java.lang.ArithmeticException 算术条件异常。譬如:整数除零等。
3、java.lang.NullPointerException 空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等
4、java.lang.ClassNotFoundException 找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
5、java.lang.NegativeArraySizeException 数组长度为负异常
6、java.lang.ArrayStoreException 数组中包含不兼容的值抛出的异常
7、java.lang.SecurityException 安全性异常
8、java.lang.IllegalArgumentException 非法参数异常
2.IOException
IOException:操作输入流和输出流时可能出现的异常。
EOFException 文件已结束异常
FileNotFoundException 文件未找到异常
3.** 其他**
ClassCastException 类型转换异常类
ArrayStoreException 数组中包含不兼容的值抛出的异常
SQLException 操作数据库异常类
NoSuchFieldException 字段未找到异常
NoSuchMethodException 方法未找到抛出的异常
NumberFormatException 字符串转换为数字抛出的异常
StringIndexOutOfBoundsException 字符串索引超出范围抛出的异常
IllegalAccessException 不允许访问某类异常
InstantiationException 当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常