是否可以忽略使用try-with-resources语句关闭资源时抛出的异常?
示例:
class MyResource implements AutoCloseable{
@Override
public void close() throws Exception {
throw new Exception("Could not close");
}
public void read() throws Exception{
}
}
//this method prints an exception "Could not close"
//I want to ignore it
public static void test(){
try(MyResource r = new MyResource()){
r.read();
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
}或者我应该继续在finally中关闭?
public static void test2(){
MyResource r = null;
try {
r.read();
}
finally{
if(r!=null){
try {
r.close();
} catch (Exception ignore) {
}
}
}
}发布于 2011-07-31 22:49:19
我在硬币开发邮件列表上找到了答案:http://mail.openjdk.java.net/pipermail/coin-dev/2009-April/001503.html
5.可以安全地忽略close方法的某些故障(例如,关闭已打开以进行读取的文件)。该构造是否提供了此功能?
不是的。虽然这个功能看起来很吸引人,但它是否值得增加复杂性还不清楚。作为一个实际问题,这些“无害的异常”很少发生,所以如果这些异常被忽略,程序将不会更健壮。如果你觉得你必须忽略它们,有一个变通方法,但它不是很好:
static void copy(String src, String dest) throws IOException {
boolean done = false;
try (InputStream in = new FileInputStream(src)) {
try(OutputStream out = new FileOutputStream(dest)) {
byte[] buf = new byte[8192];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
}
done = true;
} catch(IOException e) {
if (!done)
throw e;
}
}发布于 2011-07-31 21:27:53
你可以在这里使用一个装饰器模式来悄悄地关闭资源:
public class QuietResource<T extends AutoCloseable> implements AutoCloseable{
T resource;
public QuietResource(T resource){
this.resource = resource;
}
public T get(){
return resource;
}
@Override
public void close() {
try {
resource.close();
}catch(Exception e){
// suppress exception
}
}
}我个人并不喜欢由此产生的语法,但这可能对您有效:
public static void test(){
try(QuietResource<MyResource> qr = new QuietResource<>(new MyResource())){
MyResource r = qr.get();
r.read();
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
}如果您愿意将自己限制在处理接口并利用动态代理类,那么您可以做得更好:
public class QuietResource<T> implements InvocationHandler {
private T resource;
@SuppressWarnings("unchecked")
public static <V extends AutoCloseable> V asQuiet(V resource){
return (V) Proxy.newProxyInstance(
resource.getClass().getClassLoader(),
resource.getClass().getInterfaces(),
new QuietResource<V>(resource));
}
public QuietResource(T resource){
this.resource = resource;
}
@Override
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
if(m.getName().equals("close")){
try {
return m.invoke(resource, args);
}catch(Exception e){
System.out.println("Suppressed exception with message: " + e.getCause().getMessage());
// suppress exception
return null;
}
}
return m.invoke(resource, args);
}
}然后假设你有:
public interface MyReader extends AutoCloseable{
int read();
}使用实际的资源类:
public class MyResource implements MyReader {
public void close() throws Exception{
throw new Exception("ha!");
}
public int read(){
return 0;
}
}调用语法将如下所示:
public static void test(){
try(MyReader r = QuietResource.asQuiet(new MyResource())){
r.read();
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
}如果您想要开始包含库,比如AOP enablers,那么您可以做得更好。然而,这些解决方案将与JDK7一起开箱即用,并且没有其他依赖项。
发布于 2011-07-31 21:55:14
这是一种解决方案:
boolean ok=false;
try(MyResource r = new MyResource())
{
r.read();
ok=true;
}
catch (Exception e)
{
if(ok)
; // ignore
else
// e.printStackTrace();
throw e;
}如果ok==true和我们得到了一个异常,它肯定来自close()。
如果为ok==false,则e来自read()或构造函数。close()仍然会被调用,并且可能抛出e2,但e2无论如何都会被禁止。
无需经过这样的分析,代码的可读性非常好。直观地说,如果是ok==true,我们真正的工作就完成了,我们并不关心在那之后会发生什么关于资源的错误。
https://stackoverflow.com/questions/6889697
复制相似问题