一.单元概述
程序设计中如果没有对异常进行考虑并处理,就会大大降低程序的健壮性。Java语言具有异常处理机制,通过本章的学习应该能够了解Java语言的异常处理机制,掌握异常的概念,掌握异常的捕获、声明和抛出的方法,掌握如何创建自定义异常。
二,教学重点与难点
重点:
(1) 异常的概念
(2) 检查性异常
(3) 非检查性异常
(4) try、catch、finally语句
(5) throw、throws关键字
(6) 自定义异常类
难点:
(1) 自定义异常类
(2)方法调用的堆栈

8.1异常简介

我们在进行程序设计和运行过程中,发生错误是不可避免的。尽管Java语言的设计便于写出整洁、安全的代码,并且程序员也会尽量地去避免错误的发生。但错误的存在仍然不可避免,有时甚至会使程序被迫终止。为此,Java提供了异常处理机制来帮助程序员处理可能出现的错误,保证了程序的健壮性。本章将向读者介绍异常处理的概念以及如何处理异常,如何创建自定义异常类等知识。
异常是程序中的一些错误,但并不是所有的错误都是异常,并且有些错误是可以避免的。我们思考一下编写Java程序时可能会遇到哪些异常或错误问题?我们把编写、运行Java程序时会遇到的错误问题分为三种:语法错误、逻辑错误和运行时错误。

8.1.1语法错误

这种错误在编译程序时就会发现,比如关键字拼写错误,变量定义时违反了命名规则等。相信读者在之前的实践练习中经常会遇到这样的问题。我们先来阅读下面的一段代码,看看你能找出几个语法错误?

  1. 8.1 测试语法错误。
  2. public class Example8_1{
  3. String name
  4. public void test(){
  5. Name = "Test_Java";
  6. }
  7. }
  8. 细心的读者会发现,上面的一段代码中有两处语法错误:
  9. public class Example8_1{
  10. String name
  11. public void test(){
  12. Name = "Test_Java";
  13. }
  14. }

语法错误也就是编码不符合Java 语法规范,在编写过程中或编译时就可以被发现,导致编译无法通过。编译器在发现语法错误时就会显示错误信息,编译过程也就此终止。上面代码例子经过编译后就会得到如下图8.1所示的错误信息。
08.异常处理 - 图1
经过编译后的程序是没有语法错误的,也就是说我们可以在编译程序前消灭语法错误。

8.1.2逻辑错误

这种错误很少在编写程序时被轻易地发现,因为这种错误不是语法错误,所以编译器无法提示相应的错误信息。我们来阅读下面的一段代码:

  1. 8.2 测试逻辑错误,求1~100之和。
  2. public class Example8_2{
  3. public static void main(String args[]){
  4. int sum = 0;
  5. for(int i=0;i<100;i++)
  6. sum += i;
  7. System.out.println("1至100之和是:"+sum);
  8. }
  9. }
  10. 我们知道1100之和是5050,但是编译并运行上面的程序后,得到的结论却是4950.为何少了100呢?我们来分析一下这个程序:
  11. public class Example8_2{
  12. public static void main(String args[]){
  13. int sum = 0;
  14. for(int i=0;i<100;i++)
  15. sum += i;
  16. System.out.println("1至100之和是:"+sum);
  17. }
  18. }

原来是循环条件写错了,让循环体少运行了一遍,因此少加了100。我们把循环条件改为:
for(int i=0;i<=100;i++)
修改后再编译运行,结果就正确了。
逻辑错误,也就是程序设计中常说的Bug,一般存在逻辑错误的程序都是可以顺利的被编译器编译通过的,并且也能够顺利运行,但是得出的结果却并不是我们所希望的。这种错误也是编程新手会经常出现的错误。我们可以通过不断地实践,积累更多的编程经验,来减少这样的错误发生。

8.1.3运行时错误

有些程序虽然编译通过了,但是在运行过程中却出现了问题而导致程序异常终止,出现了运行时的错误。异常就是运行期间出现的错误,而不是编译时的语法错误和逻辑错误。
例如,打开一个不存在的文件、网络连接中断和操作数组越界等,如下图8.2所示。
08.异常处理 - 图2

  1. 我们来编译、运行下面的一段代码:
  2. 8.3 测试运行时错误。
  3. public class Example8_3{
  4. public static void main(String args[]){
  5. int a = 0;
  6. int b = 100/a;
  7. System.out.println("除法结束。");
  8. }
  9. }
  10. 程序的运行结果如下图8.3所示。

08.异常处理 - 图3
在结果中显示出,在程序运行时出现了错误,程序终止了运行,因此第5行的代码没有执行输出。根据异常信息显示,该异常叫“ArithmeticException”,异常的消息是“用零做除数(/ by zero)”,出现异常的位置是第4行。像ArithmeticException这种错误就属于Java的异常,也就是说Java中的异常是一种运行时的错误,会导致程序异常终止,同时显示异常信息。

  1. 8.4 数组下标越界。
  2. public class ArrayException {
  3. public static void main(String args[]) {
  4. int i = 0;
  5. String greetings[]={"Hello World","Hello Dingdang","Hello Kitty" };
  6. while (i < 4) {
  7. System.out.println(greetings[i]);
  8. i++;
  9. }
  10. }
  11. }
  12. 程序运行结果如下图8.4所示。

08.异常处理 - 图4
在结果中显示出,在程序运行时出现了错误,程序终止了运行。根据异常信息显示,该异常叫“java.lang.ArrayIndexOutOfBoundsException”,异常的消息是“数组下标越界”, 数组下标越界这样的错误也是Java异常中的一种,出现异常的位置是第6行,出现此异常的原因是数组中共三个元素,下标分别是0、1、2,而循环中代码会访问数组中下标为3的元素,所以导致出现异常。

8.2异常类的继承关系

8.2.1异常的继承树

异常是程序执行的时候所遇到的非正常情况或意外行为。一般情况下,如数组下标越界、算法溢出、除数为零等都可以引发异常发生。所有异常类型都是Throwable的子类,Throwable处在异常类层次结构的顶层。它是所有异常类的父类。它有两个子类,即Error 和Exception,它们分别用来处理两组异常,如下图8.5所示。
08.异常处理 - 图5
异常类的层次结构如下图8.6所示。
08.异常处理 - 图6
Object 类的直接子类Throwable描述了所有被虚拟机抛出的非正常状况。一般情况下很少用Throwable,而是使用它的两个子类Error、Exception。
Error类特指应用程序在运行期间发生的严重错误。如:虚拟机内存用尽、堆栈溢出等等。一般情况下这种错误都是灾难性的,所以没有必要使用异常处理机制处理Error。
Exception类有几十个子类,描述了不同类型的异常,其中:

  1. 以RuntimeException为代表的一些类,称为非检查性异常(unchecked Exception),用来表示设计或实现方面的问题,如数组下标越界、除数为零等问题。因为设计和实现正确的程序不会引发这类异常,所以Java并不强制提前处理它。发生这类异常时,运行时环境会输出一条信息,提示用户如何去修正错误。我们可以利用Java提供的异常处理机制,对可能出现的异常进行预见性处理,以保证程序的顺利运行而不是异常终止。
  2. 以IOException为代表的一些类为检查性异常(checked Exception)。所谓的检查和非检查是指编译器在编译时是否检查。如果代码中存在检查性异常,必须进行异常处理,否则编译时不能通过;而非检查性异常编译时不进行检查,到运行时才会显现。因为用户的疏忽很可能导致这类问题在程序运行时发生,比如用户键入的内容不完整等,所以Java鼓励程序员提前处理它们。

    8.2.2 异常类型

    异常按照处理方式可以分为如下两种类型:
    1.检查性异常(checked exception)
    若系统运行时可能产生该类异常,则必须写出相应的处理代码,否则无法通过编译。
    2.非检查性异常(unchecked exception)
    非检查性异常也称之为RuntimeException,若系统运行时可能产生该类异常,则不必在程序中声明对该类异常的处理,就可以编译执行。

    1. 8.5 异常的类型
    2. import java.io.FileInputStream;
    3. import java.io.FileNotFoundException;
    4. public class CheckException {
    5. public static void main(String args[]) {
    6. // 检查性异常,需要在程序中进行处理
    7. FileInputStream fin = new FileInputStream("d://a.txt");
    8. System.out.println("这里抛出的是一个检查性的错误");
    9. // 非检查性异常,可以不在程序中进行处理
    10. String str[] = { "bananan", "apple", "pear" };
    11. int i = 5;
    12. System.out.println(str[5]);
    13. }
    14. }

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

    8.2.3 异常是如何产生的

    Java语言是一种面向对象的编程语言,因此,在Java语言中异常也是作为某种异常类的实例的形式出现的。当在某一方法中发生错误时,运行环境就创建一个异常对象,并且把它传递给系统,我们可以利用Java提供的异常处理机制,捕获这个异常对象,并且可以脱离主程序流程进行处理。我们不但可以捕获系统创建的异常实例,还可以创建自己的异常实例,并可以主动抛出异常实例,达到控制程序执行顺序的作用。对于异常的捕获、抛出和创建,将在后面详细讲解。

    8.3异常处理机制

    8.3.1异常处理过程

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

    8.3.2 使用try/catch 字句

    使用Java提供的异常捕获结构,我们就可以捕获到可能出现的异常,避免程序异常终止。Java的异常捕获结构由try/catch/finally子句组成,我们先来讲讲try/catch子句。try/catch的用法如下图8.8所示。
    08.异常处理 - 图10

    1. 8.6 捕获异常实例,使程序可以成功运行。
    2. public class Exception_Sample_1 {
    3. public static void main(String args[]) {
    4. int num[] = new int[5];
    5. int i = 0;
    6. int j = 2;
    7. try {
    8. while (i < 6) {
    9. j = j - 1;
    10. num[i] = i;
    11. System.out.print(num[i] + "/" + j + "=");
    12. System.out.println(num[i] / j);
    13. i++;
    14. }
    15. } catch (Exception e2) {
    16. System.out.println("除数不能是0");
    17. }
    18. }
    19. }
    20. 运行结果结果如下
    21. 0/1=0
    22. 1/0=除数不能是0

    运行例题8.6,没有显示异常信息,可以顺利运行。程序运行时由catch子句捕获到这个异常实例,开始执行catch子句中的代码,并且不会回到try子句中了。也就是说在try子句中,在发生异常的语句后面的代码将不再被执行,而是跳转到相应的catch子句中继续执行。
    一般情况下我们如下使用try/catch块:
    try{
    我们把可能会出现异常的语句放在这里。
    在异常发生时,会由catch块捕获到相应的异常实例。
    }catch(XXXException e){
    e就是捕获到的异常实例,它由系统自动创建,里面包含了异常的信息。
    XXXException就是Exception异常的任意子类。
    /我们在这里可以对出现异常的情况进行处理,比如输出错误信息。
    }
    注意:
    1.catch块,是用来捕获并处理try块抛出的异常的代码块。没有try块,catch块不能单独存在。我们可以有多个catch块,以捕获不同类型的异常
    2.如果程序抛出多个不同类型的异常,我们需要多个catch()语句来处理。
    3.和特殊异常类相关联的catch()块必须写在和普通异常类相关联的catch()之前。
    4.try{…}和catch( ){…}之间不可以添加任何代码

    8.3.3 多重catch子句

    有时一段程序可能会产生多种异常,这时,我们就可以设置多个catch子句来进行捕获,每个子句都来捕获不同类型的异常。当有异常发生时,每个catch子句依次被匹配检查,当发生的异常是catch子句所声明的类型或其子类型时,程序执行流程就转入到该catch子句中继续执行,其余的catch子句将不再检查或执行。多catch子句的用法如下图8.10所示。
    08.异常处理 - 图11
    每次try块有异常抛出,系统会试着从上到下往每个catch块中传参,直到遇到一个类型匹配的catch块为止。
    如上示例中最后一个catch块中的形参为Exception类型,它是所有异常类的父类,任何异常都可以传参到该块中,该块可以处理任何类型的异常。因此,这个catch块只能放到最后面,否则所有的异常都被它处理了,其他的catch块就不能起作用了。
    如果编写过程中我们违背了这一点,会产生编译错误:
    exception java.io.ArrayOutOfBoundsException has already bean caught
    一般一个catch块中是专门处理异常的代码,在程序中这里还可以是记录日志的语句,当发生异常时记录该日志,无异常时将不会记录。

    1. 8.7 使用多重catch子句,捕获不同的异常。
    2. import java.io.IOException;
    3. public class Exception_sample_2 {
    4. public static void main(String args[]) {
    5. int num[] = new int[5];
    6. int i = 0;
    7. int j = 3;// j=8
    8. try {
    9. while (i < 6) {
    10. j = j - 1;
    11. num[i] = i;
    12. System.out.print(num[i] + "/" + j + "=");
    13. System.out.println(num[i] / j);
    14. i++;
    15. }
    16. } catch (ArrayIndexOutOfBoundsException e) {
    17. System.out.println("数组越界异常");
    18. } catch (RuntimeException e) {
    19. System.out.println("数组越界异常");
    20. }
    21. }
    22. }
    23. 变量j3时的运行结果
    24. 0/2=0
    25. 1/1=1
    26. 2/0=运行时异常
    27. 变量j8时的运行结果如下
    28. 0/7=0
    29. 1/6=0
    30. 2/5=0
    31. 3/4=0
    32. 4/3=1
    33. 数组越界异常

    上面程序运行时,当j的值是3时,出现“被0除”的异常,因此会越过第一个catch子句,执行第二个catch;当j的值为8时,会在访问参数数组时,发生ArrayIndexOutOfBoundsException异常,因此执行第1个catch子句。
    思考:

  3. 如果有一个异常类型及其子类型都在各自的catch块中,那么应该把哪个catch块放在前面?

  4. 如果有捕获Exception异常类的catch块,那么这个catch块应该放在其他catch块的前面还是最后面?

    8.3.4finally子句

    从前面的内容中,我们了解到,当try子句中的某行代码发生异常时,会终止程序的运行,跳转到catch子句来执行。但是有些时候,为了程序的健壮性和完整性,无论有没有异常发生都要执行某些代码,比如说打开了文件的I/O流需要关闭,建立的数据库连接需要释放等操作。finally子句就是为了完成必须执行的代码而设计的。
    finally语句放在try …catch语句后,fianlly语句中的代码块不管异常是否被捕获总是要执行,具体运行情况如下图8.13所示。
    08.异常处理 - 图12
    通常在finally语句中可以进行资源的释放操作,如:关闭打开文件、删除临时文件。
    对应finally代码中的语句,即使try代码块和catch代码块中使用了return语句退出当前方法或应用break跳出某个循环,但程序中的finally代码块都会执行。
    当try或catch代码块中执行了System.exit(0)时,finally代码块中的内容不被执行,finally的运行情况如下图8.14所示。
    08.异常处理 - 图13
    1. 8.8 使用finally子句。
    2. public class Exception_sample_3 {
    3. public static void main(String args[]) {
    4. int num[] = new int[5];
    5. int i = 0;
    6. int j = 3;
    7. try {
    8. while (i < 3) {
    9. j = j - 1;
    10. num[i] = i;
    11. System.out.println();
    12. System.out.print(num[i] + "/" + j + "=");
    13. System.out.println(num[i] / j);
    14. i++;
    15. }
    16. } catch (ArrayIndexOutOfBoundsException e1) {
    17. System.out.println("数组下标越界");
    18. } catch (Exception e2) {
    19. System.out.println("被0除");
    20. // return;
    21. // System.exit(0);
    22. } finally {
    23. System.out.println("while 执行" + (i + 1) + "次");
    24. }
    25. System.out.println("程序结束");
    26. }
    27. }
    28. 程序运行结果如下
    29. 0/2=0
    30. 1/1=1
    31. 2/0=被0
    32. while 执行3
    33. 程序结束
    由上面两种运行结果来看,无论有无异常发生或者发生了何种异常,最后都会执行finally子句。

    8.3.5throws关键字

    如果一个方法中发生了异常而没有捕获它,那么必须在这个方法头进行声明,由方法的调用者来进行处理。声明异常使用throws关键字。我们来看看下面的代码。
    如果一个方法中的语句执行时可能发成某种异常,但是并不能确定如何处理,则可以在程序所在的方法声明后,使用throws关键字抛出异常
    位置:方法参数列表的后面
    throws关键字后面,可以跟多个异常,中间用逗号分割
    throws关键字抛出的异常,由调用该方法的方法处理。throws的用法如下图8.16所示。
    08.异常处理 - 图14
    用throws声明方法抛出异常,不进行处理。谁调用谁负责处理。覆盖方法抛出异常时,可以抛出与被覆盖方法相同的异常或者被覆盖方法异常的子类异常。throws在程序中的用法如下图8.17所示。
    08.异常处理 - 图15
    例: 使用throws子句。 ```java

public class Exception_Sample_4 { public static void devide(int j) throws ArrayIndexOutOfBoundsException, RuntimeException { int[] num = new int[5]; int i = 0; while (i < 6) { j = j - 1; num[i] = i; System.out.print(num[i] + “/“ + j + “=”); System.out.println(num[i] / j); i++; } } public static void main(String args[]) { System.out.println(“ok”); try { devide(3); } catch (ArrayIndexOutOfBoundsException e) { System.out.println(); } catch (RuntimeException e) { System.out.println(); } } } 程序运行结果如下 ok 0/2=0 1/1=1 2/0=

  1. ```
  2. 例8.10 在方法头声明异常。
  3. public class Example_throws {
  4. public void test1(int i) throws ArithmeticException {
  5. System.out.println(100 / i);
  6. }
  7. public void test2() {
  8. try {
  9. test1(0);
  10. } catch (ArithmeticException e1) {
  11. System.out.println(e1.toString());
  12. }
  13. }
  14. }

在上面的例题中,方法test1()是被调用者,方法test2()是调用者,在方法test1()中可能会发生“除数为0”的异常,但是并没有对其捕获处理,而是在方法头中声明,这样调用者test2()就必须对这个可能的异常进行处理,要么捕获要么继续声明。
如上所述,我们不建议一味地使用声明异常,在最终的调用者里我们还是应该对异常进行捕获处理,否则就和没有处理异常是一样的效果了。
在Java的语法中,如果一个方法中调用了已经声明检查性异常的另一个方法,那么Java编译器会强制调用者必须处理被声明的异常,要么捕获要么继续声明。

8.3.6throw 语句

我们在上面的代码例子中,都是在处理系统所发生的异常,其实Java为我们提供了自己产生异常的机会—-throw抛出异常。要区分声明异常throws和抛出异常throw两个不同的关键字。抛出异常的语法如下:
throw 异常实例;
异常是通过关键字 throw 抛出,程序可以用throw语句引发明确的异常。如下图8.19所示。
08.异常处理 - 图16

8.4 方法调用堆栈

后进先出:方法A调用方法B的时候,只有方法B先完成后,方法A才完成。先执行的方法总是后完成,后执行的方法先完成,类似于数据结构中的堆栈--后进先出,我们称之为方法调用堆栈。
如示例,仅有一条语句抛出异常,会导致所有的方法都不能正常结束。如果不想出现这样的情况,我们就要使用java的异常处理机制-抓抛模型,方法调用的堆栈如下图8.21所示。
08.异常处理 - 图17
方法调用的过程如下图8.22所示。
08.异常处理 - 图18
【总结与提示】

  1. catch子句的捕获范围,限制于与其匹配的try子句,不能捕获其他try子句中的异常;
  2. 不能单独使用try子句,它必须和catch子句或finally子句结合使用,catch子句可以设置多个,finally子句只能有一个;
  3. 有多重catch子句时,只能执行那个捕获到异常的子句,其余的catch子句不能执行;
  4. try/catch/finally三个子句中变量的作用域独立而不能相互访问。如果要在三个子句中都可以访问,则需要将变量定义到这些子句的外面;
  5. 不要写过大的try子句,一个try子句中尽量不要存在太多的异常;
  6. 一个方法中如果有发生异常的可能,则可以进行捕获处理,也可以声明由调用者来处理;
  7. throw语句后不允许有其他语句,因为这些语句没有机会执行;
  8. 不能利用异常处理来进行程序的分支处理,它只是处理非正常情况的一种机制。

    8.5课后作业

    (一) 选择题
    1) 对于try和catch子句的排列方式,下面哪一项是正确的?
    A.子类异常在前,父类异常在后
    B.父类异常在前,子类异常在后
    C.只能有子类异常
    D.父类异常和子类异常不能出现在同一个try程序段内
    2) 下列错误不属于Error的是?
    A.动态链接失败
    B.虚拟机错误
    C.线程死锁
    D.被零除
    3) 下列那种异常不属于免检异常 ?
    A.Error
    B.RuntimeException
    C.NullPointerException
    D.IOException
    4) 有如下代码,选择正确执行结果 ?

    1. import java.io.*;
    2. public class TestTryCatch {
    3. public static void main(String args[]) {
    4. try {
    5. ma(1);
    6. System.out.println("No Exception");
    7. } catch (EOFException ex1) {
    8. System.out.println("ex1");
    9. } catch (IOException ex2) {
    10. System.out.println("ex2");
    11. }
    12. }
    13. public static void ma(int n) throws Exception {
    14. if (n == 1) {
    15. throw new IOException();
    16. } else if (n == 2) {
    17. throw new EOFException();
    18. }
    19. }
    20. }

    A.编译不通过
    B.编译通过,输出No Exception
    C.编译通过,输出ex1
    D.编译通过,输出ex2
    5) 关于异常的定义,下面描述正确的是?
    A.程序编译错误
    B.程序语法错误
    C.程序自定义的异常事件
    D.程序编译或运行中所发生的可预料或者不可预料的异常事件,它会引起程序的中断,影响程序的正常运行
    6) 下列异常处理语句编写正确的是?
    A. try {System.out.println(2 / 0);}
    B.try {System.out.println(2 / 0);}catch (Exception e) {System.out.println(e.getMessage());}
    C.try {System.out.println(2 / 0);}catch (e) {System.out.println(e.getMessage());}
    D.try {System.out.println(2 / 0);}catch{System.out.println(e.getMessage());}
    7) 抛出异常时使用下列哪个关键字 ?
    A.throw
    B.catch
    C.finally
    D.throws
    8) 声明异常时使用下列哪个关键字 ?
    A.throw
    B.catch
    C.finally
    D.throws
    9) 当方法产生该方法无法确定该如何处理的异常时,应该如何处理?
    A.声明异常
    B.捕获异常
    C.抛出异常
    D.嵌套异常
    10) 以下代码的执行结果是:
    image.png
    A. finished
    B. Exception
    C. 编译错误
    D. Arithmetic Exception
    (二)简答题

  9. 写程序结果

    1. public class ExceptionDemo {
    2. public static void mySqrt(int a) throws Exception {
    3. if (a < 0)
    4. throw new Exception();
    5. System.out.println(Math.sqrt(a));
    6. }
    7. public static void main(String args[]) {
    8. try {
    9. System.out.println("begin");
    10. mySqrt(25);
    11. mySqrt(-5);
    12. } catch (Exception e) {
    13. System.out.println("Caught e");
    14. }
    15. }
    16. }

    2) 写出程序的运行结果。

    1. public class Test {
    2. public static void main(String args[]) {
    3. System.out.println(ma());
    4. }
    5. public static int ma() {
    6. int b = 10;
    7. try {
    8. int n = 100;
    9. return n / b;
    10. } catch (Exception e) {
    11. return 10;
    12. } finally {
    13. return 100;
    14. }
    15. }
    16. }

    3) 写程序结果

    1. try {
    2. System.out.println("begin");
    3. int i = 0;
    4. int y = 2 / i;
    5. System.out.println(y);
    6. System.out.println("end");
    7. } catch (Exception e) {
    8. System.out.println("exception");
    9. } finally {
    10. System.out.println("exit");
    11. }

    (三)编程题
    1) 创建类Student,属性有平时成绩,期末成绩;方法有计算总成绩的方法getScore(),(用平时成绩加上期末成绩的1/2,来计算总成绩);在上面的方法中,在方法头声明异常Exception,如果总成绩小于60分,则抛出异常Exception。创建测试类,实例化Student对象,给平时成绩和期末成绩赋值,然后调用getScore()方法来计算总成绩,注意异常的捕获。

2) 自定义异常类BNEException。编写帐户类Account,属性包括帐号和余额;方法包括存钱方法save(double d),增加收入后,打印输出余额;取钱方法pay(double d),减少收入后,打印输出余额,当余额小于0时,抛出余额不足的异常BNEException。编写测试类,创建Account的对象,并且调用该对象的save和pay方法。

3) 编写应用程序,从命令行传入两个整型数作为除数和被除数。要求程序中捕获NumberFormatException 异常和ArithmeticException 异常,而且无论在哪种情况下,“总是被执行”这句话都会在控制台输出。

在命令行输入不同的参数时能输出如下各种结果:

  • 在命令行输入 java A

总是被执行
Exception in thread “main” java.lang.ArrayIndexOutofBoundsException at A.main(A.java:7)

  • 在命令行输入 java A 1 2

0
总是被执行

  • 在命令行输入 java A 1 3a

java.lang.NumberFormatException: 3a at java.lang.Integer.parseInt(Integer.java:435) at java.lang.Integer.parseInt(Integer.java:476) at A.main(A.java:8)
总是被执行

  • 在命令行输入 java A 1 0

java.lang.ArithmeticException: / by zero at A.main(A.java:9)
总是被执行

4) 编写一个检查给定的数字的数据类型是否为byte的程序,如果此数字超出byte数据类型表示的数的范围,则引发用户自定义的异常ByteSizeException,并显示相应的错误信息
•步骤1:创建用户自定义异常类ByteSizeException
•步骤2:在main方法中编写逻辑代码
•步骤3:运行并测试
•效果如图:
08.异常处理 - 图20

5) 编写一个方法,比较两个字符串。假如其中一个字符串为空,会产生NullPointerException异常,在方法声明中通告该异常,并在适当时候触发异常,然后编写一个程序捕获该异常。