Java学习笔记--异常
一:异常的基础知识
1.1 Java语言中的基本异常处理是围绕try-catch-finally、throws和throw这几个关键词展开
try-catch-finally用于捕获异常并进行处理;thrwos用于声明一个方法可能抛出的异常,对方法体中可能抛出的异常都要进行声明;throw用于遇见错误的时候抛出一个具体的异常。
1.2 异常的分类
Java中的异常可以分为两种异常类型--受检异常(checked exception)和非受检异常(unchecked exception)。非受检异常指的是java.lang.RuntimeException和java.lang.Error类及其子类,其他所有的异常类都被称之为受检异常。两种类型的异常在作用上没有差别,唯一的差别是使用受检异常时的合法性要在编译时刻由编译器来检测,因此受检异常在使用的时候需要比非受检异常更多的代码来规避编译错误。
一直以来,关于在程序中到底是该使用受检异常还是非受检异常,开发者之间一直存在着争议,毕竟两者各有优缺点。受检异常的特点在于它强制要求开发者在代码中进行显式的声明和捕获,否则就会产生编译错误。这种限制从好的方面来说,可以防止开发者意外地忽视某些出错的情况,因为编译器不允许出现未被处理的受检异常;从不好的方面来说,受检异常对程序中的设计提出了更高的要求。不恰当的使用受检异常,会使代码中充斥着大量没有实际作用、只是为了通过编译而添加的代码。而非受检异常的特点是,如果不捕获异常,不会产生编译错误,异常会在运行时刻才被抛出。非受检异常的好处是可以去掉一些不需要的异常处理代码,而不好之处是开发者可能忽略某些应该处理的异常。
目前的主流意见是,最好优先使用非受检异常。
1.3 异常声明是API的一部分
这一条提示主要是针对受检异常的。在一个公开方法的声明中使用throws关键词来声明其可能抛出的异常的时候,这些异常就成为这个公开方法的一部分,属于开放API。在维护这个公开API的时候,这些异常有可能会对API的演化造成阻碍,使得编写代码时不能不考虑向后兼容性的问题。
如果公开方法声明了会抛出一个受检异常,那么这个API的使用者肯定已经使用了try-catch-finally来处理这个异常。如果在后面的版本更新中,发现该API抛出这个异常是不合适的,也不能直接把这个异常的声明删除。因为这样会造成之前的API使用者的代码无法通过编译。
因此,对于API的设计者来说,谨慎考虑每个公开方法所申明的异常是很有必要的。因为一旦加了异常声明,在很长的一段时间内部都无法甩掉它。这也是为什么推荐使用非受检异常的一个重要原因,非受检异常不需要声明就可以直接抛出。但是对于一个方法抛出的非受检异常,也需要在文档中进行说明。
二.创建自已的异常
2.1精心设计异常的层次结构
一般来说,一个程序中应该要有自己的异常类的层次结构。如果只打算使用非受检异常,至少需要一个继承自RuntimeException的异常类。如果还需要使用受检异常,还有另外一个继承自Exception的异常类。如果程序中可能出现的异常情况比较多,应该在不同的抽象层次上定义相关的异常,并形成一个完整的层次结构。这个异常的层次结构与程序本身的类层次结构是相对应的。不同抽象层次上的代码应该只声明抛出同一个层次上的相关异常。
2.2异常类中包含足够的信息
异常存在的一个很重要的意义在于,当错误发生的时候,调用者可以对错误进行处理,从产生的错误中恢复。为了方便调用者处理这些异常,每个异常中都需要包含尽量丰富的信息。异常不应该只说明某些错误发生了,还应该给出相关的信息。异常类是完整的Java类,因此在其中添加所需的域和方法是一件很简单的事情。
2.3 异常与错误提示
对于与用户进行交互的程序来说,需要适当区分异常与展示给用户的错误提示。