Skip to content

14.异常

14.1定义

运行期间出现的错误,而不是编译时的语法错误

例如,

  1. 打开一个不存在的文件
  2. 网络连接中断
  3. 操作数组越界等

14.2 异常的继承树

Object 类的直接子类Throwable描述了所有被虚拟机抛出的非正常状况。一般情况下很少用Throwable,而是使用它的两个子类Error、Exception。

  • Error类特指应用程序在运行期间发生的严重错误。如:虚拟机内存用尽、堆栈溢出等等。一般情况下这种错误都是灾难性的,所以没有必要使用异常处理机制处理Error。

  • Exception类有几十个子类,描述了不同类型的异常,其中:

    • 以RuntimeException为代表的一些类,称为非检查性异常(unchecked Exception),
    • 以IOException为代表的一些类为检查性异常(checked Exception)。所谓的检查和非检查是指编译器在编译时是否检查。如果代码中存在检查性异常,必须进行异常处理,否则编译时不能通过;而非检查性异常编译时不进行检查,到运行时才会显现。

异常类型

  • 检查性异常(checked exception)
    • 若系统运行时可能产生该类异常,则必须写出相应的处理代码,否则无法通过编译
    • 非RuntimeException异常
  • 非检查性异常(unchecked exception)
    • 若系统运行时可能产生该类异常,则不必在程序中声明对该类异常的处理,就可以编译执行
    • RuntimeException:运行时异常

14.3 Java为何分别处理这两类异常?

  • 一般我们不在 代码中处理非检查性异常,这类异常都在运行时抛出。原因主要是由于程序员经验不足或是思维不缜密造成。如:数组越界异常(ArrayIndexOutOfBoundsException)、整数除以0异常(ArithmeticException)等,这类异常其实就是我们通常说的bug。所以,这类异常应通过反复测试尽量避免,而不应该靠异常处理机制来解决。
  • 检查性异常不同,就算程序员再有经验,也是难以避免。如:用户连接数据库的异常(SQLException),如果是由于数据库服务器没有启动或是网络中断引起的,我们程序员是无法避免的。又如:程序要读取光盘中的文件,而用户忘记插入光盘,此时则抛出文件没找到异常(FileNotFoundException),程序员也无法避免。
  • 综上,异常处理机制主要处理检查性异常而不是非检查性异常和Error。

14.4 异常类型

非检查性异常说明
RuntimeExceptionjava.lang包中多数异常的基类
ArithmeticException算术错误,如除以 0
IllegalArgumentException方法收到非法参数
ArrayIndexOutOfBoundsException数组下标出界
NullPointerException试图访问 null 对象引用
检查性异常说明
ClassNotFoundException无法找到想要创建对象的类文件
IOExceptionI/O 异常的根类
FileNotFoundException不能找到文件
EOFException文件结束
IllegalAccessException对类的访问被拒绝
NoSuchMethodException请求的方法不存在
InterruptedException线程中断

14.5 异常处理机制

  • 在Java程序执行过程中如果出现异常事件,系统会发出异常报告,这时系统将生成一个异常类对象,异常类对象封装了异常事件的信息并将其提交给Java运行时系统
  • Java 中可用于处理异常的两种方式:
    1. 自行处理:可能引发异常的语句封入在 try 块内,而处理异常的相应语句则封入在 catch 块内。
    2. 回避异常:在方法声明中包含 throws 子句,通知潜在调用者,如果发生了异常,必须由调用者处理。

14.5.1. try…catch语句

​ catch块,是用来捕获并处理try块抛出的异常的代码块。没有try块,catch块不能单独存在。我们可以有多个catch块,以捕获不同类型的异常

​ try{…}和catch( ){…}之间不可以添加任何代码

  1. 如果程序抛出多个不同类型的异常,我们需要多个catch()语句来处理。
  2. 和特殊异常类相关联的catch()块必须写在和普通异常类相关联的catch()之前。
  3. 每次try块有异常抛出,系统会试着从上到下往每个catch块中传参,直到遇到一个类型匹配的catch块为止。
  4. 如上示例中最后一个catch块中的形参为Exception类型,它是所有异常类的父类,任何异常都可以传参到该块中,该块可以处理任何类型的异常。因此,这个catch块只能放到最后面,否则所有的异常都被它处理了,其他的catch块就不能分门别类的起作用了。
  5. 一般一个catch块中是专门处理异常的代码,在程序中这里还可以是记录日志的语句,当发生异常时记录该日志,无异常时将不会记录。

14.5.2 finally异常处理机制

  1. finally语句放在try …catch语句后

  2. fianlly语句中的代码块不管异常是否被捕获总是要执行

  3. 通常在finally语句中可以进行资源的清除操作,如:关闭打开文件、删除临时文件

  4. 对应finally代码中的语句,即使try代码块和catch代码块中使用了return语句退出当前方法或般若break跳出某个循环,相关的finally代码块都有执行。

  5. 当try或catch代码块中执行了System.exit(0)时,finally代码块中的内容不被执行

14.5.3 throws关键字

  1. 如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理,则可以在程序所在的函数声明后,使用throws关键字抛出异常
  2. 位置:函数参数列表的后面
  3. throws关键字后面,可以跟多个异常,中间用逗号分割
  4. throws关键字抛出的异常,由调用该函数的函数处理。
  5. 方法中如果用throws关键字抛出:
    • 非检查性异常:上一级去除异常,直到不抛出异常;
    • 检查性异常
      • 在调用该函数内try-catch,把异常处理掉。那么不往上一级抛出异常,程序正常执行,上一级方法并不知道曾经产生异常。
      • 用throws声明方法抛出异常,不进行处理。谁调用谁负责处理
      • 覆盖方法抛出异常时,可以抛出与被覆盖方法相同的异常或者被覆盖方法异常的子类异常。

14.5.4 throw语句

异常是通过关键字throw抛出,程序可以用throw语句引发明确的异常。 例如:

java
void doA() throws Exception1 {
	try {
    	...
    } catch(Exception1 e) { 
    	throw e;
   	} catch(Exception2 e) {
   		System.out.println("出错了"); 
   	} 
}

throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。不能单独使用,要么和try.. catch…一起使用,要么和throws一起使用。

throw语句的操作数一定是Throwable类类型或Throwable子类类型的一个对象

14.6. 方法调用堆栈

方法调用堆栈

  • 后进先出:方法A调用方法B的时候,只有方法B先完成后,方法A才完成。先执行的方法总是后完成,后执行的方法先完成,类似于数据结构中的堆栈--后进先出,我们称之为方法调用堆栈。

  • 如示例,仅有一条语句抛出异常,会导致所有的方法都不能正常结束。如果不想出现这样的情况,我们就要使用java的异常处理机制-抓抛模型。

14.7 自定义异常类

如果Java提供的异常类型不能满足程序设计的需要,我们可以定义自己的异常类型。

用户自定义的异常类应为 Exception 类(或者Exception 类的子类)的子类

java
/**
 * 项目:      javaadvice
 * 类名:       NumMaxException
 * 创建时间:  2020/11/17  14:21
 * 描述 :
 * 作者 :     张金山 
 * QQ:	314649444
 * Site:      https://jshand.gitee.io
 *  当参数类型为num,超过最大值的时候抛出
 */
public class NumMaxException extends Exception{
    public NumMaxException() {
    }

    public NumMaxException(String message) {
        super(message);
    }
}

使用

java
public static int sum(int numa ,int numb) throws Exception {
    if(true){
        throw new NumMaxException("数据范围不正确....{"+numa+"}");
    }
    return numa + numb;
}

Released under the MIT License.