java的异常处理

1.异常的概念:

所谓异常(exception)是在程序运行过程中产生的使程序终止正常运行的错误对象,如数组下标越界、整数除法中零作除数、文件找不到等都可能使程序终止运行。

Java语言规定当某个对象的引用为null时,调用该对象的方法或使用对象时就会产生NullPointerException异常。

2.异常类

Java语言的异常处理采用面向对象的方法,定义了多种异常类。Java异常类都是Throwable类的子类,是Object类的直接子类,定义在java.lang包中。Throwable类有两个子类,一个是Error类,另一个是Exception类,这两个子类又分别有若干个子类。

2.1非检查异常

非检查异常(unchecked exception)是RuntimeException类及其子类异常,也称为运行时异常。常见的非检查异常如图12-2所示。

非检查异常是在程序运行时检测到的,可能发生在程序的任何地方且数量较大,因此编译器不对非检查异常(包括Error类的子类)处理,这种异常又称免检异常。

尽管编译器不对非检查异常处理,但程序运行时产生这类异常,程序也不能正常结束。为了保证程序正常运行,要么避免产生非检查异常,要么对非检查异常进行处理。

2.2检查异常

检查异常(checked exception)是除RuntimeException类及其子类以外的异常类,有时也称为必检异常。对这类异常,程序必须捕获或声明抛出,否则编译不能通过。程序12.1中的read()方法声明抛出IOException异常就是必检异常。例如,若试图使用Java命令运行一个不存在的类,则会产生ClassNotFoundException异常,若调用了一个不存在的方法,则会产生NoSuchMethodException异常。

3.异常处理

异常处理可分为下面几种:使用try-catch-finally捕获并处理异常;通过throws子句声明抛出异常;用throw语句抛出异常;使用try-with-resources管理资源。

3.1异常的抛出与捕获

异常都是在方法中产生的。方法运行过程中如果产生了异常,在这个方法中就生成一个代表该异常类的对象,并把它交给系统,运行时系统寻找相应的代码来处理该异常。这个过程称为抛出异常。运行时系统在方法的调用栈中查找,从产生异常的方法开始进行回溯,直到找到包含相应异常处理的方法为止,这一过程称为捕获异常。

3.2try-catch-finally语句

当try块中产生异常,运行时系统从上到下依次检测异常对象与哪个catch块声明的异常类相匹配,若找到匹配的或其父类异常,就进入相应catch块处理异常,catch块执行完毕说明异常得到处理。

(3)finally块是可选项。异常的产生往往会中断应用程序的执行,而在异常产生前,可能有些资源未被释放。有时无论程序是否发生异常,都要执行一段代码,这时就可以通过finally块实现。无论异常产生与否finally块都会被执行。即使是使用了return语句,finally块也要被执行,除非catch块中调用了System.exit()方法终止程序的运行。

另外需要注意,一个try块必须有一个catch块或finally块,catch块或finally块也不能单独使用,必须与try块搭配使用。

在异常类的根类Throwable中还定义了其他方法,如下所示:

public void printStackTrace():在标准错误输出流上输出异常调用栈的轨迹。

public String getMessage():返回异常对象的细节描述。

public void printStackTrace(PrintWriter s):在指定输出流上输出异常调用栈的轨迹。

public String toString():返回异常对象的简短描述,是Object类中同名方法的覆盖。这些方法被异常子类所继承,可以调用异常对象的方法获得异常的有关信息,方便程序调试。有关其他方法的详细内容,请参阅Java API文档。

3.3用catch捕获多个异常

如前所述,一个try语句后面可以跟两个或多个catch语句。虽然每个catch语句经常提供自己特有的代码序列,但是有时捕获异常的两个或多个catch语句可能执行相同的代码序列。现在可以使用JDK 7提供的一个新功能,用一个catch语句处理多个异常,而不必单独捕获每个异常类型,减少了代码重复。

程序运行当尝试除以0时,将产生一个ArithmeticException错误。当尝试越界访问letter数组时,将产生一个ArrayIndexOutOfException错误,两个异常被同一个catch语句捕获。注意,多重捕获的每个形参隐含地为final,所以不能为其赋新值。

3.4声明方法抛出异常

所有的异常都产生在方法(包括构造方法)内部的语句。有时方法中产生的异常不需要在该方法中处理,可能需要由该方法的调用方法处理,这时可以在声明方法时用throws子句声明抛出异常,将异常传递给调用该方法的方法处理。

注意:对于运行时异常可以不做处理,对于非运行时异常必须使用try-catch结构捕获或声明方法抛出异常。

3.5用throw语句抛出异常

3.7try-with-resources语句

Java程序中经常需要创建一些对象(如I/O流、数据库连接),这些对象在使用后需要关闭。忘记关闭文件可能导致内存泄露,并引起其他问题。在JDK 7之前,通常使用finally语句来确保一定会调用close()方法。

可以看到,为了关闭连接资源要在finally块中写这些代码,如果在一个try块中打开多个资源,代码会更长。JDK 7提供的自动关闭资源的功能为管理资源(如文件流、数据库连接等)提供了一种更加简便的方式。这种功能是通过一种新的try语句实现的,称为try-with-resources,有时也称为自动资源管理。try-with-resources的主要优点是可以避免在资源(如文件流)不需要时忘记将其关闭。

4.自定义异常类:

尽管Java已经预定义了许多异常类,但有时还需要定义自己的异常。编写自定义异常类实际上是继承一个API标准异常类,用新定义的异常处理信息覆盖原有信息的过程。

5.断言

断言是Java 1.4版新增的一个特性,并在该版本中增加了一个关键字assert。断言功能可以被看成是异常处理的高级形式。所谓断言(assertion)是一个Java语句,其中指定一个布尔表达式,程序员认为在程序执行时该表达式的值应该为true。系统通过计算该布尔表达式执行断言,若该表达式为false,系统会报告一个错误。通过验证断言是true,能够使程序员确信程序的正确性。

        5.1开启和关闭断言

5.2何时使用断言

断言的使用是一个复杂的问题,因为这将涉及程序的风格、断言运用的目标、程序的性质等。通常,断言用于检查一些关键的值,并且这些值对整个应用程序或局部功能的实现有较大影响,并且当断言失败,这些错误是不容易恢复的。

6.记录日志

每个 Java 程序员都很熟悉在有问题的代码中插入一些 System . out . println 方法调用来帮助
观察程序运行的操作过程 当然 一旦发现问题的根源 就要将这些语句从代码中删去
果接下来又出现了问题 就需要再插入几个调用 System . out . println 方法的语句 记录日志
API 就是为了解决这个问题而设计的 下面先讨论这些 API 的优点
•可以很容易地取消全部日志记录,或者仅仅取消某个级别的日志,而且打开和关闭这
个操作也很容易。
•可以很简单地禁止日志记录的输出, 因此,将这些日志代码留在程序中的开销很小。
•日志记录可以被定向到不同的处理器, 用于在控制台中显示, 用于存储在文件中等。
•日志记录器和处理器都可以对记录进行过滤。过滤器可以根据过滤实现器制定的标准
丢弃那些无用的记录项。
•日志记录可以采用不同的方式格式化,例如,纯文本或 XML。
应用程序可以使用多个日志记录器, 它们使用类似包名的这种具有层次结构的名字,
例如, com.mycompany.myapp
0
•在默认情况下,日志系统的配置由配置文件控制。如果需要的话, 应用程序可以替换
这个配置。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

m87里的光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值