文章目录
1.异常
1.1 异常类
异常是对象,而对象都采用类来定义。异常的根类是 java.lang.Throwable。
Throwable 类是所有 异常类 的根。所有的 Java 异常类都直接或者间接地继承自Throwable。可以通过继承 Exception 或者 Exception 的子类来创建自己的异常类。
1.2 异常类型
异常类可以分为三种主要类型:系统错误、异常和运行时异常。
系统错误 ( system error) 是由 Java 虚拟机抛出的,用 Error 类表示。Error 类描述的是内部系统错误。这样的错误很少发生。如果发生,除了通知用户以及尽量稳妥地终止程序外,几乎什么也不能做。
类 | 可能引起异常的原因 |
---|---|
LinkageError | 一个类依赖于另一个类,但是在编译前者后,后者进行了修改,出现不兼容 |
VirtualMachineError | Java 虚拟机崩溃. 或者继续运行所必需的资源已经耗尽 |
异常 ( exception) 是用 Exception 类表示的,它描述的是由你的程序和外部环境所引起的错误,这些错误能被程序捕获和处理。
类 | 可能引起异常的原因 |
---|---|
ClassNotFoundException | 试图使用一个不存在的类。例如,如果试图使用命令 java 来运行一个不存在的类. 或者程序要调用三个类文件而只能找到两个,都会发生这种异常 |
lOException | 同输人 /输出相关的操作,例如,无效的输人、读文件时超过文件尾、打开一个不存在的文件等。 |
运行时异常 ( runtime exception) 是RuntimeException 类表示的,它描述的是程序设计错误,例如,错误的类型转换、访问一个越界数组或数值错误。运行时异常通常表明了编程错误。
类 | 可能引起异常的原因 |
---|---|
ArithmeticException | 一个整数除以 0。注意,浮点数的算术运算不抛出异常。 |
NullPointerException | 试图通过一个 null 引用变量访问一个对象 |
ndexOutOfBoundsException | 数组的下标超出范围 |
IllegalArgumentException | 传递给方法的参数非法或不合适 |
1.3 免检异常和必检异常
RuntimeException、Error 以及它们的子类都称为免检异常 (unchecked exception)
所有其他异常都称为必检异常 (checked exception), 意味着编译器会强制程序员检查并通过 try-catch 块处理它们,或者在方法头进行声明。
在大多数情况下,免检异常都会反映出程序设计上不可恢复的逻辑错误。免检异常可能在程序的任何一个地方出现。为避免过多地使用try-catch 块,Java 语言不强制要求编写代码捕获或声明免检异常
2.异常的声明、抛出与捕获
异常的 处理器是通过从当前的方法开始,沿着方法调用链,按照异常的反向传播方向找到的
Java 的异常处理模型基于三种操作:声明一个异常 ( declaring an exception)、抛出一个异常 (throwing an exception) 和捕获一个异常 (catchingan exception)
2.1 声明异常
在 Java 中,当前执行的语句必属于某个方法。Java 解释器调用main 方法开始执行一个程序。
每个方法都必须声明它可能抛出的必检异常的类型。这称为声明异常 ( deciding exception)。 因为任何代码都可能发生系统错误和运行时错误,因此,Java不要求在方法中显式声明 Error 和 RuntimeException (免检异常)。
然而,方法要抛出的其他异常都必须在方法头中显式声明,这样,方法的调用者会被告知有异常。
public void func()
throws Exception1,Exception2,Exception3,...ExceptionN
如果父类中的方法没有声明异常,那么就不能在子类中对其重写时声明异常。
2.2 抛出与捕获异常
检测到错误的程序可以创建一个合适的异常类型的实例并抛出它,这称为抛出一个异常(throwing an exception)。
当抛出一个异常时,可以在try-catch 块中捕获和处理它。
try {
statements; / / Statements that may throw exceptions
}
catch (Exceptionl exVar1 ) {
handler for exceptionl ;
}
catch (Exception2 exVar2) {
handler for exception2;
}
catch (ExceptionN exVarN) {
handler for exceptionN;
}
finally{...}
无论异常是否产生,finally 子句总会被执行。
不论 try 块中是否出现异常或者是否被捕获。
即使在到达 finally 块之前有一个 return 语句,finally 块还是会执行。
如果 try 块中的某条语句抛出一个异常,Java 就会跳过 try 块中剩余的语句,然后开始查找处理这个异常的代码。处理这个异常的代码称为异常处理器 (exception handler)
从第一个到最后一个逐个检查 catch 块,判断在 catch 块中的异常类实例是否是该异常对象的类型。
如果是,就将该异常对象赋值给所声明的变量,然后执行 catch 块中的代码。
如果没有发现异常处理器,Java 会退出这个方法,把异常传递给这个方法的调用者,继续同样的过程来查找处理器。
如果在调用的方法链中找不到处理器,程序就会终止并且在控制台上打印出错信息。
查找处理器的过程称为捕获一个异常 (catching an exception)
各种异常类可以从一个共同的父类中派生。如果一个 catch 块可以捕获一个父类的异常对象,它就能捕获那个父类的所有子类的异常对象。(因为父类变量可以指子类对象)
catch 块中异常被指定的顺序是非常重要的。如果父类的 catch 块出现在子类的catch 块之前,就会导致编译错误。
对于使用同样的代码处理多种异常的情况,可以使用 JDK7 的新的多捕获特征(multi-catch feature)简化异常的代码编写。
catch(Exceptionl|Exception2|…|Exceptionk ex)
Java 强制程序员处理必检异常。如果方法声明了 一个必检异常(即 Error 或Runtime Exception 之外的异常),就必须在 try-catch 块中调用它,或者在调用方法中声明会抛出的异常(留给上一层方法)。
即:要么自己用try-catch处理好异常,要么自己声明异常,留给上一层方法去处理。
2.3 从异常中获取信息
3.链式异常
3.1 重新抛出异常
如果异常处理器不能处理一个异常,或者只是简 单地希望它的调用者注意到该异常,Java 允许该异常处理器重新抛出异常。
3.2 链式异常
catch 块重新抛出最初的异常。有时候,可能需要同最初异常一起抛出一个新异常(带有附加信息),这称为链式异常(chained exception)。
public class ChainedExcepti onDemo {
public static void main(String[] args) {
try {
method1 () ;
}
catch (Exception ex) {
ex.printStackTrace( ) ;
}
}
public static void methodi ( ) throws Exception {
try {
method2() ;
}
catch (Exception ex) {
throw new Exception ("New info from methodi", ex);
}
}
public static void method2( ) throws Exception {
throw new Exception("New Info from method2") ;
}
}
4.创建自定义异常类
可以通过继承 java.lang.Exception 类来定义一个 自定义异常类。
Exception 类中的所 有方法(例如,getMessage()、toString()和printStackTrace())都是从 Throwable 继承而来的。Exception 类包括四个构造方法,其中
经常使用的是以下构造方法:
public class MyException extends Exception{
private int a;
public int getA(){
return a;
}
public MyException(int a){
super("a="+a);
this.a=a;
}
}
最后,
可以继承 RuntimeException 声明一个自定义异常类吗? 可以,但这不是一个好方法,因为 这会使自定义异常成为免检异常。最好使自定义异常是必检的,这样,编译器就可以在程序中强制捕获这些异常。