両方のストリームを閉じるためにclose()
例外を扱うあまりsoくない方法はありますか:
InputStream in = new FileInputStream(inputFileName);
OutputStream out = new FileOutputStream(outputFileName);
try {
copy(in, out);
} finally {
try {
in.close();
} catch (Exception e) {
try {
// event if in.close fails, need to close the out
out.close();
} catch (Exception e2) {}
throw e; // and throw the 'in' exception
}
}
out.close();
}
更新:上記のコードはすべて、警告のおかげでもう1つのtry-catch内にあります。
最後に(答えの後):
そして、 Execute Around idiom (Tom Hawtinに感謝)を使用して、優れたユーティリティメソッドを実行できます。
これは正しいidomです(そして、うまく動作します):
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(inputFileName);
out = new FileOutputStream(outputFileName);
copy(in, out);
finally {
close(in);
close(out);
}
public static void close(Closeable c) {
if (c == null) return;
try {
c.close();
} catch (IOException e) {
//log the exception
}
}
これがうまく機能する理由は、finallyコードが例外をスローしたり、異常終了したりしない限り、finallyに到達する前にスローされた例外が、finallyコードの終了後にスローされるためです。
編集:Java 7(およびAndroid SDK 19-KitKat)の時点で、このクリーナーを作成するためのTry with resources構文があります。対処方法 この質問 で対処されています。
ユーティリティメソッドを実装できます。
public final class IOUtil {
private IOUtil() {}
public static void closeQuietly(Closeable... closeables) {
for (Closeable c : closeables) {
if (c != null) try {
c.close();
} catch(Exception ex) {}
}
}
}
次に、コードは次のようになります。
try {
copy(in, out);
} finally {
IOUtil.closeQuietly(in, out);
}
追加
サードパーティのオープンソースライブラリにこのような方法があると思います。ただし、私の機能は、その機能の大部分を使用していない限り、不要なライブラリの依存関係を回避することです。したがって、私はこのような単純なユーティリティメソッドを自分で実装する傾向があります。
try {
final InputStream in = new FileInputStream(inputFileName);
try {
final OutputStream out = new FileOutputStream(outputFileName);
try {
copy(in, out);
out.flush(); // Doesn't actually do anything in this specific case.
} finally {
out.close();
}
} finally {
in.close();
}
} catch (IOException exc) {
throw new SomeRelevantException(exc);
}
ストリームを開くと例外がスローされる可能性があるため、ストリームのオープニング間にtry
が必要になることに注意してください(null
sに関連するハックは行わないでください。Error
(Exception
のインスタンスではありません).
catch
とfinally
が同じtry
を共有することはほとんどありません。
Java SE 7を使用すると、try-with-resourceを使用してインデントをあまり行わないように書くことができます。隠された例外は抑制されますが、ほぼ同じことを行います。
try (
final InputStream in = new FileInputStream(inputFileName);
final OutputStream out = new FileOutputStream(outputFileName);
) {
copy(in, out);
out.flush(); // Doesn't actually do anything in this specific case.
} catch (IOException exc) {
throw new SomeRelevantException(exc);
}
Execute Around idiom を使用することもできます。
コピーする標準的な良い方法は、NIOのtransferTo
/transferFrom
を使用することだと思います。
Guava には非常に素晴らしいIOこれが不要なAPIがあります。たとえば、あなたの例は:
_Files.copy(new File(inputFileName), new File(outputFileName));
_
より一般的には、InputSupplier
sおよびOutputSupplier
sの概念を使用して、そのユーティリティメソッド内でInputStream
sおよびOutputStream
sを作成できるようにし、完全に制御できるようにします。クローズを適切に処理できるようにします。
さらに、Closeables.closeQuietly(Closeable)
があります。これは、基本的にほとんどの答えが示唆しているメソッドのタイプです。
その中のIOのものはまだベータ版であり、変更される可能性がありますが、作業している内容によっては、チェックアウトして使用する価値があります。
Java 7.0では、ストリームを自分で明示的に閉じる必要はもうありません。 Language Features in Java 7
try (BufferedReader br = new BufferedReader(new FileReader(path)) {
return br.readLine();
}
Java 7なので、Closeable
リソースに関してtry-finallyブロックを書くためのより良い方法があります。 。
次のように、try
キーワードの後に括弧でリソースを作成できます。
try (initialize resources here) {
...
}
そして、コードのブロックが終了すると、それらは閉じられますautomaticallyfinally
部分は必要ありません。
例:
try (
ZipFile zf = new ZipFile(zipFileName);
BufferedWriter writer = Files.newBufferedWriter(outputFilePath, charset);
) {
// Enumerate each entry
for (Enumeration entries = zf.entries(); entries.hasMoreElements();) {
// Get the entry name and write it to the output file
String newLine = System.getProperty("line.separator");
String zipEntryName = ((Java.util.Zip.ZipEntry)entries.nextElement()).getName() + newLine;
writer.write(zipEntryName, 0, zipEntryName.length());
}
}
そして、for
ループが完了すると、リソースは閉じられます!
Commons ioには IOUtils 、いくつかのcloseQuietlyメソッドがあります。
私が時々使うトリックの1つは、引数がnull
かどうかをテストしてから例外を無視してcloseQuietly(Closeable)
というメソッドを定義することです。ただし、実際にはmatters;の例外をスローする可能性があるため、OutputStreamsおよびWritersを慎重に閉じる必要があります。例えば最終フラッシュが失敗した場合。
Java 7.で改善される可能性があります。レポートには、管理対象リソースを処理するより簡潔な方法を提供する新しい構成が含まれます。 。
最後に、例にバグがあることに注意する必要があります。メソッド呼び出しが2番目のストリームを開く場合、最初のストリームは閉じられません。 2番目のオープンは、try
ブロック内で行う必要があります。
ほとんどの場合、 'in' close()例外は無関係です。したがって、
try {
copy(in, out);
} finally {
try { in.close() } catch (Exception e) { /* perhaps log it */ }
try { out.close() } catch (Exception e) {/* perhaps log it */ }
}
例外を飲み込むことは通常悪い習慣ですが、この場合は大丈夫だと思います。
うまくいけば私の答えははるかに良いです
https://stackoverflow.com/a/35623998/25854
try {
fos = new FileOutputStream(new File("..."));
bos = new BufferedOutputStream(fos);
oos = new ObjectOutputStream(bos);
}
catch (Exception e) {
}
finally {
Stream.close(oos,bos,fos);
}
class Stream {
public static void close(AutoCloseable... array) {
for (AutoCloseable c : array) {
try {c.close();}
catch (IOException e) {}
catch (Exception e) {}
}
}
}
使用する
IOUtils.closeNoThrow(myInputStream);
シンプルでエレガント。