定义
An exception is an unwanted or unexpected event, which occurs during the execution of a program i.e at run time, that disrupts the normal flow of the program’s instructions.
Java 语言在设计之初就提供了相对完善的异常处理机制,这也是 Java 得以大行其道的原因之一,因为这种机制大大降低了编写和维护可靠程序的门槛。
Error vs Exception
Java exception和Error有什么区别,运行时异常与一般异常有什么区别?
Error: An Error indicates serious problem that a reasonable application should not try to catch.
Exception: Exception indicates conditions that a reasonable application might try to catch.
首先可以看一下Throwable 类图,如下:
可以看出,Exception和Error都继承自Throwable,在Java中只有Throwable类型的实例才可以被抛出(throw)或捕获(catch),它是异常处理机制的基本组成类型。
Exception
Checked Exceptions
正确的程序在运行中,很容易出现的、情理可容的异常状况。除了Exception中的RuntimeException及其子类以外,其他的Exception类及其子类(例如:IOException和ClassNotFoundException)都属于可查异常。
Checked exceptions are exceptions that the Java compiler requires us to handle。
Unchecked Exceptions
包括运行时异常(RuntimeException与其子类)和错误(Error),RuntimeException发生的时候,表示程序中出现了编程错误,所以应该找出错误修改程序,而不是去捕获RuntimeException。
Unchecked exceptions are exceptions that the Java compiler does not require us to handle.
Handling Exceptions
/**
* @exception FileNotFoundException ...
*/
public Scanner(String fileName) throws FileNotFoundException {
...
}
throws
public int getPlayerScore(String playerFile)
throws FileNotFoundException {
Scanner contents = new Scanner(new File(playerFile));
return Integer.parseInt(contents.nextLine());
}
FileNotFoundException 是一个可检测异常,最简单的方式就是抛出。
try–catch
public int getPlayerScore(String playerFile) {
try {
Scanner contents = new Scanner(new File(playerFile));
return Integer.parseInt(contents.nextLine());
} catch (FileNotFoundException noFile) {
throw new IllegalArgumentException("File not found");
}
}
finally
它表示无论是否出现异常,都应当执行的内容。
public int getPlayerScore(String playerFile)
throws FileNotFoundException {
Scanner contents = null;
try {
contents = new Scanner(new File(playerFile));
return Integer.parseInt(contents.nextLine());
} finally {
if (contents != null) {
contents.close();
}
}
}
上面的代码对于一个经验深的人来说,仍旧可能会有问题
public int getPlayerScore(String playerFile) {
Scanner contents;
try {
contents = new Scanner(new File(playerFile));
return Integer.parseInt(contents.nextLine());
} catch (FileNotFoundException noFile ) {
logger.warn("File not found, resetting score.");
return 0;
} finally {
try {
if (contents != null) {
contents.close();
}
} catch (IOException io) {
logger.error("Couldn't close the reader!", io);
}
}
}
因为close本身也是一个高风险的方法,我们也要同时抓取。
Multiple catch Blocks
public int getPlayerScore(String playerFile) {
try (Scanner contents = new Scanner(new File(playerFile))) {
return Integer.parseInt(contents.nextLine());
} catch (IOException e) {
logger.warn("Player file wouldn't load!", e);
return 0;
} catch (NumberFormatException e) {
logger.warn("Player file was corrupted!", e);
return 0;
}
}
上面这段代码有没有问题,如果我修改成下面的代码会怎么样?
public int getPlayerScore(String playerFile) {
try {
Scanner contents = new Scanner(new File(playerFile));
return Integer.parseInt(contents.nextLine());
} catch (Exception e) {
logger.warning("Player file wouldn't load!");
e.printStackTrace();
return 0;
}
}
Union catch Blocks
catch 代码块可以集中一起,如下:
public int getPlayerScore(String playerFile) {
try (Scanner contents = new Scanner(new File(playerFile))) {
return Integer.parseInt(contents.nextLine());
} catch (IOException | NumberFormatException e) {
logger.warn("Failed to load score!", e);
return 0;
}
}
Throwing Exceptions
当出现了异常以后,我们并不知道如何处理时,或者压根就不想处理当前异常时,我看可以使用throws关键词,将异常抛给调用者,让调用者去处理异常。
创建两个可以检查异常,如下:
public class TimeoutException extends Exception {
public TimeoutException(String message) {
super(message);
}
}
Throwing a Checked Exception
public List loadAllPlayers(String playersFile) throws TimeoutException {
while ( !tooLong ) {
...
}
throw new TimeoutException("This operation took too long");
}
如果中间执行时间过长的话,调用者得到异常后可以知道下一步该如何处理。
抛出一个不可检查异常:
public List loadAllPlayers(String playersFile) throws TimeoutException {
if(!isFilenameValid(playersFile)) {
throw new IllegalArgumentException("Filename isn't valid!");
}
return new ArrayList();
}
public boolean isFilenameValid(String f){
return true;
}
public List loadAllPlayers(String playersFile)
throws PlayerLoadException {
try {
...
} catch (IOException io) {
throw new PlayerLoadException(io);
}
}
上面代码是什么意思?
Swallowing Exceptions
public int getPlayerScore(String playerFile) {
try {
// ...
} catch (Exception e) {}
return 0;
}
如果采取这样的话,很可能会引发难以诊断的诡异情况,生吞异常,往往是基于假设这段代码不会发生或者感觉忽略异常是无所谓的。但是如果我们不把异常抛出来,或者没有输出到日志,程序可能在后续的代码以不可控的方式结束。没人能够轻易判断究竟是哪里抛出了异常,以及是什么原因产生了异常。
try {
// 业务代码
// …
} catch (IOException e) {
e.printStackTrace();
}
我们来查看一下printStackTrace() 代码可以看到 "Prints this throwable and its backtrace to the standard error stream."。问在这里,在稍微复杂的生产系统中。
Common Exceptions and Errors
Checked
Checked Exceptions
This exception is typically a way to say that something on the network, filesystem, or database failed.
RuntimeExceptions
ArrayIndexOutOfBoundsException
this exception means that we tried to access a non-existent array index, like when trying to get index 5 from an array of length 3.
ClassCastException
this exception means that we tried to perform an illegal cast, like trying to convert a String into a List. We can usually avoid it by performing defensive instanceof checks before casting.
IllegalStateException
This exception is a generic way for us to say that our internal state, like the state of our object, is invalid.
NullPointerException
This exception means we tried to reference a null object. We can usually avoid it by either performing defensive null checks or by using Optional.
NumberFormatException
This exception means that we tried to convert a String into a number, but the string contained illegal characters, like trying to convert “5f3” into a number.
Errors
StackOverflowError
this exception means that the stack trace is too big. This can sometimes happen in massive applications; however, it usually means that we have some infinite recursion happening in our code.
NoClassDefFoundError
this exception means that a class failed to load either due to not being on the classpath or due to failure in static initialization.
OutOfMemoryError
this exception means that the JVM doesn’t have any more memory available to allocate for more objects. Sometimes, this is due to a memory leak.
参考