目录
异常很有用,能够将错误处理代码从“常规”代码中分离出来。
1、异常层次结构
所有异常都是java.lang.Exceptions的子类,而Exception又是Throwable的子类,Throwable还有一个子类为Errors。如图所示。
2、三种异常
检查型异常:异常必须要被处理,比如使用try捕获异常或者在方法上抛出异常。通常是一些用户可以预测到和期待修改的异常。除了Error、RuntimeException及其子类,其他的都是检查型异常。
运行型异常:运行时异常可以不用被处理,如果发生运行时异常,通常表明对应的api使用不正确。运行时异常包括RuntiemException及它的子类。
错误:错误通常是由硬件或系统故障导致的,因此用户也不必捕获该异常,但是为了通知用户此类异常的方法,也可以选择捕获该异常。错误包含Error和它的子类。
3、try-catch-finally
下面是一个捕获异常的例子,在try语句中的语句用来检测异常,catch捕获异常,finally语句块中代码不管是否try发生异常都会执行。
public void writeList() {
PrintWriter out = null;
try {
System.out.println("Entering" + " try statement");
out = new PrintWriter(new FileWriter("OutFile.txt"));
for (int i = 0; i < SIZE; i++) {
out.println("Value at: " + i + " = " + list.get(i));
}
} catch (IndexOutOfBoundsException e) {
System.err.println("Caught IndexOutOfBoundsException: "
+ e.getMessage());
} catch (IOException e) {
System.err.println("Caught IOException: " + e.getMessage());
} finally {
if (out != null) {
System.out.println("Closing PrintWriter");
out.close();
}
else {
System.out.println("PrintWriter not open");
}
}
}
一个catch也可以同时捕获多个异常,通过|分隔,但是异常类型隐式final:
catch (IOException|SQLException ex) {
logger.log(ex);
throw ex;
}
- 即使try中有return,finally也会别执行。在return语句执行之前,finally语句块会被执行。
- catch和finally,两者可以省略一个。
4、try-with-resources
在try-with-resources的try块中声明的资源在try语句块结束后可以自动关闭,不用手动使用finally关闭了。
public class App
{
public static void main(String[] arg) {
try (BufferedReader br =new BufferedReader(new FileReader("D:\\A.java"))) {
br.readLine();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
需要在try的括号中声明资源,资源对应的类需要实现java.lang.AutoCloseable接口。当try语句执行完或抛出异常时会立刻关闭资源,如果close方法抛出异常,则该异常会被抑制。然后才是捕获异常的步骤。
如果异常被抑制了,可以在catch语句中通过Throwabl的getSuppressed方法获得被抑制的异常,可以看看下面的例子:
public class TryWithResources {
public static void main(String[] args) throws Exception {
try ( OpenDoor door = new OpenDoor() ) {
door.swing(); //this throws a SwingExecption
}
catch (Exception e) {
System.out.println("Is there a draft? " + e.getClass());
int suppressedCount = e.getSuppressed().length;
for (int i=0; i<suppressedCount; i++){
System.out.println("Suppressed: " + e.getSuppressed()[i]);
}
}
finally {
System.out.println("I'm putting a sweater on, regardless. ");
}
}
}
class OpenException extends Exception {}
class SwingException extends Exception {}
class CloseException extends Exception {}
class OpenDoor implements AutoCloseable {
public OpenDoor() throws Exception {
System.out.println("The door is open.");
}
public void swing() throws Exception {
System.out.println("The door is becoming unhinged.");
throw new SwingException();
}
public void close() throws Exception {
System.out.println("The door is closed.");
throw new CloseException(); // throwing CloseException
}
}
5、使用
在编写自己的公有方法时,会时常抛出运行时异常,表明用户错误地使用API。比如传入的参数不正确,会抛出IllegalArgumentException异常。一些常用的运行时异常如下:
- IllegalArgumentException
- IllegalStateException
- NullPointerException
- IndexOutOfBoundsException
- ConcurrentModificationException
- UnsupportedOperationException
如果不满足使用,可以自定义异常。
对于非公有方法,这些方法一般是提供给自己使用的,因此可以不抛出异常,只需要添加注释约定方法的使用方式。
6、异常链
一个异常导致另一个异常,于是组成了异常链,最后抛出的异常链通常包裹着造成该异常的异常。只需要将内部异常传入外部异常构造函数即可。
例子:
class Untitled {
public static void main(String[] args) throws AException{
aMethod();
}
static public void aMethod() throws AException {
try {
throw new BException("B异常抛出");
} catch (BException e) {
throw new AException("A异常抛出;内部异常:"+e.getMessage(),e);
}
}
}
class AException extends Exception{
public AException(String message) {
super(message);
}
public AException(String message, Throwable cause) {
super(message, cause);
}
}
class BException extends Exception{
public BException(String message) {
super(message);
}
public BException(String message, Throwable cause) {
super(message, cause);
}
}
输出:
Exception in thread "main" AException: A异常抛出;内部异常:B异常抛出
at Untitled.aMethod(Untitled.java:9)
at Untitled.main(Untitled.java:3)
Caused by: BException: B异常抛出
at Untitled.aMethod(Untitled.java:7)
... 1 more
参考
https://docs.oracle.com/javase/tutorial/essential/exceptions/index.html
https://www.theserverside.com/tutorial/OCPJP-OCAJP-Java-7-Suppressed-Exceptions-Try-With-Resources
Chained Exceptions in Java