Java Exception
Java Exception
java中在处理Exception中经常出现异常的丢失问题,比如下面的代码
package com.viashare.exception;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by Jeffy on 15/04/13.
*/
public class FailExceptionMain {
public static void main(String[] args) throws WrapperException {
InputStream input = null;
try{
input = new FileInputStream("test.txt");
} catch(IOException e){
e.printStackTrace();
throw new WrapperException(e);
} finally {
try{
input.close();
} catch(IOException e){
throw new WrapperException(e);
}
}
}
static class WrapperException extends Exception{
private Exception exception;
public WrapperException(Exception exception) {
this.exception = exception;
}
}
}
上面的例子中假设 test.txt 文件不存在的话,那么在第一个catch块中catch住这个异常,但是因为有finally块,所以在抛出异常之前,执行了input.close();,因为文件不存在,所以在执行 input.close() 时抛出NullPointerException,然而catch的是IOException 所以异常丢失,下面是输出的结果:
Exception in thread "main" java.lang.NullPointerException
at com.viashare.exception.FailExceptionMain.main(FailExceptionMain.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
为了更好的处理类问题,我们需要认真的判断这个非空。
package com.viashare.exception;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by Jeffy on 16/04/13.
*/
public class FailExceptionMain {
public static void main(String[] args) throws WrapperException {
InputStream input = null;
try{
input = new FileInputStream("test.txt");
} catch(IOException e){
// e.printStackTrace();
throw new WrapperException(e);
} finally {
try{
if(null!=input)
input.close();
} catch(IOException e){
throw new WrapperException(e);
}
}
}
static class WrapperException extends Exception{
private Exception exception;
public WrapperException(Exception exception) {
this.exception = exception;
}
}
}
但即使这个异常处理也有问题。让我们假设文件存在,所以“input”引用现在指向一个有效的FileInputStream。我们还假装在处理输入流时抛出异常。该异常被捕获在catch(IOException e)块中。然后被包裹并重新抛出。在包裹的异常传播到调用堆栈之前,finally子句被执行。如果input.close()调用失败,并抛出IOException,那么它被捕获,包装和重新抛出。但是,当从finally子句抛出包装的异常时,再次忘记了从第一个catch块抛出的包装异常。它消失了只有从第二个catch块抛出的异常在调用堆栈中传播。
如您所见,失败的安全异常处理并不总是微不足道的。 InputStream处理示例甚至不是您可以遇到的最复杂的例子。 JDBC中的事务有更多错误的可能性。当尝试提交,然后回滚,最后当您尝试关闭连接时,可能会发生异常。所有这些可能的异常都应该由异常处理代码来处理,所以它们都不会抛出第一个异常消失。一种方法是确保抛出的最后一个异常包含以前抛出的所有异常。这样他们都可以向开发人员调查错误原因。这就是我们的Java持久化API Persister先生实现事务异常处理的方式。