对于可恢复/期望恢复的情况,抛出checked异常
对于程序出错、不确定是否可恢复,抛出unchecked异常
尽可能在checked异常中提供方法和丰富的信息,以便协助恢复
不建议声明Error类型异常、不建议声明RuntimeException类型的异常
方法要在定义和spec中明确声明所抛出的全部checked异常
没有声明所有抛出的checked异常,编译会出错
unchecked异常和Error可以不用处理
如果子类型中override了父类型中的函数,那么子类型中方法抛出的异常不能比父类型抛出的异常类型更宽泛
子类型方法可以抛出更具体的异常,也可以不抛出任何异常
如果父类型的方法未抛出异常,那么子类型的方法也不能抛出异常
利用Exception的构造函数,将发生错误现场信息充分的传递给client
为了捕获失败,异常的细节信息应该包含“对该异常有贡献” 所有参数和域的值
出于安全考虑,千万不要在细节信息中包含密码、秘钥以及类似的信息!
找到一个能表达错误的JDK提供的Exception类/或者构造一个新的Exception类
构造Exception类的实例,将错误信息写入,抛出它
一旦异常抛出,方法不会在将控制权返回给调用它的client,依次也无需考虑返回错误代码
如果JDK提供的exception类无法充分描述你的程序发生的错误,可以创建自己的异常类
异常发生后,如果找不到处理器,就终止执行程序,在控制台打印出stack trace
当try块抛出在catch子句中指定的异常时,将忽略出现异常位置之后的代码 ,由catch子句进行异常处理
无异常抛出时,catch子句不执行
如果抛出的异常,在catch语句中没有匹配的异常处理,则被访问的程序退出(由client处理)
也可以不在本方法内处理,而是传递给调用方,有client处理(“推卸责任”),在某些情况下,client更清楚如何处理
尽量在自己这里处理,实在不行就往上传——要承担责任
但有些时候自己不知道如何处理,那么就提醒上家,有client自己处理
本来catch语句下面是用来做exception handling的,但也可以在catch里抛出异常
这么做的目的是:更改exception的类型,更方便client端获取错误信息并处理:是client不依赖于无关不感兴趣的低层异常
但是这么做的时候最好保留“根原因”
当异常抛出时,方法中正常执行的代码被终止
如果异常发生前曾申请过某些资源,那么异常发生后这些资源要被恰当的回收
Finally部分的代码,是否捕获异常都会被执行
最好的防御就是不要引入bug
如果无法避免bugs,尝试着将bug限制在最小的范围内
限定在一个方法/小模块内部,不扩散
尽快失败,就越容易发现、越早修复
利用断言,Fail fast,避免扩散
检查前置条件是防御式编程的一种典型形式
断言:在开发阶段的代码中嵌入,检验某些“假设”是否成立。若成立,表明程序运行正常,否则表明存在错误
断言即是对代码中程序员所做的假设的文档化,也不会影响运行时的性能(在实际使用时,assertion可以被disabled)
assert condition;
assert condition: message;
所构造的message在发生错误时显示给用户,便于快速发现错误所在
断言主要用于开发阶段,避免引入和帮助发现bug
实际运行阶段,不再使用断言
是要断言的主要目的时为了在开发阶段调试程序、尽快避免错误
运行时断言不是免费的,且它们会使代码混乱不易读,因此必须谨慎使用
代码需要实现的功能,不要出现在断言中
程序之外的事,不受你控制,不要乱用断言
断言只是检查程序内部装态是否符合规约
断言一旦false,程序就停止执行
外部失败不是bugs,你的代码无法保证不出现此类外部错误
外部失败要exception
断言是非常影响运行时性能的
在其他一些开发者眼里,不应该针对参数的合法性使用断言
如果参数来自外部(不受自己控制),使用异常处理
如果来自于自己所写的其他代码,可以使用断言来帮助发现错误(例如:post-condition)
按照惯例,public方法上的前置条件时通过抛出待定的、指定的异常的显示检查来进行的
可以使用断言将来测试非公共方法的前置条件,当认为无论client对该类做什么,这些前置条件都正确时(正确性不由client决定)
在public和nonpublic方法中,都可以使用断言来处理后置条件
断言和异常处理都可以处理同样的错误
开发阶段用断言尽可能消除bugs
在发行版本里用异常处理机制处理漏掉的错误