Java的基本原理就是“形式错误的代码不会运行”。
捕获错误最理想的是在编译期间,最好在试图运行程序以前。然而,并非所有错误都能在编译期间侦测到。有些问题必须在运行期间解决,让错误的缔结者通过一些手续向接收者传递一些适当的信息,使其知道该如何正确地处理遇到的问题。
在错误控制中排除所有偶然性,强制格式的正确。
我们只需要在一个地方处理问题:“违例控制模块”或者“违例控制器”。
“违例条件”表示在出现什么问题的时候应中止方法或作用域的继续。
产生一个违例时,会发生几件事情。首先,按照与创建Java对象一样的方法创建违例对象:在内存“堆”里,使用new来创建。随后,停止当前执行路径(记住不可沿这条路径继续下去),然后从当前的环境中释放出违例对象的句柄。此时,违例控制机制会接管一切,并开始查找一个恰当的地方,用于继续程序的执行。这个恰当的地方便是“违例控制器”,它的职责是从问题中恢复,使程序要么尝试另一条执行路径,要么简单地继续。
对于Java的违例控制机制,它的一个好处就是允许我们在一个地方将精力集中在要解决的问题上,然后在另一个地方对待来自那个代码内部的错误。
每个catch从句——即违例控制器——都类似一个小型方法,它需要采用一个(而且只有一个)特定类型的自变量。
只有相符的catch从句才会得到执行;它与switch语句不同,后者在每个case后都需要一个break命令,防止误执行其他语句。
Throwable在任何违例规范中都不是必需的。
永远不必关心如何清除前一个违例,或者与之有关的其他任何违例。它们都属于用new创建的、以内存堆为基础的对象,所以垃圾收集器会自动将其清除。
Throwable对象有两种常规类型(亦即“从Throwable继承”)。其中,Error代表编译期和系统错误,我们一般不必特意捕获它们(除在特殊情况以外)。Exception是可以从任何标准Java库的类方法中“掷”出的基本类型。此外,它们亦可从我们自己的方法以及运行期偶发事件中“掷”出。
if(t == null) throw new NullPointerException();我们根本不必这样做——它属于Java进行的标准运行期检查的一部分。若对一个空句柄发出了调用,Java会自动产生一个NullPointerException违例。所以上述代码在任何情况下都是多余的。
几乎永远不必专门捕获一个“运行期违例”——RuntimeException——它在默认情况下会自动得到处理。
尽管违例规范是由编译器在继承期间强行遵守的,但违例规范并不属于方法类型的一部分,后者仅包括了方法名以及自变量类型。因此,我们不可在违例规范的基础上覆盖方法。除此以外,尽管违例规范存在于一个方法的基础类版本中,但并不表示它必须在方法的衍生类版本中存在。这与方法的“继承”颇有不同(进行继承时,基础类中的方法也必须在衍生类中存在)。换言之,用于一个特定方法的“违例规范接口”可能在继承和覆盖时变得更“窄”,但它不会变得更“宽”——这与继承时的类接口规则是正好相反的。
try {
// 要保卫的区域:
// 可能“掷”出A,B,或C的危险情况
} catch (A a1) {
// 控制器 A
} catch (B b1) {
// 控制器 B
} catch (C c1) {
// 控制器 C
} finally {
// 每次都会发生的情况
}
无论是否“掷”出一个违例,finally从句都会执行。除非System.exit();
在没有“垃圾收集”以及“自动调用破坏器”机制的一种语言中,finally显得特别重要,因为程序员可用它担保内存的正确释放——无论在try块内部发生了什么状况。但Java提供了垃圾收集机制,所以内存的释放几乎绝对不会成为问题。另外,它也没有构建器可供调用。既然如此,Java里何时才会用到finally呢?
除将内存设回原始状态以外,若要设置另一些东西,finally就是必需的。
有时需要打开一个文件或者建立一个网络连接,或者在屏幕上画一些东西,甚至设置外部世界的一个开关,等等。
即使违例不在当前的catch从句集里捕获(catch可能捕获不到,或者缺失catch),finally都会在违例控制机制转到更高级别搜索一个控制器之前得以执行。
“一旦产生违例,会正确地进行清除吗?”大多数时候都会非常安全,但在构建器中却是一个大问题。构建器将对象置于一个安全的起始状态,但它可能执行一些操作——如打开一个文件。除非用户完成对象的使用,并调用一个特殊的清除方法,否则那些操作不会得到正确的清除。若从一个构建器内部“掷”出一个违例,这些清除行为也可能不会正确地发生。
Java的一项缺陷——除内存清除之外的所有清除都不会自动进行。
用违例做下面这些事情:
(1) 解决问题并再次调用造成违例的方法。
(2) 平息事态的发展,并在不重新尝试方法的前提下继续。
(3) 计算另一些结果,而不是希望方法产生的结果。
(4) 在当前环境中尽可能解决问题,以及将相同的违例重新“掷”出一个更高级的环境。
(5) 在当前环境中尽可能解决问题,以及将不同的违例重新“掷”出一个更高级的环境。
(6) 中止程序执行。
(7) 简化编码。若违例方案使事情变得更加复杂,那就会令人非常烦恼,不如不用。
(8) 使自己的库和程序变得更加安全。这既是一种“短期投资”(便于调试),也是一种“长期投资”(改善应用程序的健壮性)
think in java回顾整理之违例
最新推荐文章于 2022-02-25 20:00:37 发布