第7章 异常、断言和日志
7.1 处理错误
Error、RuntimeException:非检查型异常。(编译器会检查是否为检查型异常提供了异常处理器);Exception:包含检查型异常。
RuntimeExceptioin:编程错误导致的异常
- 错误的强制类型转换;
- 数组访问越界;
- 访问null指针。
IOException:程序本身没问题,I/O错误这类问题导致的异常
- 试图长约文件末尾继续读取数据;
- 试图打开一个不存在的文件;
- 试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在。
String readData(Scanner in) throws EOFException
{
if (...)
{
throw new EOFException(String message);
}
}
// 自定义异常
class FileFormatException extends IOException
{
public FileFormatException(){}
public FileFormatException(String gripe)
{
super(gripe);
}
}
thorw与thorws的区别
7.2 捕获异常
try // 抛出 ExceptionType 异常类
{
...
}
catch(ExceptionType1 e) // 异常处理器
{
handler for this type
}
catch(ExceptionType2 | ExceptionType3 e) // 异常type2与type3不存在子类关系
{
handler for both type
}
......
finally
{
... // 不论是否有异常捕获,都会执行(清理资源,不要写改变控制流的语句: return/throw/break/continue)
}
注:捕获(try catch)知道如何处理的异常;继续传播(thorws)不知道如何处理的异常(交给处理器处理)。
// try-with-resources
try(Resource res = ...)
{
work with res
// 退出时,自动调用res.close()
}
7.3 使用异常的技巧
- 异常处理不能代替简单的测试;
- 不要过分细化异常;
- 充分利用异常层次结构;
- 不要压制异常;
- 在检测错误时,苛刻比放任更好;
- 不要羞于传递异常。
7.4 使用断言
断言机制:在测试期间向代码中插入一些检查,而在生成代码中会自动删除这些检查。
assert condition;
assert condition : expression; // expression 传入AssertionError对象的构造器
// 类加载器 启动/关闭 断言 enableassertions/disableassertions
java -enableassertions MyApp
- 断言失败是致命的、不可恢复的错误;
- 断言检查只是在开发和测试阶段打开。
7.5 日志
// 基本日志
Logger.getGlobal().info("...");
// 取消所有日志
Logger.getGlobal().setLevel(Level.OFF); // SEVERE WARNING INFO / CONFIG FINE FINER FINEST
private static final Logger myLogger = Logger.getLogger("name"); // 未被任何变量引用的日志记录器可能会被垃圾回收,所以用静态变量存储引用
懵
7.6 调试技巧
System.out.println("x=" + x);
Logger.getGlobal().info("x=" + x);
// 打印堆栈轨迹
(Throwable) t.printStachTrace();
Thread.dumpStach();
// 同时捕获System.err和System.out
java MyProgram 1> errors.txt 2>&1 // bash , Windows shell
// 观察类的加载过程
java -verbose
// 编译器找出常见代码问题
javac -Xlint sourceFiles