十三.Java异常处理

十三.Java异常处理

Java 提供了异常处理机制来帮助程序员检查可能出现的错误,以保证程序的可读性和可维护性。

在程序中,错误可能产生于程序员没有预料到的各种情况,或者超出程序员可控范围的环境,例如用户的坏数据、试图打开一个不存在的文件等。为了能够及时有效地处理程序中的运行错误,Java 专门引入了异常类。

异常产生的原因及使用原则

  1. Java 内部错误发生异常,Java 虚拟机产生的异常。
  2. 编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。这种异常称为未检査的异常,一般需要在某些类中集中处理这些异常。
  3. 通过 throw 语句手动生成的异常,这种异常称为检査的异常,一般用来告知该方法的调用者一些必要的信息。

Java 通过面向对象的方法来处理异常。在一个方法的运行过程中,如果发生了异常,则这个方法会产生代表该异常的一个对象,并把它交给运行时的系统,运行时系统寻找相应的代码来处理这一异常。

我们把生成异常对象,并把它提交给运行时系统的过程称为拋出(throw)异常。运行时系统在方法的调用栈中查找,直到找到能够处理该类型异常的对象,这一个过程称为捕获(catch)异常

Java 异常强制用户考虑程序的强健性和安全性。**异常处理不应用来控制程序的正常流程,其主要作用是捕获程序在运行时发生的异常并进行相应处理。**编写代码处理某个方法可能出现的异常,可遵循如下三个原则:

  1. 在当前方法声明中使用 try catch 语句捕获异常。
  2. 一个方法被覆盖时,覆盖它的方法必须拋出相同的异常或异常的子类。
  3. 如果父类抛出多个异常,则覆盖方法必须拋出那些异常的一个子集,而不能拋出新异常。

异常类型

在 Java 中所有异常类型都是内置类 java.lang.Throwable 类的子类,即 Throwable 位于异常类层次结构的顶层。

Throwable 类下有两个异常分支 Exception 和 Error

[外链图片转存失败(img-JHkc49AX-1568539911695)(C:\Users\72451\AppData\Roaming\Typora\typora-user-images\1568537614050.png)]

Throwable 类是所有异常和错误的超类,下面有 Error 和 Exception 两个子类分别表示错误和异常。

其中异常类 Exception 又分为运行时异常和非运行时异常,这两种异常有很大的区别,也称为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。

  • Exception 类用于用户程序可能出现的异常情况,它也是用来创建自定义异常类型类的类。

  • Error 定义了在通常环境下不希望被程序捕获的异常。Error 类型的异常用于 Java 运行时由系统显示与运行时系统本身有关的错误。堆栈溢出是这种错误的一例。

  • 不讨论关于 Error 类型的异常处理

    运行时异常都是 RuntimeException 类及其子类异常,如 NullPointerException、IndexOutOfBoundsException 等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般由程序逻辑错误引起,程序应该从逻辑角度尽可能避免这类异常的发生。

非运行时异常是指 RuntimeException 以外的异常,类型上都属于 Exception 类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如 IOException、ClassNotFoundException 等以及用户自定义的 Exception 异常,一般情况下不自定义检查异常。

常见的异常类型及它们的作用

异常类型说明
Exception异常层次结构的根类
RuntimeException运行时异常,多数 java.lang 异常的根类
ArithmeticException算术谱误异常,如以零做除数
ArraylndexOutOfBoundException数组大小小于或大于实际的数组大小
NullPointerException尝试访问 null 对象成员,空指针异常
ClassNotFoundException不能加载所需的类
NumberF ormatException数字转化格式异常,比如字符串到 float 型数字的转换无效
IOExceptionI/O 异常的根类
F ileN otF oundException找不到文件
EOFException文件结束
InterruptedException线程中断
IllegalArgumentException方法接收到非法参数
ClassCastException类型转换异常
SQLException操作数据库异常

Java异常处理机制及异常处理的基本结构

异常处理的机制:

  • 在方法中用 try catch 语句捕获并处理异常,catch 语句可以有多个,用来匹配多个异常。
  • 对于处理不了的异常或者要转型的异常,在方法的声明处通过 throws 语句拋出异常,即由上层的调用方法来处理。
//try catch 语句用于捕获并处理异常
try
{
    逻辑程序块
}
catch(ExceptionType1 e)
{
    处理代码块1
}
catch (ExceptionType2 e)
{
    处理代码块2
    throw(e);    //throw 语句用于拋出异常
}

//finally 语句用于在任何情况下(除特殊情况外)都必须执行的代码
finally
{
    释放资源代码块
}

//throws 语句用于声明可能会出现的异常。

在以上语法中,把可能引发异常的语句封装在 try 语句块中,用以捕获可能发生的异常。

如果 try 语句块中发生异常,那么一个相应的异常对象就会被拋出,然后 catch 语句就会依据所拋出异常对象的类型进行捕获,并处理。处理之后,程序会跳过 try 语句块中剩余的语句,转到 catch 语句块后面的第一条语句开始执行。

如果 try 语句块中没有异常发生,那么 try 块正常结束,后面的 catch 语句块被跳过,程序将从 catch 语句块后的第一条语句开始执行。

在以上语法的处理代码块1中,可以使用以下 3 个方法输出相应的异常信息。

  • printStackTrace() 方法:指出异常的类型、性质、栈层次及出现在程序中的位置。
  • getMessage() 方法:输出错误的性质。
  • toString() 方法:给出异常的类型与性质。

在实际开发中,根据 try catch 语句的执行过程,try 语句块和 catch 语句块有可能不被完全执行,而有些处理代码则要求必须执行,例如文件的关闭、释放资源等,此时就可以将这些代码放在 finally 语句块中。

img

try catch finally 语句块的执行情况可以细分为以下 5 种情况:

  1. 如果 try 代码块中没有拋出异常,则执行完 try 代码块之后直接执行 finally 代码块,然后执行 try catch finally 语句块之后的语句。
  2. 如果 try 代码块中拋出异常,并被 catch 子句捕捉,那么在拋出异常的地方终止 try 代码块的执行,转而执行相匹配的 catch 代码块,之后执行 finally 代码块。如果 finally 代码块中没有拋出异常,则继续执行 try catch finally 语句块之后的语句;如果 finally 代码块中拋出异常,则把该异常传递给该方法的调用者。
  3. 如果 try 代码块中拋出的异常没有被任何 catch 子句捕捉到,那么将直接执行 finally 代码块中的语句,并把该异常传递给该方法的调用者。
  4. 在前面的代码中用 System.exit() 退出运行。如果代码在 try 内部执行一条 System.exit() 语句,则应用程序将终止而不会执行 finally。
  5. 如果在执行 finally 块之前,程序所在的线程死亡,finally 块将不被执行。

Java声明和抛出异常

通过 throws 关键字在方法上声明该方法要拋出的异常,然后在方法内部通过 throw 拋出异常对象

throws 关键字和 throw 关键字在使用上的几点区别如下

  • throws 用来声明一个方法可能抛出的所有异常信息,throw 则是指拋出的一个具体的异常类型。
  • 通常在一个方法(类)的声明处通过 throws 声明方法(类)可能拋出的异常信息,而在方法(类)内部通过 throw 声明一个具体的异常信息。
  • throws 通常不用显示地捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法; throw 则需要用户自己捕获相关的异常,而后再对其进行相关包装,最后将包装后的异常信息抛出。
throws 声明异常

当一个方法产生一个它不处理的异常时,那么就需要在该方法的头部声明这个异常,以便将该异常传递到方法的外部进行处理。可以使用 throws 关键字在方法的头部声明一个异常,其具体格式如下:

returnType method_name(paramList) throws Exception 1,Exception2,{}	//其中,returnType 表示返回值类型,method_name 表示方法名,Exception 1,Exception2,… 表示异常类。

如果有多个异常类,它们之间用逗号分隔。这些异常类可以是方法中调用了可能拋出异常的方法而产生的异常,也可以是方法体中生成并拋出的异常。

在编写类继承代码时要注意,子类在覆盖父类带 throws 子句的方法时,子类的方法声明中的 throws 子句不能出现父类对应方法的 throws 子句中没有的异常类型,因此 throws 子句可以限制子类的行为。也就是说,子类方法拋出的异常不会超过父类定义的范围。

throw 拋出异常

throw 语句用来直接拋出一个异常,后接一个可拋出的异常类对象,其语法格式如下:

throw ExceptionObject;

其中,ExceptionObject 必须是 Throwable 类或其子类的对象。如果是自定义异常类,也必须是 Throwable 的直接或间接子类。

当 throw 语句执行时,它后面的语句将不执行,此时程序转向调用者程序,寻找与之相匹配的 catch 语句,执行相应的异常处理程序。如果没有找到相匹配的 catch 语句,则再转向上一层的调用程序。这样逐层向上,直到最外层的异常处理程序终止程序并打印出调用栈情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值