本博客只用于个人查漏补缺
处理错误
异常分类
- 所有异常都是由Throwable继承而来,其下有两个分支 Error 和 Exception
- Error 类层次结构描述了 Java运行时系统内部错误和资源耗尽错误,这种错误一般不能抛出,很少出现
- Excption 层次结构又分为 IOException 和 RuntimeException
- 编程错误导致的异常属于 RuntimeException
- 程序本身没有问题, I/O 错误属于其他异常
- 派生于 RuntimeException 的异常包括(程序员自己的问题)
- 错误的强制类型转换
- 数组访问越界
- 访问 null 指针
- 不是派生于 RuntimeException 的异常包括(不是你的问题)
- 超越文件末尾读取数据
- 打开一个不存在的文件
- 根据给定字符串查找Class对象,而这个字符串表示的类不存在
- RuntimeException 和 Error 派生的异常 属于 非检查型异常
- 其他所有异常(I/O等) 属于 检查型异常,运行的时候会被检查出来
声明检查型异常
- throws 抛出异常,如果一个方法要抛出多个异常,在方法首部列出所有的异常类,每个异常类之间用逗号隔开
public Image loadImage(int i) thorws FileNotFindException, EOFException {}
- 不应该声明从RuntimeException 继承的那些非检查型异常
如:throws ArrayIndexOutOfBoundsException
- 这些运行时错误应该在我们的控制之中,应该多花时间修正这些错误,而不是声明这些错误可能发生
- 一个方法必须声明所有可能抛出的 检查型异常, 而 非检查型异常 要么在你的控制之外(Error),要么就是一开始应该避免的(RuntimeException)
- 子类覆盖父类的方法,子类中抛出的异常必须比父类小,子类也可以不抛出异常
如何抛出异常
throw new Exception();
即
- 找到一个合适的异常类
- 创建这个异常类的一个对象
- 将对象抛出(throw)
创建异常类
- 定义一个派生于Exception的类,或者派生于 Exception子类的类
- 一般来说,自定义的这个异常类应该包含,一个无参构造,另一个包含详细描述信息的构造(超类的throwable的toString方法会返回一个字符串,包含这个详细信息,在调试中非常有用)
捕获异常
捕获单个异常
- 使用
try{...} catch ( Exception e) { handle it }
- 如果 try 语句块中的任何代码抛出了 catch 字句中指定的一个异常类,那么
程序将跳过 try 语句块的剩余代码
程序将执行 catch 字句中的处理器代码
捕获多个异常
- 使用多个 catch 子句,为每个异常提供单独的 catch 子句
- 可以通过
e.getMassage();
获得异常对象的更多信息
e.getClass().getName();
获取异常对象的实际类型 - java 7 中,同一个 catch 子句可以捕获多个异常类型,使用
|
符号隔开异常类型
只有当捕获的异常彼此之间不存在子类关系是才需要这个特性
捕获使用一个 catch 多个异常时,异常变量 e 隐含为 final 变量,在 catch 子句体中不能为 e 赋不同的值
再次抛出异常与异常链
- 可以在 catch 再抛出一个异常,通常,希望改变异常的类型时会这么做
- 可以吧原始异常设置为新异常的“原因”
- 使用这种技术,可以在子系统中抛出高层异常,而不会丢失原始异常的细节
- 如果在一个方法中发生了一个 检查型异常 ,但这个方法不允许抛出 检查型异常,那么可以用包装技术,捕获这个检查型异常,然后包装成一个 运行时异常
finally子句
- try语句可以只有finally子句,而没有catch子句
- 如果在 try 中和 finally 中都有 return 语句,那么 finally 语句中的 return 会在 try 中的 return 返回之前返回,也就是忽略掉原先 try 的返回值
如果 try 中发生了异常, finally中的 return 甚至会 “吞掉” 这个异常 - finally 子句要用于清理资源,不要将 改变控制流程语句 (return,throw,break,continue)放在其中
try-with-Resources语句(Java 7)
- 只有实现了 AutoCloseable 或 (其子接口) Closeable 接口的类才能使用
try (FileInputStream in = new FileInputStream("...");
...) //可以有多个资源,用 ; 隔开
{
...
}
- try块退出(正常退出 或者 存在异常时退出)时,都会自动调用 对象的 close() 方法
- try-with-resources 可以用本身可以由 catch 子句和 finally子句,这些子句会在关闭资源之后执行
分析堆栈轨迹元素
- 堆栈轨迹是程序执行过程中某个特定点上所有挂起的方法的一个列表
异常使用技巧
- 异常处理不能代替简单的测试,因为异常处理耗费的时间大,也就是尽量只在异常的情况下使用异常
- 充分利用异常层次结构,如果能将一种异常转换为另一种更加合适的异常,那么就应该转换
- 早抛出,晚捕获
断言
- 断言机制允许在测试期间向代码插入一些异常,而在生产代码中会自动删除这些异常
可以看做是一种高级的异常处理,可以起到使代码更加稳定的作用 - 断言的格式
assert condition;
assert condition : expression
condition是一个布尔表达式
expression部分唯一的目的就是产生一个消息字符串。
启用和禁用断言
- 默认情况下,断言是禁用的,可以在程序运行时用 -enableassertions 或 -ea 来启用
-disableassertions 或 -da 禁用断言 - 不过对于那些没有类加载器的“系统类”上,要使用 -enablesystemassertions 或 -esa 来开关断言
日志
基本日志
- 使用全局日志记录器(global logger) 并调用其 info 方法
Logger.getGlobal().info("hellow logger");
放在main方法的第一行,会取消所有的日志
Logger.getGlobal().setLevel(Level.OFF);
高级日志
- 定义自己的日志记录器,而不是全局日志记录器
private static final Logger myLogger = Logger.getLogger("com.mycompany.myapp");
- 与包名类似,日志记录器也有类似的层次结构。
对于包来说,父与子之间没有语义关系,而日志记录器的父与子之间将共享一些属性
如:日志记录器“com.mycompany”设置了日志级别,它的子日志会继承这个级别 - 通常有七种日志级别:
SEVERE
WARNING
INFO
CONFIG
FINE
FINER
FINEST
默认情况下,只记录前3个级别,也就是INFO或更高级别的日志,其他等级用来记录那些有助于诊断问题而对用户帮助不大的信息