异常屏蔽
直接上代码:
public class Connection implements AutoCloseable {
public void sendData() throws Exception {
throw new Exception("send data");
}
@Override
public void close() throws Exception {
throw new MyException("close");
}
}
public class TryWithResource {
public static void main(String[] args) {
try {
test();
}
catch (Exception e) {
e.printStackTrace();
}
}
private static void test() throws Exception {
Connection conn = null;
try {
conn = new Connection();
conn.sendData();
}
finally {
if (conn != null) {
conn.close();
}
}
}
}
output==>
basic.exception.MyException: close
at basic.exception.Connection.close(Connection.java:10)
at basic.exception.TryWithResource.test(TryWithResource.java:82)
at basic.exception.TryWithResource.main(TryWithResource.java:7)
......
由于我们一次只能抛出一个异常,所以在最上层看到的是最后一个抛出的异常——也就是close方法抛出的MyException,而sendData抛出的Exception被忽略了。这就是所谓的异常屏蔽。由于异常信息的丢失,异常屏蔽可能会导致某些bug变得极其难以发现,程序员们不得不加班加点地找bug,如此毒瘤,怎能不除!幸好,为了解决这个问题,从Java 1.7开始,大佬们为Throwable类新增了addSuppressed方法,支持将一个异常附加到另一个异常身上,从而避免异常屏蔽。那么被屏蔽的异常信息会通过怎样的格式输出呢?我们再运行一遍刚才用try-with-resource包裹的main方法:
public class TryWithResource {
public static void main(String[] args) {
try (Connection conn = new Connection()) {
conn.sendData();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
output==>
java.lang.Exception: send data
at basic.exception.Connection.sendData(Connection.java:5)
at basic.exception.TryWithResource.main(TryWithResource.java:14)
......
Suppressed: basic.exception.MyException: close
at basic.exception.Connection.close(Connection.java:10)
at basic.exception.TryWithResource.main(TryWithResource.java:15)
... 5 more
具体原因是编译器帮我们将一个异常附加到了另一个异常上(var2.addSuppressed(var11)):
public class AppTest {
public AppTest() {
}
public static void main(String[] args) {
try {
AppTest.Connection con = new AppTest.Connection();
Throwable var2 = null;
try {
con.print();
} catch (Throwable var12) {
var2 = var12;
throw var12;
} finally {
if (con != null) {
if (var2 != null) {
try {
con.close();
} catch (Throwable var11) {
var2.addSuppressed(var11);
}
} else {
con.close();
}
}
}
} catch (Exception var14) {
var14.printStackTrace();
}
}
static class Connection implements AutoCloseable {
Connection() {
}
public void print() {
System.err.println("print data==>");
}
public void close() throws Exception {
System.err.println("auto close===>");
}
}
}