异常的捕获和处理

异常概述

1.认识异常

异常是指在程序的运行过程中所发生的不正常事件,如所需文件找不到、网络连接不通或连接中断、算术运算出错(如被零除)、数组 下标越界、装载一个不存在的类、对null对象操作、类型转换异常等。异常会中断正在运行的程序。

 

通过if-else语句进行异常处理,有以下缺点。
代码臃肿, 加入了大量的异常情况判断和处理代码。
程序员把相当多的精力放在 了异常处理代码上,放在了“堵漏洞”上,占用了编写业务代码的时间,必然影响开发效率。
很难穷举所有 的异常情况,程序仍旧不健壮。
异常处理代码和业务代码交织在一 起, 影响代码的可读性,加大日后程序的维护难度。
Java提供了异常处理机制,可以由系统来处理程序在运行过程中可能出现的异常事件,使程序员有更多精力关注于业务代码的编写。
 

2. Java 异常体系结构

Java中的异常有很多类型,异常在Java中被封装成了各种异常类。
所有异常类型都是Throwable类的子类,它派生了两个子类: Error 类和Exception类。
(1) Error 类:表示仅靠程序本身无法恢复的严重错误,如内存溢出、动态链接失败、虚拟机错误。应用程序不应该抛出这种类型的错误(般由虚拟机抛出)。假如出现这种错误,应尽力使程序安全退出。所以在进行程序设计时,应该更关注Exception类。

(2) Exception 类:由Java应用程序抛出和处理的非严重错误,如所需文件找不到、网络连接不通或连接中断、算术运算出错(如被零除)、数组下标越界、装载一个不存在的类、对null 对象操作、类型转换异常等。它的各种不同的子类分别对应不同类型的异常。Exception 又可分为两大类异常。


运行时异常:包括RuntimeException及其所有子类。不要求程序必须对它们进行处理,如示例1中的算术异常AthticExepiiie本章重点讲解的就是这类异常。

 Cheked异常(非运行时异常):除了运行时异常外的其他从Ecpon类继承来的异常类。

 

2.java异常处理机制

1.异常处理
异常处理机制就像人们对平时可能会遇到的意外情况,预先想好了一些处理的办法。在程序执行代码时,若发生了异常,程序会按照预定的处理办法对异常进行处理,异常处理完毕之后,程序继续运行。
Java的异常处理是通过5个关键字来实现的,即try、catch、 finally、 throw 和throws

2.使用try-catch 处理异常
Java中提供了try-catch 结构进行异常捕获和处理,把可能出现异常的代码放入try语句块中,并使用catch 语句块捕获异常。

try catch语句块的执行流程比较简单,首先执行的是try语句块中的语句,这时可能会出现以下3种情况。
(1)如果try语句块申所有语句正常执行完毕,没有发生异常,那么catch语句块中的所有语句都将会被忽略。当在控制台输入两个整数时,示例3中的try语句块中的代码将正常执行,不会执行eatch语句块中的代码。输出结果如图91所示。
(2)如果try语句块在执行过程中发生异常,并且这个异常与eatch语句块中声明的异常类型匹配,那么try语句块中剩下的代码都将被忽略,而相应的catch语句块将会被执行。四配是指catch所处理的异常类型与所生成的异常类型完全一致或 是它的父类。

(3)如果try语句块在执行过程中发生异常,而抛出的异常在cach语句块中没有被声明,那么方法立刻退出。
常用的方法如下。
 void pintStackTrace(): 输出异常的堆栈信息。堆栈信息包括程序运行到当前类的执行流程,它将输出从方法调用处到异常抛出处的方法调用序列。
String getMessage():返回异常信息描述字符串,该字符申描述了异常产生的原因,是printStackTrace()输出信息的一部分。

3. 使用try-catch- finally处理异常
如果希望示例3中不管是否发生异常,都执行输出“感谢使用本程序!”语句,就需要在try-catch语句块后加入finally语句块,把要执行输出的语句放入finally语句块中。无论是否发生异常,finally 语句块中的代码总能被执行。

try-catch -finally语句块的执行流程大致分为如下两种情况。
(1)如果try语句块中所有语句正常执行完毕,fnally语句块也会被执行。例如,当在控制台输入两个数字时,示例4中的try语句块中的代码将正常执行,不会执行catch语句块中的代码,但是finally语句块中的代码将被执行。

(2)如果try语句块在执行过程中发生异常,无论这种异常能否被catch语句块捕获到,都将执行finally语句块中的代码。例如,当在控制台输入的除数为0时,示例4中的try语句块中将抛出异常,进入catch语句块,最后finally语句块中的代码也将被执行。
try-catch-finally结构中try语句块是必须存在的,catch, finally 语句块为可选,仙两者至少出现其中之一。
需要特别注意的是,即使在catch请句块中存在returm语句,fnally语句块中的通句也会执行。发生异常时的执行顺序是,先执行catch语句块中return之前的语句,在执行finally语句块中的语句,最后执行catch语句块中的return并退出

4.使用多重catch处理异常
在计算并输出商的示例中,至少存在两种异常情况,输入非整数内容和除数为0.在示例4中统一按照 Exception类型捕获,其实可使用多重catch语句块分别捕获并外理对应异常。
一段代码可能会引发多种类型的异常, 这时,可以在一个 try语句块后面跟多个catch语句块分别处理不同的异常。但排列顺序必须是从子类到父类,最后一个一般都是Exception类。因为按照匹配原则,如果把父类异常放到前面,后面的catch语句块将不会获得执行机会。
运行时,系统从上到下分别对每个catch语句块处理的异常类型进行检测,并执行第一个与异常类型匹配的catch语句。执行其中的一条 catch 语句之后, 其后的catch 语句将被忽略。

5. 使用throws声明抛出异常
如果在一个方法体中抛出 了异常,并希望调用者能够及时地捕获异常, Java语言中通过关键字throws声明某个方法可能抛出的各种异常以通知调用者。throws 可以同时声明多个异常,之间由逗号隔开。
在下面的示例7中,把计算并输出商的任务封装在了divide() 方法中,并在方法的参数列表后通过throws声明抛出了异常,然后在main()方法中调用该方法,此时mainO方法就知道divide0方法中抛出了异常,可以采用如下两种方式进行处理。

通过try-catch捕获并处理异常。

通过throws继续声明异常。如果调用者不知道如何处理该异常,可以维续通过throws声明异常,让上一级调用者处理异常。main() 方法声明的异常将由java虚拟机来处理。

6.使用throw抛出异常
除了系统自动抛出异常外,在编程过程中,有些问题是系统无法自动发现并解决的,如年龄不在正常范围内,性别输入不是“男”或“女”等,此时需要程序员而不是系统来自行抛出异常,把问题提交给调用者去解决。
在Java语言中,可以使用throw关键字来自行抛出异常。在下面示例8的代码中抛出了一个异常, 抛出异常的原因在于当前环境无法解决参数问题,因此在方法内部通过throw抛出异常,把问题交给调用者去解决。

7,自定义异常
当JDK中的异常类型不能满足程序的需要时,可以自定 义外常类。使用自定义师常股有如下几个步骤 ,
(1)定义异常类,并继承Exepion成M RuntimeExepion
(2)编写异常类的构造方法,并继承父类的实现,常见的构造方法有如下4种形式。
构造方法1

public MyException(){

supe();

}

构造方法2

public MyException(String message) {

super(message);

}

构造方法3

public MyException(String message, Throwable cause) {

super(message, cause);

}

构造方法 4

public MyException(Throwable cause) {

super(cause);

}

3.实例化自定义异常处理,并在程序中使用throw抛出

 

8.异常链
在异常处理时有时会遇到如下情况: A方法调用B方法,B方法却抛出了异常。那么A方法是继续抛出原有的异常还是抛出一个新异常呢?若抛出原有的异常将是很糟糕的设计方法。因为A方法与B方法进行了关联,不便于代码的修改和扩展。若抛出新的异常,虽然解决了A方法和B方法的关联问题,但是原有的异常信息却会丢失。幸运的是,JDK 1.4推出了异常链,正好解决这个问题。它虽然创建了新的异常,但却保留了原有异常的信息。
 


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值