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) {
}
}
}
}
私はこれがcoin-devメーリングリストで答えられているのを見つけました: 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;
}
}
ここでデコレータパターンを使用して、リソースを静かに閉じることができます。
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イネーブラーなどのライブラリーを含め始めたい場合は、これよりもうまくいくことができます。ただし、これらのソリューションは、JDK7を使用するだけですぐに機能し、他の依存関係はありません。
これは1つの解決策です:
_ 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
_の場合、実際の作業は完了しており、その後にリソースに関してどのようなエラーが発生するかは気にしません。