java 使用 try-with-resources 安静地关闭资源
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6889697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Close resource quietly using try-with-resources
提问by dogbane
Is it possible to ignore the exception thrown when a resource is closed using a try-with-resources statement?
是否可以忽略使用 try-with-resources 语句关闭资源时抛出的异常?
Example:
例子:
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());
}
}
Or should I continue to close in a finally
instead?
还是我应该继续关闭finally
?
public static void test2(){
MyResource r = null;
try {
r.read();
}
finally{
if(r!=null){
try {
r.close();
} catch (Exception ignore) {
}
}
}
}
采纳答案by dogbane
I found this answered on the coin-dev mailing list: http://mail.openjdk.java.net/pipermail/coin-dev/2009-April/001503.html
我在 coin-dev 邮件列表中找到了这个答案:http: //mail.openjdk.java.net/pipermail/coin-dev/2009-April/001503.html
5. Some failures of the close method can be safely ignored (e.g., closing a file that was open for read). Does the construct provide for this?
No. While this functionality seems attractive, it is not clear that it's worth the added complexity. As a practical matter these “harmless exceptions” rarely if ever occur, so a program will be no more robust if these exceptions are ignored. If you feel you must ignore them, there is a workaround, but it isn't pretty:
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;
}
}
回答by Mark Elliot
You could use a decorator pattern here to close the resource quietly:
您可以在此处使用装饰器模式安静地关闭资源:
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
}
}
}
I'm not personally a fan of the resulting syntax, but maybe this works for you:
我个人不是结果语法的粉丝,但也许这对你有用:
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());
}
}
You can do better if you're willing to limit yourself to dealing with interfaces and leverage a Dynamic Proxy Class:
如果您愿意限制自己处理接口并利用动态代理类,则可以做得更好:
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);
}
}
Then assuming you have:
然后假设你有:
public interface MyReader extends AutoCloseable{
int read();
}
With an actual resource class:
使用实际的资源类:
public class MyResource implements MyReader {
public void close() throws Exception{
throw new Exception("ha!");
}
public int read(){
return 0;
}
}
Calling syntax would look like:
调用语法如下所示:
public static void test(){
try(MyReader r = QuietResource.asQuiet(new MyResource())){
r.read();
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
}
You can do better than this if you want to start including libraries, like AOP enablers. These solutions, however, will work out of the box with JDK7 and no other dependencies.
如果您想开始包含库,例如 AOP 启用程序,您可以做得比这更好。然而,这些解决方案将与 JDK7 一起开箱即用,没有其他依赖项。
回答by irreputable
This is one solution:
这是一种解决方案:
boolean ok=false;
try(MyResource r = new MyResource())
{
r.read();
ok=true;
}
catch (Exception e)
{
if(ok)
; // ignore
else
// e.printStackTrace();
throw e;
}
If ok==true
and we got an exception, it definitely comes from close()
.
如果ok==true
我们有一个例外,它肯定来自close()
.
If ok==false
, e
comes from read()
or constructor. close()
will still be called and may throw e2
, but e2 will be suppressed anyway.
如果ok==false
,e
来自read()
或构造函数。close()
仍然会被调用并且可能会抛出e2
,但是 e2 无论如何都会被抑制。
The code is quite readable without going through such analysis. Intuitively it says, if ok==true
, our real work is done, and we don't really care what errors come after that regarding the resource.
无需经过这样的分析,代码就具有可读性。直观地说,如果ok==true
,我们真正的工作已经完成,我们并不真正关心在资源之后会出现什么错误。