异常、断言和日志
1. 处理错误
- 用户输入错误
- 设备错误
- 物理限制
- 代码错误
1.1 异常分类
在 Java 中,异常对象都是派生于Throwable
类的一个实例。
需要注意的是,所有的异常都是由Throwable
继承而来,但在下一层立即分解为两个分支:Error
和Exception
。
Error
类层次结构描述了 Java 运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。如果出现了这样的内部情况,只能通告给用户,并尽力使程序安全的终止,再无能为力了。
Exception
类层次结构又可以分解为两个分支:一个分支派生于RuntimeException
,另一个分支包含其他异常,划分规则是:由程序错误导致的异常属于RuntimeException
,而程序本身没有问题,但由于像I/O
错误这类问题导致的异常属于其他异常。
1.2 声明受查异常
对于那些可能被他人使用的 Java 方法,应该根据异常规范(exception specification),在方法的首部声明这个方法可能抛出的异常:
class MyAnimation {
...
public Image loadImage(String s) throws IOException {
...
}
}
如果有可能抛出多个受查异常类型,那么就必须在方法的首部列出所有的异常类,每个异常类之间用逗号隔开:
class MyAnimation {
...
public Image loadImage(String s) throws FileNotFoundException, EOFException {
...
}
}
但是,不需要声明 Java 的内部错误,即从
Error
继承的错误。任何程序代码都具有抛出那些异常的可能,而我们对其也没有任何控制能力
1.3 如何抛出异常
throw new EOFException();
// 或者
EOFException e = new EOFException();
throw e;
在异常类中抛出异常:
String readData(Scanner in) throws EOFException {
...
while (...) {
if (!in.hasNext()) { // EOF encountered
if (n < len)
throw new EOFException();
}
...
}
return s;
}
1.4 创建异常类
class FileFormatException extends IOException {
public FileFormatException() {}
public FileFormatException(String gripe) {
super(gripe);
}
}
2. 捕获异常
2.1 如何捕获异常
如果某个异常发生的时候没有在任何地方进行捕获,那么程序就会终止执行,并在控制台上打印出异常信息,其中包括异常的类型和堆栈的内容。
try {
code
more code
} catch (Exception e) {
handler for this type
}
如果在try
语句块中的任何代码抛出了一个在catch
子句中说明的异常类,那么:
- 程序将跳过
try
语句块的其余代码 - 程序将执行
catch
子句中的handler
代码
如果在try
语句块中的代码没有抛出任何异常,那么程序将跳过catch
子句。
如果方法中的任何代码抛出了一个在catch
子句中没有声明的异常类型,那么这个方法就会立刻退出。
public void read(String filename) {
try {
InputStream in = new FileInputStream(filename);
int b;
while ((b = in.read()) != -1) {
// process input
}
} catch (IOException e) {
e.printStackTrace();
}
}
还可以什么都不做,将异常传递给调用者,这样就必须声明这个方法可能会抛出一个IOException
:
public void read(String filename) throws IOException {
InputStream in = new FileInputStream(filename);
int b;
while ((b = in.read()) != -1) {
// process input
}
}
Java 编译器严格的执行
throws
说明符。如果调用了一个抛出受查异常的方法,就必须对它进行处理,或者继续传递
2.2 捕获多个异常
在一个try
语句块中可以捕获多个异常类型,并对不同类型的异常做出不同的处理:
try {
// some code
} catch (FileNotFoundException e) {
// handle exception
} catch (UnknownHostException e) {
// handle exception
} catch (IOException e) {
// handle exception
}
还可以通过以下语句获得对象的更多信息:
e.getMessage();
e.getClass().getName();
在 Java SE 7 中,同一个catch
子句中可以合并多个异常类型:
try {
// some code
} catch (FileNotFoundException | UnknownHostException e) {
// handle exception
} catch (IOException e) {
// handle exception
}