⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter9.htm

📁 一本Java由初级到高级的编程书籍
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<br>
String toString()<br>
返回对Throwable的一段简要说明,其中包括详细的消息(如果有的话)。<br>
<br>
void printStackTrace()<br>
void printStackTrace(PrintStream)<br>
打印出Throwable和Throwable的调用堆栈路径。调用堆栈显示出将我们带到违例发生地点的方法调用的顺序。<br>
第一个版本会打印出标准错误,第二个则打印出我们的选择流程。若在Windows下工作,就不能重定向标准错误。因此,我们一般愿意使用第二个版本,并将结果送给System.out;这样一来,输出就可重定向到我们希望的任何路径。<br>
除此以外,我们还可从Throwable的基础类Object(所有对象的基础类型)获得另外一些方法。对于违例控制来说,其中一个可能有用的是getClass(),它的作用是返回一个对象,用它代表这个对象的类。我们可依次用getName()或toString()查询这个Class类的名字。亦可对Class对象进行一些复杂的操作,尽管那些操作在违例控制中是不必要的。本章稍后还会详细讲述Class对象。<br>
下面是一个特殊的例子,它展示了Exception方法的使用(若执行该程序遇到困难,请参考第3章3.1.2小节“赋值”):<br>
<br>
411页中程序<br>
<br>
该程序输出如下:<br>
<br>
411页下程序<br>
<br>
可以看到,该方法连续提供了大量信息——每类信息都是前一类信息的一个子集。<br>
<br>
9.2.5 重新“掷”出违例<br>
在某些情况下,我们想重新掷出刚才产生过的违例,特别是在用Exception捕获所有可能的违例时。由于我们已拥有当前违例的句柄,所以只需简单地重新掷出那个句柄即可。下面是一个例子:<br>
catch(Exception e) {<br>
System.out.println(&quot;一个违例已经产生&quot;);<br>
throw e;<br>
}<br>
重新“掷”出一个违例导致违例进入更高一级环境的违例控制器中。用于同一个try块的任何更进一步的catch从句仍然会被忽略。此外,与违例对象有关的所有东西都会得到保留,所以用于捕获特定违例类型的更高一级的控制器可以从那个对象里提取出所有信息。<br>
若只是简单地重新掷出当前违例,我们打印出来的、与printStackTrace()内的那个违例有关的信息会与违例的起源地对应,而不是与重新掷出它的地点对应。若想安装新的堆栈跟踪信息,可调用fillInStackTrace(),它会返回一个特殊的违例对象。这个违例的创建过程如下:将当前堆栈的信息填充到原来的违例对象里。下面列出它的形式:<br>
<br>
412-413页程序<br>
<br>
其中最重要的行号在注释内标记出来。注意第17行没有设为注释行。它的输出结果如下:<br>
<br>
413页中程序<br>
<br>
因此,违例堆栈路径无论如何都会记住它的真正起点,无论自己被重复“掷”了好几次。<br>
若将第17行标注(变成注释行),而撤消对第18行的标注,就会换用fillInStackTrace(),结果如下:<br>
<br>
413页下程序<br>
<br>
由于使用的是fillInStackTrace(),第18行成为违例的新起点。<br>
针对g()和main(),Throwable类必须在违例规格中出现,因为fillInStackTrace()会生成一个Throwable对象的句柄。由于Throwable是Exception的一个基础类,所以有可能获得一个能够“掷”出的对象(具有Throwable属性),但却并非一个Exception(违例)。因此,在main()中用于Exception的句柄可能丢失自己的目标。为保证所有东西均井然有序,编译器强制Throwable使用一个违例规范。举个例子来说,下述程序的违例便不会在main()中被捕获到:<br>
<br>
414页上程序<br>
<br>
也有可能从一个已经捕获的违例重新“掷”出一个不同的违例。但假如这样做,会得到与使用fillInStackTrace()类似的效果:与违例起源地有关的信息会全部丢失,我们留下的是与新的throw有关的信息。如下所示:<br>
<br>
414-415页程序<br>
<br>
输出如下:<br>
<br>
415页程序<br>
<br>
最后一个违例只知道自己来自main(),而非来自f()。注意Throwable在任何违例规范中都不是必需的。<br>
永远不必关心如何清除前一个违例,或者与之有关的其他任何违例。它们都属于用new创建的、以内存堆为基础的对象,所以垃圾收集器会自动将其清除。<br>
<br>
9.3 标准Java违例<br>
Java包含了一个名为Throwable的类,它对可以作为违例“掷”出的所有东西进行了描述。Throwable对象有两种常规类型(亦即“从Throwable继承”)。其中,Error代表编译期和系统错误,我们一般不必特意捕获它们(除在特殊情况以外)。Exception是可以从任何标准Java库的类方法中“掷”出的基本类型。此外,它们亦可从我们自己的方法以及运行期偶发事件中“掷”出。<br>
为获得违例的一个综合概念,最好的方法是阅读由http://java.sun.com提供的联机Java文档(当然,首先下载它们更好)。为了对各种违例有一个大概的印象,这个工作是相当有价值的。但大家不久就会发现,除名字外,一个违例和下一个违例之间并不存在任何特殊的地方。此外,Java提供的违例数量正在日益增多;从本质上说,把它们印到一本书里是没有意义的。大家从其他地方获得的任何新库可能也提供了它们自己的违例。我们最需要掌握的是基本概念,以及用这些违例能够做什么。<br>
java.lang.Exception<br>
这是程序能捕获的基本违例。其他违例都是从它衍生出去的。这里要注意的是违例的名字代表发生的问题,而且违例名通常都是精心挑选的,可以很清楚地说明到底发生了什么事情。违例并不全是在java.lang中定义的;有些是为了提供对其他库的支持,如util,net以及io等——我们可以从它们的完整类名中看出这一点,或者观察它们从什么继承。例如,所有IO违例都是从java.io.IOException继承的。<br>
<br>
9.3.1 RuntimeException的特殊情况<br>
本章的第一个例子是:<br>
if(t == null)<br>
throw new NullPointerException();<br>
看起来似乎在传递进入一个方法的每个句柄中都必须检查null(因为不知道调用者是否已传递了一个有效的句柄),这无疑是相当可怕的。但幸运的是,我们根本不必这样做——它属于Java进行的标准运行期检查的一部分。若对一个空句柄发出了调用,Java会自动产生一个NullPointerException违例。所以上述代码在任何情况下都是多余的。<br>
这个类别里含有一系列违例类型。它们全部由Java自动生成,毋需我们亲自动手把它们包含到自己的违例规范里。最方便的是,通过将它们置入单独一个名为RuntimeException的基础类下面,它们全部组合到一起。这是一个很好的继承例子:它建立了一系列具有某种共通性的类型,都具有某些共通的特征与行为。此外,我们没必要专门写一个违例规范,指出一个方法可能会“掷”出一个RuntimeException,因为已经假定可能出现那种情况。由于它们用于指出编程中的错误,所以几乎永远不必专门捕获一个“运行期违例”——RuntimeException——它在默认情况下会自动得到处理。若必须检查RuntimeException,我们的代码就会变得相当繁复。在我们自己的包里,可选择“掷”出一部分RuntimeException。<br>
如果不捕获这些违例,又会出现什么情况呢?由于编译器并不强制违例规范捕获它们,所以假如不捕获的话,一个RuntimeException可能过滤掉我们到达main()方法的所有途径。为体会此时发生的事情,请试试下面这个例子:<br>
<br>
417页上程序<br>
<br>
大家已经看到,一个RuntimeException(或者从它继承的任何东西)属于一种特殊情况,因为编译器不要求为这些类型指定违例规范。<br>
输出如下:<br>
<br>
java.lang.RuntimeException: From f()<br>
at NeverCaught.f(NeverCaught.java:9)<br>
at NeverCaught.g(NeverCaught.java:12)<br>
at NeverCaught.main(NeverCaught.java:15)<br>
<br>
所以答案就是:假若一个RuntimeException获得到达main()的所有途径,同时不被捕获,那么当程序退出时,会为那个违例调用printStackTrace()。<br>
注意也许能在自己的代码中仅忽略RuntimeException,因为编译器已正确实行了其他所有控制。因为RuntimeException在此时代表一个编程错误:<br>
(1) 
一个我们不能捕获的错误(例如,由客户程序员接收传递给自己方法的一个空句柄)。<br>
(2) 作为一名程序员,一个应在自己的代码中检查的错误(如ArrayIndexOutOfBoundException,此时应注意数组的大小)。<br>
可以看出,最好的做法是在这种情况下违例,因为它们有助于程序的调试。<br>
另外一个有趣的地方是,我们不可将Java违例划分为单一用途的工具。的确,它们设计用于控制那些讨厌的运行期错误——由代码控制范围之外的其他力量产生。但是,它也特别有助于调试某些特殊类型的编程错误,那些是编译器侦测不到的。<br>
<br>
9.4 创建自己的违例<br>
并不一定非要使用Java违例。这一点必须掌握,因为经常都需要创建自己的违例,以便指出自己的库可能生成的一个特殊错误——但创建Java分级结构的时候,这个错误是无法预知的。<br>
为创建自己的违例类,必须从一个现有的违例类型继承——最好在含义上与新违例近似。继承一个违例相当简单:<br>
<br>
418-419页程序<br>
<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -