1、异常分类
Error错误--程序无法处理的错误,表示运行应用程序中较严重问题(运行时异常:StackOverFlowError、OutOfMemoryError)这些错误表示故障发生于虚拟机自身或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。
Exception异常(重要子类:RunTimeException运行异常、IOException)
RunTimeException:例如空值对象引用,试图除零、数组越界则分别引发运行时异常(NullPointerException、ArithmeticException)和ArrayIndexOutOfBoundException。
异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。
Java异常(包括Exception和Error)分为可查异常(checked Exceptions)和不可查异常(unchecked Exceptions)
可查异常(编译器要求的必须处置的异常):在一定程度上它的发生是可以预计的,且一旦发生,就必须采取相应程序进行处理。除了RunTimeException及其子类外,其他的Exception都是可查异常,编译器会检查,需要try catch或throws抛出异常,否则编译器不会通过。
不可查异常(编译器不要求强制处置的异常)包括运行时异常(RuntimeException与其子类)和错误(Error)
运行时异常:RuntimeException类及其子类,这些异常不可查,java编译器不会检查它,无需try catch 或 throws,也会编译通过。
非运行时异常(编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常try catch 或 throws,如果不处理,程序就不能编译通过。
抛出异常:当方法出现错误引发异常时,方法创建异常对象(异常对象包含异常类型和异常出现时的程序状态等异常信息)并交付给运行时系统,运行时系统找到处理异常的代码并执行。
捕获异常:在方法抛出异常后,运行时系统会寻找合适的异常处理器(exception handler)
潜在的异常处理器是异常发生时存留在调用栈中的方法的集合。当异常处理器所能处理的类型与发生异常的类型相同时,即找到合适的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈,直到找到合适的异常处理器,如果遍历完仍未找到,则运行时系统停止。
对于所有的可查异常,Java规定:一个方法必须捕捉,或者声明抛出方法之外。也就是说,当一个方法选择不捕捉可查异常时,它必须声明将抛出异常。
总结:
能够捕捉异常的方法,需要提供相符类型的异常处理器。所捕捉的异常,可能是由于自身语句所引发并抛出的异常,也可能是由某个调用的方法或者Java运行时 系统等抛出的异常。也就是说,一个方法所能捕捉的异常,一定是Java代码在某处所抛出的异常。简单地说,异常总是先被抛出,后被捕捉的。
从方法中抛出的任何异常都必须使用throws子句。
捕捉异常通过try-catch语句或者try-catch-finally语句实现。
总体来说,Java规定:对于可查异常必须捕捉、或者声明抛出。允许忽略不可查的RuntimeException和Error
注意事项:一旦某个catch捕获到匹配的异常类型,将进入异常处理代码。一经处理结束,就意味着整个try-catch语句结束。其他的catch子句不再有匹配和捕获异常类型的机会。
Java通过异常类描述异常类型,异常类的层次结构如图1所示。对于有多个catch子句的异常程序而言,应该尽量将捕获底层异常类的catch子句放在前面,同时尽量将捕获相对高层的异常类的catch子句放在后面。否则,捕获底层异常类的catch子句将可能会被屏蔽。
例如:RuntimeException异常类包括运行时各种常见的异常,ArithmeticException类和ArrayIndexOutOfBoundsException类都是它的子类。因此,RuntimeException异常类的catch子句应该放在最后面,否则可能会屏蔽其后的特定异常处理或引起编译错误。
小结:
try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
catch 块:用于处理try捕获到的异常。
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。
try、catch、finally语句块的执行顺序:
1)当try没有捕获到异常时:try语句块中的语句逐一被执行,程序将跳过catch语句块,执行finally语句块和其后的语句;
2)当try捕获到异常,catch语句块里没有处理此异常的情况:当try语句块里的某条语句出现异常时,而没有处理此异常的catch语句块时,此异常将会抛给JVM处理,finally语句块里的语句还是会被执行,但finally语句块后的语句不会被执行;
3)当try捕获到异常,catch语句块里有处理此异常的情况:在try语句块中是按照顺序来执行的,当执行到某一条语句出现异常时,程序将跳到catch语句块,并与catch语句块逐一匹配,找到与之对应的处理程序,其他的catch语句块将不会被执行,而try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句;
1、throws抛出异常
当方法可能会出现异常,但没有能力处理这种异常,可以在方法中声明throws抛出异常,例如汽车在运行时可能会出现故障,但汽车本身无法解决,得抛给开车的人。
Throws语句用在方法定义时声明该方法要抛出的异常类型,多个类型用逗号分隔。
methodname throws Exception1,Exception2,..,ExceptionN{
}
方法名后的throws Exception1,Exception2,..,ExceptionN为异常列表,当方法遇到异常列表中异常及其子类时,将不做处理直接抛给调用该方法的方法。
import java.lang.Exception; public class TestException { static void pop() throws NegativeArraySizeException { // 定义方法并抛出NegativeArraySizeException异常 int[] arr = new int[-3]; // 创建数组 } public static void main(String[] args) { // 主方法 try { // try语句处理异常信息 pop(); // 调用pop()方法 } catch (NegativeArraySizeException e) { System.out.println("pop()方法抛出的异常");// 输出异常信息 } } }pop方法没有处理异常NegativeArraySizeException,而是由main函数来处理。
throws抛出异常的规则
(1)如果是不可查异常(unchecked exception),即runtimeException或者Error,在编译期间不会对其检查也会通过,无需用throws抛出异常。
(2)如果一个方法中会出现可查异常则必须用try-catch捕获或是throws声明抛出,否则编译会出错。
(3)仅当抛出了异常,该方法的调用者才必须处理或重新抛出异常。
(4)调用方法必须遵循任何可查异常的处理和声明规则。当继承时,若覆盖一个方法,声明的任何异常都必须与重写方法所声明的异常相同或是异常的子类。
2、使用throw抛出异常
throw可以在函数体中使用,并且需要在出现的方法中声明throws 抛出与throw相同的异常。Throw用来抛出一个Throwable的异常,程序会在throw后立即停止,后面的语句执行不到,然后在包含它的try块中(可能在调用函数中)从里向外查找匹配的异常处理catch字句(Java这种向上传递异常信息的处理机制,形成异常链)。
注意:当所有的方法都层层上抛异常,最终会交给JVM处理,打印异常消息和堆栈消息。如果抛出的是Error或RuntimeException,则该方法的调用者可选择处理该异常。
package Test; import java.lang.Exception; public class TestException { static int quotient(int x, int y) throws MyException { // 定义方法抛出异常 if (y < 0) { // 判断参数是否小于0 throw new MyException("除数不能是负数"); // 异常信息 } return x/y; // 返回值 } public static void main(String args[]) { // 主方法 int a =3; int b =0; try { // try语句包含可能发生异常的语句 int result = quotient(a, b); // 调用方法quotient() } catch (MyException e) { // 处理自定义异常 System.out.println(e.getMessage()); // 输出异常信息 } catch (ArithmeticException e) { // 处理ArithmeticException异常 System.out.println("除数不能为0"); // 输出提示信息 } catch (Exception e) { // 处理其他异常 System.out.println("程序发生了其他的异常"); // 输出提示信息 } } } class MyException extends Exception { // 创建自定义异常类 String message; // 定义String类型变量 public MyException(String ErrorMessagr) { // 父类方法 message = ErrorMessagr; } public String getMessage() { // 覆盖getMessage()方法 return message; } }getCause():返回抛出异常的原因。如果 cause 不存在或未知,则返回 null。
getMeage():返回异常的消息信息。
printStackTrace():对象的堆栈跟踪输出至错误输出流,作为字段 System.err 的值。
有时为了简单会忽略掉catch语句后的代码,这样try-catch语句就成了一种摆设,一旦程序在运行过程中出现了异常,就会忽略处理异常,而错误发生的原因很难查找。
在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()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常