目录
Java异常
一、内容回顾
异常处理提供了一个统一的机制来识别和响应程序错误,一个有效的异常处理方法可以使得程序健壮并易于调试。在这一部分将介绍Java的异常机制,使用,以及如何定义自己的异常类。
(一)Java异常的分类
所有的Java异常都由Throwable继承下来,并在下一层产生两个分支:Error和Exception,如图1所示。
(1)Error类层次描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。如果出现这样的内部错误,能做的只有通知用户并尽力使程序安全终止。
(2)我们在设计Java程序的时候,重点关注Exception。Exception类层次结构又分解为两个分支,一个分支派生于RuntimeException,另一个包含其他异常。划分两个分支的规则是:由程序错误导致的异常属于RuntimeException(比如错误的类型转换,数组访问越界,访问空指针等);曾经能够正确运行,由于某些情况导致的异常则不属于RuntimeException(比如文件损坏,网络连接中断等)。
图10-1 Java异常类层次结构图
另外,Java语言规范将派生于Error类和RuntimeException类的所有异常称为“未检查异常”,其他的异常称为“已检查异常”。如果程序出现了“未检查异常”,那么程序员应该尽力去排除程序的错误,而不是去捕获这类异常。
(二)Java的异常处理
Java程序的执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。如果Java运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的Java程序也将退出。
对于异常的处理,Java提供了两种方式
(1)在方法中用try-catch-finally语句捕获并处理异常。catch语句可以有多个,用来匹配多个异常。finally是可选语句,为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理,通常用来释放各种资源。不论在try代码块中是否发生了异常事件,finally块中的语句都会被执行。
-
try{
-
-
......
//可能产生异常的代码
-
-
}
catch( ExceptionName1 e ){
-
-
......
//当产生ExceptionName1型异常时的处置措施
-
-
}
catch( ExceptionName2 e ){
-
-
......
//当产生ExceptionName2型异常时的处置措施
-
-
} [
finally{
-
-
......
//无条件执行的语句
-
-
} ]
(2)声明抛出异常是Java中处理异常的第二种方式,即在方法的声明处通过throws语句抛出异常。如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
如果每个方法都是简单的抛出异常,那么在方法调用方法的多层嵌套调用中,Java虚拟机会从出现异常的方法代码块中往回找,直到找到处理该异常的代码块为止。然后将异常交给相应的catch语句处理。如果Java虚拟机追溯到方法调用栈最底部main()方法时,如果仍然没有找到处理异常的代码块,将首先调用异常的对象的printStackTrace()方法,打印方法调用栈的异常信息。如果出现异常的线程为主线程,则整个程序运行终止;如果非主线程,则终止该线程,其他线程继续运行。可以看出,越早处理异常消耗的资源和时间越小,产生影响的范围也越小。因此,尽量不要把自己能处理的异常也抛给调用者。
(三)自定义异常类
前面提到,Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出。如果Java内置的异常类不能够满足需求,也可根据需要人工创建并抛出异常。
人工创建并抛出异常,首先要生成异常对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。另外,可以抛出的异常对象必须是Throwable或其子类的实例。我们自己定义的异常类必须派生于Exception或者Exception的子类。
二、典型实例
例1 本例实现的是求一个整数的阶乘,并对各种非正常情况捕获处理异常。
-
// ExceptionTest.java
-
-
public
class ExceptionTest{
-
-
public static double multi(int n){
-
-
if(n<
0)
-
-
throw
new IllegalArgumentException(
"求负数阶乘异常");
-
-
double s=
1;
-
-
for(
int i=
1;i<=n;i++)
-
-
s=s*i;
-
-
return s;
-
-
}
-
-
public static void main(String[] args){
-
-
try{
-
-
int m=Integer.parseInt(args[
0]);
-
-
System.out.println(m+
"!="+multi(m));
-
-
}
-
-
catch (ArrayIndexOutOfBoundsException e){
-
-
System.out.println(
"命令行中没提供参数!");
-
-
}
-
-
catch (NumberFormatException e){
-
-
System.out.println(
"应输入一个整数!");
-
-
}
-
-
catch (IllegalArgumentException e){
-
-
System.out.println(
"出现的异常是:"+e.toString());
-
-
}
-
-
finally{
-
-
System.out.println(
"程序运行结束!");
-
-
}
-
-
}
-
-
}
程序执行结果如图2所示。
说明:
①本例的运行需要有参数,参数赋值给args[0]。
图2 例1执行结果
例2 本例测试如何人工抛出异常。
-
// ThrowTest.java
-
-
import java.util.Scanner;
-
-
class MyException extends Exception {
-
-
private
int idnumber;
-
-
public MyException(String message, int id) {
-
-
super(message);
-
-
this.idnumber = id;
-
-
}
-
-
public int getId() {
-
-
return idnumber;
-
-
}
-
-
}
-
-
public
class ThrowTest{
-
-
public void regist() throws MyException {
-
-
Scanner sc =
new Scanner(System.in);
-
-
int num = sc.nextInt();
-
-
if (num <
0) {
-
-
throw
new MyException(
"人数为负值,不合理",num);
-
-
}
-
-
System.out.println(
"登记人数" + num);
-
-
}
-
-
public void manager() {
-
-
try {
-
-
regist();
-
-
}
catch (MyException e) {
-
-
System.out.println(
"登记失败,出错种类"+e.getId());
-
-
}
-
-
System.out.print(
"本次登记操作结束");
-
-
}
-
-
public static void main(String args[]){
-
-
ThrowTest tt =
new ThrowTest();
-
-
tt.manager();
-
-
}
-
-
}
程序执行结果如图3所示。
说明:
①本例自定义了一个异常类MyException,如果输入的注册人数小于0,则人工抛出这个异常类的实例。
图3 例2执行结果
三、实验设计
(一)实验一
(1)实验目的
让学生掌握体会try-catch-finally语句的用法。
(2)实验要求
创建一个ThrowException类,该类有一个result() 方法,在result()方法内部有两个多项式A=4x-4,B=2*x*x-4*x*y+y*y,C=A/B,最后返回C的值。
要求:x和y的值作为该方法的形参,在计算C值以前,先判断A和B的值,当A或B等于零时抛出一个ArithmeticException异常,使用ArithmeticException捕获该异常,在创建ArithmeticException异常时须使用其带形参的构造函数,给形参赋值为“A 或 B =0”,使用getMessage()显示该字符串。当A、B都不等于零时抛出一个Exception异常,使用Exception捕获该异常,在创建Exception异常时也须使用其带形参的构造函数,给形参赋值为“program is ok!”,使用getMessage()显示该字符串。最后不管A、B是否等于零,都须显示”program is end”(注:使用finally)。
为这个类创建一个main()方法,生成两个20以内的整形随机数,调用result()方法,将这两个随机数赋给x和y,显示最后结果。
(3)实验效果展示
执行后的结果如图4所示。
图4 实验一效果展示
(二)实验二
(1)实验目的
让学生掌握体验自定义异常类的用法。
(2)实验要求
自定义类Triangle,其中有成员 x,y,z,作为三边长,构造方法triangle (a,b,c)分别给x,y,z赋值, getArea()方法用来求面积,showInfo()方法用来显示三角形信息(三个边长),这2个方法中当三条边不能构成一个三角形时要抛出自定义异常NotTriangleException,否则显示正确信息。在另外一个类中的主方法中构造一个Triangle对象(三边为命令行输入的三个浮点数),显示三角形信息和面积,要求捕获异常。
(3)实验效果展示
运行结果为图5所示。
图5实验二效果展示
(4)实验指导
①参照例2来定义NotTriangleException。
转载:https://blog.csdn.net/Mark7758/article/details/106130556