处理错误
- 出现错误时程序应该(1)返回安全状态并允许用户执行一些其他命令; (2)或者允许用户保存所有操作的结果,并以妥善方式退出程序;
- 错误产生的原因:(1)用户输入错误;(2)设备错误;(3)物理限制;(4)代码错误: 有些情况下代码的调用方并不能根据程序的错误返回码进行处理, 这时就需要抛出异常给异常处理器去处理;
- 应用程序不应该抛出Error级别的错误, 出现这种错误一般时JVM或者资源耗尽, 除了通知用户并中止程序外,无法再做更多;
Exception
的子类 RuntimeException
表示异常时由程序错误导致, 如果出现RuntimeException
异常, 程序员就一定有责任去处理杜绝它.
- 派生于
Error
和 RuntimeException
的异常被称为unchecked异常, 其他为checked异常. (checked翻译为受查)
- 下面四种情况下应该抛出异常: 1. 调用了抛出异常的方法; 2. 程序throw出一个异常; 3. 程序出错; 4. JVM或运行时库报错
- 对于给外部调用的方法, 有义务在方法上声明throws异常(checked)类型, 但不包括
Error
(调用方没能力处理)还有RuntimeException
非受查异常(程序员有义务避免)
捕获异常
- Java7 允许一个catch中捕获多个类型异常, 变量e隐含final修饰的
catch(FileNotFoundException | UnknownHostException e) { . . . }
- 最佳实践: 重新包装的异常使用
Throwable.initCause(e)
可以设置异常的原因
- 强烈建议解耦合使用try/catch和try/finally
try
{
try
{
code that might throw exceptions
}
finally
{
in.close() ;
}
}
catch (IOException e)
{
show error message
}
}
- 接口
AutoCloseable
,Closeable
(继承自AutoCloseable
) , 实现类的方法可以使用try(😉{}块实现资源自动回收.即相当于finally中调用接口的close()
方法. 如果close()方法中也抛出异常, 会被增加到原有异常中, 而finally{}则会替换原有异常.
异常处理的技巧
- 异常处理代替不了单元测试
- 不要过分细化异常, 如每行代码分别捕获
- 利用异常层次结构, 如使用更准确的子类,不要都抛出Exception类
- 不要压制异常, 如catch{}空处理罕见不重要的异常
- 检查错误时, 苛刻比放任更好, 在早期抛出异常更合适 早抛出
- 不要羞于传递异常 晚捕获
使用断言
- 断言默认不启用,通过
java -ea AppName
启用, 其时类加载器的功能,不启用则跳过; -ea, -da, -esa分别时启用,禁用,启用系统类断言
- Java中三种处理系统错误的方式1. 抛出异常; 2. 日志 ; 3. 使用断言
- 断言的特征: 1. 断言失败是致命的, 不可恢复的错误; 2.断言检查只用于开发,测试阶段;
- 断言是测试和调试阶段的战术性工具
调试技巧(只列出不常用但可能有用的)
- java -verbose 标志启动JVM可以查看类加载情况
- javac -Xlint <> 可以对一些常见问题进行检查
- jmap工具可以获取一个堆的转储
jmap -dump:format=b,file=dumpFileName processsID
Jhat dumpFileName
- java -Xprof 标记可以跟踪那些代码常被调用的方法并输出到控制台