@@ -15,7 +15,7 @@ Java 使用异常来提供一致的错误报告模型,使得构件能够与客
1515
1616Java 中的异常处理的目的在于通过使用少于目前数量的代码来简化大型、可靠的程序的生成,并且通过这种方式可以使你更加确信:你的应用中没有未处理的错误。异常的相关知识学起来并非艰涩难懂,并且它属于那种可以使你的项目受益明显、立竿见影的特性之一。
1717
18- 因为异常处理是 Java 中唯一官方的错误报告机制,并且通过编译器强制执行,所以不学习异常处理的话,书中也就只能写出那么些例子了。本章将向读者介绍如何编写正确的异常处理 3 ] 程序 ,并将展示当方法出问题的时候,如何产生自定义的异常。
18+ 因为异常处理是 Java 中唯一官方的错误报告机制,并且通过编译器强制执行,所以不学习异常处理的话,书中也就只能写出那么些例子了。本章将向读者介绍如何编写正确的异常处理程序 ,并将展示当方法出问题的时候,如何产生自定义的异常。
1919
2020<!-- Concepts -->
2121
@@ -35,7 +35,7 @@ C 以及其他早期语言常常具有多种错误处理模式,这些模式往
3535
3636<!-- Catching an Exception -->
3737
38- 异常情形(exceptional condition)是指阻止当前方法或作用城继续执行的问题 。把异常情形与普通问题相区分很重要,所谓的普通问题是指,在当前环境下能得到足够的信息,总能处理这个错误。而对于异常情形,就不能继续下去了,因为在当前环境下无法获得必要的信息来解决问题。你所能做的就是从当前环境跳出,并且把问题提交给上一级环境。这就是抛出异常时所发生的事情。
38+ 异常情形(exceptional condition)是指阻止当前方法或作用域继续执行的问题 。把异常情形与普通问题相区分很重要,所谓的普通问题是指,在当前环境下能得到足够的信息,总能处理这个错误。而对于异常情形,就不能继续下去了,因为在当前环境下无法获得必要的信息来解决问题。你所能做的就是从当前环境跳出,并且把问题提交给上一级环境。这就是抛出异常时所发生的事情。
3939
4040除法就是一个简单的例子。除数有可能为 0,所以先进行检查很有必要。但除数为 0 代表的究竟是什么意思呢?通过当前正在解决的问题环境,或许能知道该如何处理除数为 0 的情况。但如果这是一个意料之外的值,你也不清楚该如何处理,那就要抛出异常,而不是顺着原来的路径继续执行下去。
4141
@@ -56,7 +56,7 @@ if(t == null)
5656
5757### 异常参数
5858
59- 与使用 Java 中的其他对象一样,我们总是用 new 在堆上创建异常对象,这也伴随着存储空间的分配和构造器的调用。所有标准异常类都有两个构造器:一个是默认构造器 ;另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器:
59+ 与使用 Java 中的其他对象一样,我们总是用 new 在堆上创建异常对象,这也伴随着存储空间的分配和构造器的调用。所有标准异常类都有两个构造器:一个是无参构造器 ;另一个是接受字符串作为参数,以便能把相关信息放入异常对象的构造器:
6060
6161``` java
6262throw new NullPointerException (" t = null" );
8282}
8383```
8484
85- 对于不支持异常处理的程序语言,要想仔细检查错误,就得在每个方法调用的前后加上设置和错误检查的代码,甚至在每次调用同一方法时也得这么做。有了异常处理机制,可以把所有动作都放在 ry 块里,然后只需在一个地方就可以捕获所有异常。这意味着代码将更容易编写和阅读,因为完成任务的代码没有与错误检查的代码混在一起 。
85+ 对于不支持异常处理的程序语言,要想仔细检查错误,就得在每个方法调用的前后加上设置和错误检查的代码,甚至在每次调用同一方法时也得这么做。有了异常处理机制,可以把所有动作都放在 try 块里,然后只需在一个地方就可以捕获所有异常。这意味着你的代码将更容易编写和阅读,因为代码的目标是弄清楚错误检查 。
8686
8787### 异常处理程序
8888
@@ -121,7 +121,7 @@ try {
121121
122122不必拘泥于 Java 中已有的异常类型。Java 提供的异常体系不可能预见所有的希望加以报告的错误,所以可以自己定义异常类来表示程序中可能会遇到的特定问题。
123123
124- 要自己定义异常类,必须从已有的异常类继承,最好是选择意思相近的异常类继承(不过这样的异常并不容易找)。建立新的异常类型最简单的方法就是让编译器为你产生默认构造器 ,所以这几乎不用写多少代码:
124+ 要自己定义异常类,必须从已有的异常类继承,最好是选择意思相近的异常类继承(不过这样的异常并不容易找)。建立新的异常类型最简单的方法就是让编译器为你产生无参构造器 ,所以这几乎不用写多少代码:
125125
126126``` java
127127// exceptions/InheritingExceptions.java
@@ -153,7 +153,7 @@ Throw SimpleException from f()
153153Caught it!
154154```
155155
156- 编译器创建了默认构造器,它将自动调用基类的默认构造器 。本例中不会得到像 SimpleException(String) 这样的构造器,这种构造器也不实用。你将看到,对异常来说,最重要的部分就是类名,所以本例中建立的异常类在大多数情况下已经够用了。
156+ 编译器创建了无参构造器,它将自动调用基类的无参构造器 。本例中不会得到像 SimpleException(String) 这样的构造器,这种构造器也不实用。你将看到,对异常来说,最重要的部分就是类名,所以本例中建立的异常类在大多数情况下已经够用了。
157157
158158本例的结果被打印到了控制台上,本书的输出显示系统正是在控制台上自动地捕获和测试这些结果的。但是,你也许想通过写入 System.err 而将错误发送给标准错误流。通常这比把错误信息输出到 System.out 要好,因为 System.out 也许会被重定向。如果把结果送到 System.err,它就不会随 System.out 一起被重定向,这样更容易被用户注意。
159159
@@ -407,7 +407,7 @@ void f() { // ...
407407
408408这种在编译时被强制检查的异常称为被检查的异常。
409409
410- ## 任意所有捕获
410+ ## 捕获所有异常
411411
412412可以只写一个异常处理程序来捕获所有类型的异常。通过捕获异常类型的基类 Exception ,就可以做到这一点(事实上还有其他的基类,但 Exception 是所有编程行为相关的基类):
413413
@@ -932,9 +932,9 @@ if(t == null)
932932 throw new NullPointerException ();
933933```
934934
935- 如果必须对传递给方法的每个引用都检查其是否为 nul (因为无法确定调用者是否传入了非法引用),这听起来着实吓人。幸运的是,这不必由你亲自来做,它属于 Java 的标准运行时检测的一部分。如果对 null 引用进行调用,Java 会自动抛出 NullPointerException 异常,所以上述代码是多余的,尽管你也许想要执行其他的检查以确保 NullPointerException 不会出现。
935+ 如果必须对传递给方法的每个引用都检查其是否为 null (因为无法确定调用者是否传入了非法引用),这听起来着实吓人。幸运的是,这不必由你亲自来做,它属于 Java 的标准运行时检测的一部分。如果对 null 引用进行调用,Java 会自动抛出 NullPointerException 异常,所以上述代码是多余的,尽管你也许想要执行其他的检查以确保 NullPointerException 不会出现。
936936
937- 属于运行时异常的类型有很多,它们会自动被 lava 虚拟机抛出,所以不必在异常说明中把它们列出来。这些异常都是从 RuntimeException 类继承而来,所以既体现了继承的优点,使用起来也很方便。这构成了一组具有相同特征和行为的异常类型。并且,也不再需要在异常说明中声明方法将抛出 RuntimeException 类型的异常(或者任何从 RuntimeException 继承的异常),它们也被称为“不受检查异常”。这种异常属于错误,将被自动捕获,就不用你亲自动手了。要是自己去检查 RuntimeException 的话,代码就显得太混乱了。不过尽管通常不用捕获 RuntimeException 异常,但还是可以在代码中抛出 RuntimeException 类型的异常。
937+ 属于运行时异常的类型有很多,它们会自动被 java 虚拟机抛出,所以不必在异常说明中把它们列出来。这些异常都是从 RuntimeException 类继承而来,所以既体现了继承的优点,使用起来也很方便。这构成了一组具有相同特征和行为的异常类型。并且,也不再需要在异常说明中声明方法将抛出 RuntimeException 类型的异常(或者任何从 RuntimeException 继承的异常),它们也被称为“不受检查异常”。这种异常属于错误,将被自动捕获,就不用你亲自动手了。要是自己去检查 RuntimeException 的话,代码就显得太混乱了。不过尽管通常不用捕获 RuntimeException 异常,但还是可以在代码中抛出 RuntimeException 类型的异常。
938938
939939RuntimeException 代表的是编程错误:
940940
@@ -1294,7 +1294,7 @@ public class ExceptionSilencer {
12941294
12951295## 异常限制
12961296
1297- 当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。这个限制很有用,因为这意味若,当基类使用的代码应用到其派生类对象的时候 ,一样能够工作(当然,这是面向对象的基本概念),异常也不例外。
1297+ 当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。这个限制很有用,因为这意味着,若当基类使用的代码应用到其派生类对象的时候 ,一样能够工作(当然,这是面向对象的基本概念),异常也不例外。
12981298
12991299下面例子演示了这种(在编译时)施加在异常上面的限制:
13001300
@@ -1951,10 +1951,10 @@ try {
19511951
19521952## 其他可选方式
19531953
1954- | 异常处理系统就像一个活门(trap door),使你能放弃程序的正常执行序列。当“异常情形”
1954+ 异常处理系统就像一个活门(trap door),使你能放弃程序的正常执行序列。当“异常情形”
19551955发生的时候,正常的执行已变得不可能或者不需要了,这时就要用到这个“活门"。异常代表了当前方法不能继续执行的情形。开发异常处理系统的原因是,如果为每个方法所有可能发生的错误都进行处理的话,任务就显得过于繁重了,程序员也不愿意这么做。结果常常是将错误忽格。应该注意到,开发异常处理的初衷是为了方便程序员处理错误。
19561956
1957- 异常处理的一个重要原则是“只有在你知道如何处理的情况下才捕获异常"。实际上,异常处理的一个重要目标就是把错误处理的代码同错误发生的地点相分离。这使你能在一段代码中专注于要完成的事情,至于如何处理错误,则放在另一段代码中完成。这样以来,主于代码就不会与错误处理逻辑混在一起 ,也更容易理解和维护。通过允许一个处理程序去处理多个出错点,异常处理还使得错误处理代码的数量趋向于减少。
1957+ 异常处理的一个重要原则是“只有在你知道如何处理的情况下才捕获异常"。实际上,异常处理的一个重要目标就是把错误处理的代码同错误发生的地点相分离。这使你能在一段代码中专注于要完成的事情,至于如何处理错误,则放在另一段代码中完成。这样以来,主要代码就不会与错误处理逻辑混在一起 ,也更容易理解和维护。通过允许一个处理程序去处理多个出错点,异常处理还使得错误处理代码的数量趋向于减少。
19581958
19591959“被检查的异常”使这个问题变得有些复杂,因为它们强制你在可能还没准备好处理错误的时候被迫加上 catch 子句,这就导致了吞食则有害(harmful if swallowed)的问题:
19601960
@@ -2166,7 +2166,7 @@ WrapCheckedException.throwRuntimeException() 的代码可以生成不同类型
21662166
21672167异常是 Java 程序设计不可分割的一部分,如果不了解如何使用它们,那你只能完成很有限的工作。正因为如此,本书专门在此介绍了异常——对于许多类库(例如提到过的 I/O 库),如果不处理异常,你就无法使用它们。
21682168
2169- 异常处理的优点之一就是它使得你可以在某处集中精力处理你要解决的问题,而在另一处处理你编写的这段代码中产生的错误。尽管异常通常被认为是一种工具,使得你可以在运行时报告错误并从错误中恢复,但是我一直怀疑到底有多少时候“恢复”真正得以实现了,或者能够得以实现。我认为这种情况少于 10%,并且即便是这 10%,也只是将栈展开到某个已知的稳定状态,而并没有实际执行任何种类的恢复性行为。无论这是否正确,我一直相信“报告”功能是异常的精髓所在.Java 坚定地强调将所有的错误都以异常形式报告的这一事实 ,正是它远远超过语如 C++这类语言的长处之一,因为在 C++这类语言中,需要以大量不同的方式来报告错误,或者根本就没有提供错误报告功能。一致的错误报告系统意味着,你再也不必对所写的每一段代码,都质问自己“错误是否正在成为漏网之鱼?”(只要你没有“吞咽”异常,这是关键所在!)。
2169+ 异常处理的优点之一就是它使得你可以在某处集中精力处理你要解决的问题,而在另一处处理你编写的这段代码中产生的错误。尽管异常通常被认为是一种工具,使得你可以在运行时报告错误并从错误中恢复,但是我一直怀疑到底有多少时候“恢复”真正得以实现了,或者能够得以实现。我认为这种情况少于 10%,并且即便是这 10%,也只是将栈展开到某个已知的稳定状态,而并没有实际执行任何种类的恢复性行为。无论这是否正确,我一直相信“报告”功能是异常的精髓所在. Java坚定地强调将所有的错误都以异常形式报告的这一事实 ,正是它远远超过语如 C++这类语言的长处之一,因为在 C++这类语言中,需要以大量不同的方式来报告错误,或者根本就没有提供错误报告功能。一致的错误报告系统意味着,你再也不必对所写的每一段代码,都质问自己“错误是否正在成为漏网之鱼?”(只要你没有“吞咽”异常,这是关键所在!)。
21702170
21712171就像你将要在后续章节中看到的,通过将这个问题甩给其他代码-即使你是通过抛出 RuntimeException 来实现这一点的--你在设计和实现时,便可以专注于更加有趣和富有挑战性的问题了。
21722172
0 commit comments