java程序设计语言提供了三种可抛出结构:
1,受检的异常(checked exception)
2,运行时异常(run-time exception)
3,错误(error)
关于什么时候适合使用哪种可抛出结构,程序员中间存在一些困惑。虽然这项决定并不总是那么清晰吗、,但还是有一般性的原则提供了强有力的指导。
再决定使用受检的异常或者未受检的异常时,主要的原则是:如果期望调用者能够蛇胆的恢复,对于这种情况就应该受用受检的异常 。通过抛出受检的异常,强迫调用者在一个catch子句中处理该一场,或者将它传播出去。因此,方法中声明要抛出的每个受检的异常,都是对API用户的一种潜在指示:与异常相关联的条件是调用这个方法的一种可能结果。
API的设计者让API用户面对受检异常,以此强制用户从这个异常条件中恢复。用户都不需要也不应该被捕获的可抛出结构,如果程序抛出未受检的异常或者错误,往往就属于不可恢复的情形,继续执行下去有益无害。如果程序没有捕捉到这样的可抛出结构,将会导致当前线程停止,并出现适当的错误消息。
用运行时异常来表明编程错误。大多数的运行时异常都表示前提违例。所谓前提违例是指API的客户没有遵守API规范建立的约定。如果,数组访问的约定指明了数组的下标值必须在零和数组长度减1之间。ArrayIndexOutBoundsException表明这个前提被违反了。
虽然JLS(Java语言规范)并没有要求,但是按照惯例,错误往往被JVM保留用于表示资源不足、约束失败、或者其他使程序无法继续执行的条件,由于这已经是个几乎被普遍接受的惯例,因此最好不要再实现任何新的Error子类。因此,你实现的所有未受检的抛出结构都应该是RuntimeException的子类(直接活间接的)。
要想定义一个抛出结构,他不是Exception EuntimeException Error的子类,这也是可能的,JLS并没有直接规定这样的抛出结构,而是隐式的指定了:从行为意义上讲它们等同于普通的受检一擦好难过(即Exception的子类,但不是RuntimeException的子类)。那么,什么时候应该使用这样的抛出结构呢?总之,永远也不会用到,他与普通的受检异常相比没有任何益处,只会困扰API的用户。
总而言之,对于可恢复的情况,使用受检异常,对于程序错误使用运行时异常。当然,情况并不总是那么黑白分明,例如,考虑资源枯竭的情形,这可能是由于程序错误引起的,比如分配了一块不合理过大的数组,也可能确实是由于资源不足而引起的。如果资源枯竭是由于临时的短缺,或者临时需求太大所造成的,这种情况可能就是可恢复的。API设计者需要判断这样的资源枯竭是否允许恢复。如果你相信一种情况可能允许恢复,就是用受检的异常,如果不是,则使用运行时异常,如果不清楚是否有可能恢复,最好使用未受检的异常,
API的设计者往往会忘记,异常也是个完全意义上的对象,可以在他上面定义任意的方法,这些方法的主要用途是为了捕捉异常的代码而提供额外的信息,特别是关于引发这种异常条件的信息,如果没有这样的方法,程序员必须要懂得如何解析“该异常的字符串表示法”,以便获取这些额外信息。这是极为不好的做法,类很少会指定他们的字符串表示法中的细节,因此,不同的实现,不同的版本,字符串表示法会大相径庭,因此,”解析异常的字符串表示法:的代码可能是不可移植的,也是非常脆弱的。
因为受检的异常往往指明了可恢复的条件,所以,对于这样的异常,提供一些辅助的方法尤其重要,通过这些方法,调用者可以获取一些有助于恢复的信息。例如,假设因为用户没有存储足够数量的钱,他企图在一个收费电话上进行呼叫就会失败,于是抛出受检的异常。这个异常应该提供一个访问方法,以便允许客户查询所缺的费用金额,从而可以将这个数值传递给电话用户。