Java第8章异常处理与断言.ppt_第1页
Java第8章异常处理与断言.ppt_第2页
Java第8章异常处理与断言.ppt_第3页
Java第8章异常处理与断言.ppt_第4页
Java第8章异常处理与断言.ppt_第5页
已阅读5页,还剩70页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第8 8章 异常处理与断言 内容提要 异常是在程序运行过程中产生的使程序终 止正常运行的事件,是一种特殊的运行对 象。 本章要点 本章首先介绍什么是异常、异常的类型以 及如何处理异常,其中包括运行时异常和 非运行时异常、使用try-catch处理异常 、声明方法抛出异常、try-with- resources语句的使用以及创建自定义的 异常。 最后,简单介绍了有关断言的概念。 8.1 异常与异常类 8.1.1 异常的概念 8.1.2 Throwable类及其子类 8.1.1 异常的概念 所谓异常(exception)是在程序运行过 程中产生的使程序终止正常运行的错误对 象。如数组下标越界、整数除法中零作除 数、文件找不到等都可能使程序终止运行 。 为了理解异常的概念,首先看下面的程序 。 8.1.1 异常的概念 程序8.1 NullPointerDemo.java public class NullPointerDemo public static void main(String args) Circle circle = null; System.out.println(circle.area(); System.out.println(“Program finished.“); 该程序编译不会发生错误,可以生成NullPointer Demo.class字节码文件,但运行时结果如下: Exception in thread “main“ java.lang.NullPointerException at NullPointerDemo.main (NullPointerDemo.java:4) 8.1.1 异常的概念 该输出内容说明程序发生了异常,第一行给出 了异常名称,第二行给出了异常发生的位置。 Java语言规定当某个对象的引用为null时, 调用该对象的方法或使用对象时就会产生 NullPointerException异常。该程序中当调用 circle的area()方法时,运行时系统产生了一 个NullPointerException异常类对象并抛出, 运行时系统就在产生异常对象的方法中寻找处 理该异常对象的代码,若有则进入异常处理的 代码,若没有(如本程序),运行时系统继续 将异常对象抛给调用该方法的方法。 由于main() 方法是由JVM调用的,所以将异 常抛给了JVM,JVM在标准输出设备上输出异 常的名称。 8.1.1 异常的概念 再看下面一个程序,该程序试图从键盘上 输入一个字符,然后输出。 程序8.2 InputChar.java import java.io.*; public class InputChar public static void main(String args) System.out.print(“Input a char:“); char c=(char)System.in.read(); System.out.println(“c = “ + c); 8.1.1 异常的概念 当编译该程序时会出现下列编译错误: Unhandled exception type IOException 上述编译错误说明程序没有处理IOException 异常,该异常必须捕获或声明抛出,同时编译 器指出了需要捕获异常的位置。 出现上述编译错误的原因是,read()方法在 定义时声明抛出了IOException异常,因此程 序中若调用该方法必须声明抛出异常或捕获异 常。 8.1.2 Throwable类及其子类 Java语言的异常处理采用面向对象的方 法,为各种异常建立了类层次。Java异 常都是Throwable类的子类对象, Throwable类是Object类的直接子类, 它定义在java.lang包中。 Throwable类有两个子类 一个是Error类 另一个是Exception类, 这两个子类又分别有若干个子类。 8.1.2 Throwable类及其子类 1.Error类 Error类描述的是系统内部错误,这样的错 误很少出现。如果发生了这类错误,则除 了通知用户及终止程序外,几乎什么也不 能做,程序中一般不对这类错误处理。 Exception类 图8.1给出了Exception类及其常见子类的 层次结构。 Exception类的子类一般又可分为两种类 型:运行时异常和非运行时异常。 8.1.2 Throwable类及其子类 图8.2 RuntimeException类及其子类 图8.1 Exception类及其子类的层次 8.1.2 Throwable类及其子类 (1)运行时异常 RuntimeException类及其子类异常称为运行时 异常。常见的运行时异常如图8.2所示。运行时 异常是在程序运行时检测到的,可能发生在程 序的任何地方且数量较大,因此编译器不对运 行时异常(包括Error类的子类)处理,这种异 常又称为免检异常(unchecked exception) 。但程序运行时发生这种异常时运行时系统会 把异常对象交给默认的异常处理程序,在控制 台显示异常的内容及发生异常的位置。 程序8.1中的异常NullPointerException就是运 行时异常。 8.1.2 Throwable类及其子类 下面介绍几种常见的运行时异常。 NullPointerException 空指针异常,即当某 个对象的引用为null时调用该对象的方法或使 用对象时就会产生该异常,如: int a = null; a0 = 0; / 该语句发生异常 ArithmeticException 算术异常,在做整数 的除法或整数求余运算时可能产生的异常, 它是在除数为零时产生的异常。 int a = 5; int b = a / 0; / 该语句发生异常 注意:浮点数运算不会产生该类异常。如, 1.0/0.0的结果为Infinity。 8.1.2 Throwable类及其子类 ClassCastException 对象转换异常,Java 支持对象类型转换,若不符合转换的规定, 则产生类转换异常,例如: Object o = new Object(); String s = (String)o; / 该语句发生异常 ArrayIndexOutOfBoundsException 数组 下标越界异常,当引用数组元素的下标超出 范围时产生的异常,例如: int a = new int5; a5 = 10; / 该语句发生异常 因为定义的数组a的长度为5,不存在a5这 个元素,因此发生数组下标越界异常。 8.1.2 Throwable类及其子类 NumberFormatException 数字格式错误异 常。在将字符串转换为数值时,如果字符串 不能正确转换成数值则产生该异常,例如: double d = Double.parseDouble(“5m7.8“); / 该语句 发生异常 异常的原因是字符串“5m7.8“不能正确转换成 double型数据。 注意:尽管对运行时异常可以不处理,但 程序运行时产生这类异常,程序也不能正 常结束。为了保证程序正常运行,要么避 免产生运行时异常,要么对运行时异常进 行处理。 8.1.2 Throwable类及其子类 (2)非运行时异常 除RuntimeException类及其子类以外的 类称为非运行时异常,有时也称为必检异 常(checked exception)。对这类异 常,程序必须捕获或声明抛出,否则编译 不能通过。程序8.2中的异常IOException 就是非运行时异常。再比如,若试图使用 Java命令运行一个不存在的类,则会产 生Class NotFoundException异常,若调用了一 个不存在的方法,则会产生 NoSuchMethod Exception异常。 8.2 异常处理机制 8.2.1 异常的抛出与捕获 8.2.2 try-catch-finally语句 8.2.3 用catch捕获多个异常 8.2.4 声明方法抛出异常 8.2.5 用throw语句抛出异常 8.2.6 try-with-resources语句 8.2 异常处理机制 异常处理可分为下面几种: 使用try-catch-finally捕获并处理异常 ; 通过throws子句声明抛出异常; 用throw语句抛出异常; 使用try-with-resources管理资源。 8.2.1 异常的抛出与捕获 在Java程序中,异常都是在方法中产生的 。方法运行过程中如果产生了异常,在这 个方法中就生成一个代表该异常类的对象 ,并把它交给运行时系统,运行时系统寻 找相应的代码来处理这一异常。生成异常 对象并把它交给运行时系统的过程称为抛 出异常。运行时系统在方法的调用栈中查 找,从产生异常的方法开始进行回溯,直 到找到包含相应异常处理的方法为止,这 一过程称为捕获异常。 8.2.1 异常的抛出与捕获 方法调用与回溯如图8.3所示。 图8.3 方法调用与 回溯示意图 这里main()方法调用了methodA()方法, methodA()方法调用了methodB()方法, methodB()方法调用了methodC()方法。 假如在methodC()方法发生异常,运行 时系统首先在该方法中寻找处理异常的 代码,如果找不到,运行时系统将在方 法调用栈中回溯,把异常对象交给 methodB()方法,如果methodB()方法也 没有处理异常代码,将继续回溯,直到 找到处理异常的代码。最后,如果 main()方法中也没有处理异常的代码, 运行时系统将异常交给JVM,JVM将在 控制台 显示异常信息。 8.2.2 try-catch-finally语句 在Java程序中捕获并处理异常最常用的 方法是用try-catch-finally语句,该结构 的一般格式为: try / 需要处理的代码 catch (ExceptionType1 exceptionObject) / 异常处理代码 catch (ExceptionType2 exceptionObject) / 异常处理代码 finally / 最后处理代码 8.2.2 try-catch-finally语句 说明: (1)try块将程序中可能产生异常的代码段用大括 号括起来,该块内可能抛出一种或多种异常。 (2)catch块用来捕获异常,括号中指明捕获的 异常类型及异常引用名,类似于方法的参数, 它指明了catch语句所处理的异常。大括号中 是处理异常的代码。catch语句可以有多个, 用来处理不同类型的异常。 注意:若有多个catch块,异常类型的排列顺序必 须按照从特殊到一般的顺序,即子类异常放在前 面,超类异常放在后面,否则产生编译错误。 8.2.2 try-catch-finally语句 当try块中产生异常,运行时系统从上到下依次 检测异常对象与哪个catch块声明的异常类相 匹配,若找到匹配的或其父类异常,既进入相 应catch块处理异常,catch块执行完毕说明异 常得到处理。 (3)finally块是可选项。异常的产生往往会中断 应用程序的执行,而在异常产生前,可能有些 资源未被释放。有时无论程序是否发生异常, 都要执行一段代码,这时就可以通过finally块实 现。无论异常产生与否finally块都会被执行。即 使是使用了return语句,finally块也要被执行, 除非catch块中调用了System.exit()方法终止 程序的运行。 8.2.2 try-catch-finally语句 另外需要注意,一个try块必须有一个 catch块或finally块,catch块或finally 块也不能单独使用,必须与try块搭配使用 。 下面使用try-catch结构捕获并处理一个 ArithmeticException异常。 8.2.2 try-catch-finally语句 程序8.3 DivideDemo.java public class DivideDemo public static void main(String args) int a = 5; try int b = a / 0; System.out.println(“b = “ + b); catch(ArithmeticException e) e.printStackTrace(); System.out.println(“a = “ + a); 8.2.2 try-catch-finally语句 程序运行结果为: java.lang.ArithmeticException: / by zero at Demo.main(Demo.java:5) a = 5 从上述结果可以看到,程序运行中发生的 异常得到了处理,接下来程序继续运行。 程序中调用了异常对象的 printStackTrace()方法,它从控制台输出 异常栈跟踪。从栈跟踪中我么可以了解到 发生的异常类型和发生异常的源代码的行 号。 8.2.2 try-catch-finally语句 在异常类的根类Throwable中还定义了其 他方法,如下所示: public void printStackTrace():在标准错 误输出流上输出异常调用栈的轨迹。 public String getMessage():返回异常对 象的细节描述。 public String getLocalizedMessage():返 回异常对象的针对特定语言的细节描述。 public void printStackTrace(PrintStream s):在指定输出流上输出异常调用栈的轨迹。 8.2.2 try-catch-finally语句 public void printStackTrace(PrintWriter s) :在指定输出流上输出异常调用栈的轨迹。 public String toString():返回异常对象的简 短描述,是Object类中同名方法的覆盖。 这些方法被异常子类所继承,可以调用异 常对象的方法获得异常的有关信息,这可 使程序调试方便。有关其他方法的详细内 容,请参阅Java API文档。 下面是对程序8.2的修改,使用try-catch 结构捕获异常。 8.2.2 try-catch-finally语句 程序8.4 InputCharDemo.java import java.io.*; public class InputCharDemo public static void main(String args) System.out.print(“请输入一个字符:“); try char c = (char)System.in.read(); System.out.println(“c = “+c); catch(IOException e) e.printStackTrace(); 8.2.2 try-catch-finally语句 注意:catch块中的异常可以是超类异常 ,另外catch块中可以不写任何语句,只 要有一对大括号,系统就认为异常被处理 了,程序编译就不会出现错误,编译后程 序正常运行。catch块内的语句只有在真 的产生异常时才被执行。 下面程序涉及多个异常的捕获和处理。 8.2.2 try-catch-finally语句 程序8.5 MultiExceptionDemo.java 程序的输出如下: 无异常发生. 执行finally块:0 捕获到: java.lang.ArithmeticException :/ by zero 执行finally块:1 捕获到:java.lang.ArrayIndexOutOfBounds Exception: 4 执行finally块:2 8.2.3 用catch捕获多个异常 如前所述,一个try语句后面可以跟两个或 多个catch语句。虽然每个catch语句经 常提供自己的特有的代码序列,但是有时 捕获异常的两个或多个catch语句可能执 行相同的代码序列。现在可以使用JDK 7 提供的一个新功能,用一个catch语句处 理多个异常,而不必单独捕获每个异常类 型,这就减少了代码重复。 要在一个catch语句中处理多个异常,需 要使用“或”运算符(|)分隔多个异常 。下面的程序演示了捕获多个异常的方法 。 8.2.3 用catch捕获多个异常 程序8.6 MultiCatchDemo.java 8.2.3 用catch捕获多个异常 程序运行当尝试除以0时,将产生一个 ArithmeticException错误。当尝试越界 访问letter数组时,将产生一个 ArrayIndex OutOfException错误,两个异常被同一 个catch语句捕获。 注意,多重捕获的每个形参隐含地为final ,所以不能为其赋新值。 8.2.4 声明方法抛出异常 所有的异常都产生在方法(包括构造方法 )内部的语句。有时方法中产生的异常不 需要在该方法中处理,可能需要由该方法 的调用方法处理,这时可以在声明方法时 用throws子句声明抛出异常,将异常传递 给调用该方法的方法处理。 声明方法抛出异常的格式如下: returnType methodName(paramlist) throws ExceptionList / 方法体 8.2.4 声明方法抛出异常 按上述方式声明的方法,就可以对方法中 产生的异常不作处理,若方法内抛出了异 常,则调用该方法的方法必须捕获这些异 常或者再声明抛出。 上面的例子是在method ()方法中处理异 常,若不在该方法中处理异常,而由调用 该方法的main()方法处理,程序修改如下 。 8.2.4 声明方法抛出异常 程序8.7 ThrowsExceptionDemo.java 该程序的输出结果为: 8.2.4 声明方法抛出异常 注意:对于运行时异常可以不做处理,对 于非运行时异常必须使用try-catch结构 捕获或声明方法抛出异常。 前面讲到子类可以覆盖超类的方法,但若 超类的方法使用throws声明抛出了异常, 子类方法也可以使用throws声明异常。但 是要注意,子类方法抛出的异常必须是超 类方法抛出的异常或子异常。 8.2.4 声明方法抛出异常 class AA public void test() throws IOException System.out.println(“In AAs test()“); class BB extends AA public void test () throws FileNotFoundException / 允许 System.out.println(“In BBs test()“); class CC extends AA public void test () throws Exception / 错误 System.out.println(“In CCs test()“); 8.2.4 声明方法抛出异常 代码中BB类的test()方法是对AA类test() 方法的覆盖,它抛出了 FileNotFoundException异常,因为该异 常是 IOException 异常类的子类,这是 允许的。而在CC类的test ()中抛出了 Exception异常,该异常是IOException 异常类的父类,这是不允许的,不能通过 编译。 8.2.5 用throw语句抛出异常 到目前为止,处理的异常都是由程序产生 的,并由程序自动抛出,然而也可以创建 一个异常对象,然后用throw语句抛出, 或者将捕获到的异常对象用throw语句再 次抛出,throw语句的格式如下: throw throwableInstance; throwableInstance可以是用户创建的异 常对象,也可以是程序捕获到的异常对象 ,该实例必须是Throwable类或其子类的 实例,请看下面例子。 8.2.5 用throw语句抛出异常 程序8.9 ThrowExceptionDemo.java import java.io.IOException; public class ThrowExceptionDemo public static void method()throws IOException try throw new IOException(“file not found“); catch(IOException e) System.out.println(“caught inside method“); throw e; / 将捕获到的异常对象再次抛出 8.2.5 用throw语句抛出异常 public static void main(String args) try method(); catch(IOException e) System.out.println(“recaught:“ + e); 8.2.5 用throw语句抛出异常 程序的输出结果为: caught inside method recaught:java.io.IOException:file not found 上述程序在method()方法中try块中用new 创建一个异常对象并将其抛出,随后在 catch块中捕获到该异常,然后又再次将该 异常抛给main()方法,在main()方法的 catch块中捕获并处理了该异常。 请注意,该程序在method()方法需使用 throws声明方法抛出IOException异常,因 为该异常是非运行时异常,必须捕获或声明 抛出。在main()方法也必须使用try-catch捕 获和处理异常。 8.2.6 try-with-resources语句 Java程序中经常需要创建一些对象(如 I/O流、数据库连接),这些对象在使用完 后需要关闭。忘记关闭文件可能导致内存 泄露,并引起其他问题。在JDK 7之前,通 常使用finally语句来确保一定会调用 close()方法: try / 打开资源 catch(Exception e) finally / 关闭资源 8.2.6 try-with-resources语句 如果在调用close()方法也可能抛出异常, 那么也要处理这种异常。这样编写的程序 代码会变得冗长。例如,下面是打开一个 数据库连接的典型代码: Connection connection = null; try / 创建连接对象并执行操作 catch(Exception e) finally if(connection!=null) try connection.close(); catch(SQLException e) 8.2.6 try-with-resources语句 可以看到,为了关闭连接资源要在finally块 中写这些代码,如果在一个try块中打开多个 资源,代码会更长。JDK 7提供的自动关闭 资源的功能为管理资源(如文件流、数据库 连接等)提供了一种更加简便的方式。这种 功能是通过一种新的try语句实现的,叫try- with-resources,有时称为自动资源管理。 try-with-resources的主要好处是可以避免在 资源(如文件流)不需要时忘记将其关闭。 8.2.6 try-with-resources语句 try-with-resources语句的基本形式如下: try(resource-specification) / 使用资源 这里,resource-specification是声明并初 始化资源(如文件)的语句,它包含变量声 明,用被管理的对象的引用初始化该变量。 这里可以创建多个资源,用分号分隔即可。 当try块结束时,资源会自动释放。 8.2.6 try-with-resources语句 如果是文件,文件将被关闭,因此不需要 显式调用close()方法。try-with- resources语句也可以不包含catch语句 和finally语句。 8.2.6 try-with-resources语句 并非所有的资源都可以自动关闭。只有实 现了java.lang.AutoCloseable接口的那 些资源才可自动关闭。该接口是JDK 7新 增的,它定义了close()方法。 java.io.Closeable接口继承了 AutoCloseable接口。这两个接口被所有 的流类实现,包括FileInputStream和 FileOutputStream。因此,在使用流( 包括文件流)时,可以使用try-with- resources语句。 下面的例子演示了try-with-resources语 句的使用。 8.2.6 try-with-resources语句 程序8.10 TryWithResources.java 8.2.6 try-with-resources语句 程序定义了Door类和Window类,它们都 实现了java.langAutoClosable接口的 close()方法。此外,还定义了open()方 法,在open()方法中使用throw抛出了异 常。 在程序的main()方法中使用了try-with- resources语句创建了door对象和 window对象,这两个对象就是可自动关 闭的资源。在调用door.open()方法时抛 出异常,程序控制转到异常处理代码,在 此之前,程序调用两个资源的close()方法 将door和window关闭,然后才处理异常 。 8.3 自定义异常类 尽管Java已经预定义了许多异常类,但 有时还需要定义自己的异常,这时只需要 继承Exception类或其子类就可以了。 程序8.11 MyException.java public class MyException extends Exception private int num; MyException(int a) num = a; public String toString() return “MyException“+num+“; 8.3 自定义异常类 下面的程序中使用了自定义的类 MyException 程序8.12 ExceptionExample.java public class ExceptionExample static void makeexcept(int a) throws MyException System.out.println(“called makeexcept(“+a+“)“); if(a = 0) throw new MyException(a); System.out.println(“exit without exception“); 8.3 自定义异常类 public static void main(String args) try makeexcept(5); makeexcept(0); catch(MyException e) System.out.println(“caught:“+e); 8.3 自定义异常类 程序的输出为: called makeexception(5) exit without exception called makeexception(0) caught:MyException0 8.4 断言机制 断言是Java 1.4版新增的一个特性,并在 该版本中增加了一个关键字assert。断言 功能可以被看成是异常处理的高级形式。 所谓断言(assertion)是一个Java语句 ,其中指定一个布尔表达式,程序员认为 在程序执行时该表达式的值应该为true。 系统通过计算该布尔表达式执行断言,若 该表达式为false系统会报告一个错误。通 过验证断言是true,能够使程序员确信程 序的正确性。 8.4.1 断言概述 断言是通过assert关键字来声明的,断言 的使用有两种格式: assert expression ; assert expression : detailMessage ; 在上述语句中,expression为布尔表达式 ,detailMessage是基本数据类型或 Object类型的值。当程序执行到断言语 句时,首先计算expression的值,如果其 值为true,什么也不做,如果其值为false ,抛出AssertionError异常。 8.4.1 断言概述 AssertionError类有一个默认的构造方法和 7个重载的构造方法,它们有一个参数,类 型分别为:int、long、float、double、 boolean、char和Object。对于第一种断 言语句没有详细信息,Java使用 AssertionError类默认的构造方法。对于第 二种带有一个详细信息的断言语句,Java 使用AssertionError类的与消息的数据类型 匹配的构造方法。由于AssertionError类是 Error类的子类,当断言失败时( expression的值为false),程序在控制台 显示一条消息并终止程序的执行。 下面是一个使用断言的例子。 8.4.1 断言概述 程序8.13 AssertionDemo.java public class AssertionDemo public static void main(Stringargs) int i; int sum = 0; for(i = 0; i 10 case 2: ; case 3: ; default: assert false : “x value is invalid:“ + x; 8.4.3 何时使用断言 2. 检查前置条件(precondition) 在private修饰的方法前检查输入参数是否有效 。对于一些private方法,如果要求输入满足一 定的条件,可以在方法的开始处

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论