Java中的异常处理

来源:互联网 发布:淘宝纯露哪家比较好 编辑:程序博客网 时间:2024/05/21 09:51

一、什么是异常

异常是一种对象,表示阻止正常进行程序执行的错误或者情况,包括数组下标越界、除数为零、网络连接失败、非法参数、空指针异常、文件找不到等。

二、异常的种类

异常类

这些异常类可分为三种主要类型:系统错误、异常和运行时异常。

系统错误(system error)
由Java虚拟机抛出,用Error类表示。Error类描述的是内部系统错误。这样错误很少发生。如果发生,除了通知用户以及尽量稳妥地终止程序外,几乎什么也不能做。
如:
LinkageError - 一个类对另一个类有某种依赖性,但是编译前者在后,后者进行了修改,变得不兼容
VirtualMachineError - Java虚拟机崩溃,或者运行所需的资源已经耗尽

异常(exception)
用Exception类表示,描述的是由程序和外部环境所引起的的错误,这些错误能被程序捕获和处理。
如:
ClassNotFoundException - 试图调用不存在的类
IOException - 同输入/输出有关的操作,如无效输入、读文件超过文件尾、打开一个不存在的文件等。
运行时异常(runtime exception)
用RuntimeException类表示,描述的是程序设计错误,通常由Java虚拟机抛出。
常见的有:
NullPointerException - 空指针引用异常
ClassCastException - 类型强制转换异常
IllegalArgumentException - 传递非法参数异常
ArithmeticException - 算术运算异常(一个整数除以0,浮点数的算数运算不抛出异常)
ArrayStoreException - 向数组中存放与声明类型不兼容对象异常
IndexOutOfBoundsException - 下标越界异常
NegativeArraySizeException - 创建一个大小为负数的数组错误异常
NumberFormatException - 数字格式异常
SecurityException - 安全异常
UnsupportedOperationException - 不支持的操作异常

免检异常与必检异常

RuntimeException、Error以及它们的子类都称为免检异常(unchecked exception);所有其他的异常都称为必检异常(checked exception),意思是必须通过try-catch块处理它们,或在方法头中进行声明。

大多数情况下,免检异常都会反映出程序设计上不可恢复的逻辑错误。是程序中必须纠正的逻辑错误,但免检异常可能在程序中的任何一个地方出现,为避免过多的使用try-catch块,Java语言不强制要求编写代码捕获或者声明免检异常。

三、异常处理模型

Java的异常处理基于三种模型:声明一个异常,抛出一个异常,捕获一个异常。

1、声明

每个方法都必须在方法头声明它可能抛出的必检异常的类型,这称为免检异常。
在方法中声明一个异常,在方法头中要用到关键字throws

public void myMethmod() throws IOException

如果该方法可能抛出多个异常,就可以在关键字throws后添加一个用逗号分隔的异常列表

public void myMethmod()    throws Exception1,Exception2,...,ExceptionN

attention:如果方法在父类中没有声明异常,那么就不能在子类中对其进行继承来声明异常。

2、抛出

检测到错误的程序可以创建一个合适的异常类型的实例并抛出它,这就称为抛出一个异常。
例如程序发现传递给方法的参数与方法的合约不符,这时可创建IllegalArgumentException的一个实例并抛出它,如下所示:

IllegalArgumentException ex = new IllegalArgumentException("wrong Argument");throw ex;

或者,根据你的偏好,也可以使用下面的语句

throw new IllegalArgumentException("wrong Argument");

attention:声明异常的关键字是throws,抛出异常的关键字throw。

3、捕获

当声明和抛出异常后,可以在try-catch中捕获和处理它

try{    statements;//maybe throw exceptions}catch(Exception1 exVar1){    hanlder for Exception1;}catch(Exception2 exVar2){    hanlder for Exception3;}...catch(ExceptionN exVarN){    hanlder for ExceptionN;}

1.如果执行try块中没有出现异常,则跳过catch子句。

2.如果执行try块中某个语句抛出异常,Java就会跳过try块中的剩余语句,然后开始查找处理这个异常代码的过程。从第一个到最后一个逐个检查catch块,判断在catch块中是否是该异常对象的类型,如果是,就将该异常对象赋值给所声明的变量,然后执行catch块中的代码。如果执行完最后一个catch还没有发现异常处理器,那么就会退出这个方法,把此异常传递给调用这个方法的方法,继续进行同样的过程来查找异常处理器。如果在调用方法链都找不到异常处理器,程序就会在控制台上打印出出错信息。

寻找异常处理器的过程被称为捕获一个异常。

如果一个catch块可以捕获一个父类的异常对象,它就能捕获那个父类的所有子类的异常对象。

catch块中异常被指定的顺序是非常重要的。如果父类的catch出现子类的catch块之前,就会导致编译错误。

//错误的代码try{    ...}catch(Exception ex){    ...}catch(RuntimeException ex){    ...}
//正确的代码try{    ...}catch(RuntimeException ex){    ...}catch(Exception ex){    ...}

4、从异常中获取信息

可以用java.lang.Throwable类中的实例方法获取有关异常的信息
从异常中获取信息

5、finally子句

无论异常是否产生,finally子句总是会被执行的

//正确的代码try{    statements;}catch(TheException ex){    handling ex;}finally{    finalStatements;}

注意:如果try块中无异常,执行finalStatements,然后执行try语句下一条语句。如果有一条语句引起异常,并且被catch块捕获,然后跳过try块其它语句,执行catch块和finally子句,执行try语句下一条语句;若没有被catch捕获,就会跳过try块中的其他语句,执行finally子句,并且将异常传递给这个方法的调用者。即使在到达finally块之前有一个return语句,finally块还是会执行。

异常处理器需要初始化新的异常对象,需要从调用栈返回,而且还需要沿着方法调用链来传播异常以便找到他的异常处理器,即异常处理器通常需要更多的时间和资源。

不要把异常处理用作简单的逻辑测试,即不要用try-catch处理简单的、可预料的情况。

6、重新抛出异常

如果异常处理器不能处理一个异常,或者只是简单的希望它的调用者注意到该异常,Java允许该异常处理器重新抛出异常。

try {    statements}catch(TheException ex){    perform operations before exits;    throw ex;}

7、链式异常

有时候,需要将原始异常一起抛出一个新异常(带有附加信息),这称为链式异常。

8、创建自定义异常类

Java中提供相当多的异常类,尽量不要自己创建异常类。然而,如果遇到不能用预定义异常类恰当的描述问题,那就可以通过派生Exception类或其子类,来创建自己的异常类。

//demopublic class InvaildRadiusExpetion extends Exception{    private double radius;    public InvaildRadiusExpetion(double radius){        super("Invalid radius " + radius);        this.radius = radius;    }    public double getRadius(){        return radius;    }}
原创粉丝点击