例外をスローし、最後にブロック
質問
ああこれまでにない取扱いの例外がスローされる finally
ブロック?
例えば:
try {
// Use the resource.
}
catch( Exception ex ) {
// Problem with the resource.
}
finally {
try{
resource.close();
}
catch( Exception ex ) {
// Could not close the resource?
}
}
どうでしょう try
/catch
の finally
ブロック?
解決
私は通常、このようにそれを実行します。
try {
// Use the resource.
} catch( Exception ex ) {
// Problem with the resource.
} finally {
// Put away the resource.
closeQuietly( resource );
}
このほかます:
protected void closeQuietly( Resource resource ) {
try {
if (resource != null) {
resource.close();
}
} catch( Exception ex ) {
log( "Exception during Resource.close()", ex );
}
}
他のヒント
Iは、典型的にcloseQuietly
のいずれかの方法を使用し、org.apache.commons.io.IOUtils
:
public static void closeQuietly(OutputStream output) {
try {
if (output != null) {
output.close();
}
} catch (IOException ioe) {
// ignore
}
}
は、Java 7、およびresource
道具をAutoClosable
使用している場合、あなたは(例としてInputStreamを使用して)これを行うことができます:
try (InputStream resource = getInputStream()) {
// Use the resource.
}
catch( Exception ex ) {
// Problem with the resource.
}
トップオーバーおそらく少し、多分に便利、あなたは例外バブルアップをさせるていると、あなたの方法の中から何かをログに記録することができない場合(例えば、それは図書館だとするのではなく、呼び出し元のコードハンドルの例外をさせたいので、とログ):
Resource resource = null;
boolean isSuccess = false;
try {
resource = Resource.create();
resource.use();
// Following line will only run if nothing above threw an exception.
isSuccess = true;
} finally {
if (resource != null) {
if (isSuccess) {
// let close throw the exception so it isn't swallowed.
resource.close();
} else {
try {
resource.close();
} catch (ResourceException ignore) {
// Just swallow this one because you don't want it
// to replace the one that came first (thrown above).
}
}
}
}
UPDATE:私はもう少し、このに見て、明らかに私よりもっとこのことについて考えた人からの偉大なブログ記事を見つけました:<のhref = "http://illegalargumentexception.blogspot.com/2008/10/java - どのよう-ないツー・混乱・オブ・stream.html作る」のrel = "noreferrer"> http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of -stream.html の彼は、さらに一歩進んで、私はいくつかのケースで有用である見ることができた1、に2つの例外を兼ね備えています。
のJava 7のとして、あなたは、もはやを最後にのブロック内で明示的に近いリソースの代わりに使用すると、を試すの -with-リソースの構文を使用することができますする必要があります。 try-と、リソースのステートメントは、1つ以上のリソースを宣言するtry文です。リソースは、プログラムがそれを終了した後に閉じなければならない対象です。 try-と資源の文は、各リソースは、文の最後に閉じられていることを保証します。 java.io.Closeableを実装するすべてのオブジェクトを含むjava.lang.AutoCloseableを実装する任意のオブジェクトは、リソースとして使用することができる。
次のコードを想定します:
try( Connection con = null;
Statement stmt = con.createStatement();
Result rs= stmt.executeQuery(QUERY);)
{
count = rs.getInt(1);
}
いずれかの例外が発生した場合は、閉じるの方法は、それらが作成された逆の順序でこれらの3つのリソースのそれぞれに呼び出されます。これは、closeメソッドは、文およびConnectionオブジェクトの末尾にResultSetmために最初に呼び出されることになることを意味する。
これは、closeメソッドが自動的に呼び出されたときに発生する例外が抑制されていることを知ることも重要です。これらの抑制例外はのThrowableののクラスで定義されたのgetsuppressed()の方法により取得することができます。
ソース: https://docs.oracle.com/javase/チュートリアル/不可欠/例外/ tryResourceClose.htmlする
1は、これらの例外がどうなるか、彼らが表現するどのような条件を知っていない限り、「最終的には」ブロックが一般的である<私>は悪いアイデアで発生した例外を無視します。通常のtry/finally
使用パターンでは、try
ブロックは、外部のコードが期待されることはありません状態に物事を置き、そしてfinally
ブロックは、外部のコードが期待するものにそれらの事の状態を復元します。例外をキャッチし、社外のコードは、一般的に例外にもかかわらず、すべてがnormal
状態に復元された、ことを期待しています。例えば、いくつかのコードは、トランザクションを開始してから2件のレコードを追加しようとしたとし、 「最終的には」ブロックの動作を「コミットしていない場合は、ロールバック」を行います。呼び出し側は、第二の「追加」操作の実行中に発生した例外のために準備されるかもしれない、それは、そのような例外をキャッチした場合、データベースはどちらかの操作を試みた前にそれがあった状態になることを期待します。しかし、2番目の例外は、ロールバック中に発生した場合、発信者は、データベースの状態についての仮定を行った場合、悪いことが起こる可能性があります。ロールバックの失敗は、<私>の主要なの危機を表し、 - 単なるを期待コードでキャッチすべきではない一つの例外「のレコードを追加できませんでした」
私の個人的な傾きは、このような障害が大きな問題を表しており、このような例外が軽くキャッチすべきではないことを認識し、発生し、最終的方法キャッチ例外を持っており、「CleanupFailedException」でそれらをラップすることです。
一つの解決策、2つの例外は、2つの異なるクラスがある場合は、
try {
...
}
catch(package1.Exception err)
{
...
}
catch(package2.Exception err)
{
...
}
finally
{
}
しかし、時には、あなたは、この第2ののtry-catchを避けることができません。例えばストリームを閉じる
InputStream in=null;
try
{
in= new FileInputStream("File.txt");
(..)// do something that might throw an exception during the analysis of the file, e.g. a SQL error
}
catch(SQLException err)
{
//handle exception
}
finally
{
//at the end, we close the file
if(in!=null) try { in.close();} catch(IOException err) { /* ignore */ }
}
なぜあなたは追加のブロックを避けるためにしたいですか? finallyブロックは、例外をスローすることが「普通」の操作が含まれており、最終的に実行するためにブロックしたいので、完全にあなたは、例外をキャッチする必要があります。
あなたが期待していない場合は、最終的に例外をスローするようにブロックし、あなたがとにかく例外を処理する方法がわからない(コールスタックを例外バブルをアップしてみましょうのtry-catchを削除する(あなただけのスタックトレースをダンプします) )finallyブロックから。
あなたはあなたの入力を減らしたい場合はfinallyブロックでスローされたすべての例外をキャッチする「グローバル」外側のtry-catchブロックを、実装することができます:
try {
try {
...
} catch (Exception ex) {
...
} finally {
...
}
try {
...
} catch (Exception ex) {
...
} finally {
...
}
try {
...
} catch (Exception ex) {
...
} finally {
...
}
} catch (Exception ex) {
...
}
後に多くの配慮を見せていただいたのですが、次のコードベスト:
MyResource resource = null;
try {
resource = new MyResource();
resource.doSomethingFancy();
resource.close();
resource = null;
} finally {
closeQuietly(resource)
}
void closeQuietly(MyResource a) {
if (a!=null)
try {
a.close();
} catch (Exception e) {
//ignore
}
}
を用いることを保証:
- リソースが解放されたが、コードの完成
- スローされる例外を閉じる際のリソースを消費せずに処理します。
- このコードなの資源回、不必要な例外を作成します。
あなたはそもそもエラー状態を回避するためにテストする必要がありますすることができます。
try{...}
catch(NullArgumentException nae){...}
finally
{
//or if resource had some useful function that tells you its open use that
if (resource != null)
{
resource.Close();
resource = null;//just to be explicit about it was closed
}
}
また、あなたはおそらく唯一のあなたはそれがあなたのプログラムのトップレベルに伝播させ、その後回復できない場合は、から回復する可能性のある例外をキャッチする必要があります。あなたは(私はまだ具体的な、期待のエラーをキャッチお勧めだろうが)あなたがすでに行っているように。
のtry catchブロックでコードを囲む必要がありますエラー状態をテストすることができない場合あなたは他の方法にこれをリファクタリングでき...
public void RealDoSuff()
{
try
{ DoStuff(); }
catch
{ // resource.close failed or something really weird is going on
// like an OutOfMemoryException
}
}
private void DoStuff()
{
try
{}
catch
{
}
finally
{
if (resource != null)
{
resource.close();
}
}
}
私は通常これを行います
MyResource r = null;
try {
// use resource
} finally {
if( r != null ) try {
r.close();
} catch( ThatSpecificExceptionOnClose teoc ){}
}
理由:私は、リソースと、私はそれを閉じているだけの問題で終わりだ場合、私はそれについて行うことができます多くはありません。私はとにかくリソースで行われていた場合、それは全体のスレッドを殺すためにどちらかの意味がありません。
これは、少なくとも私にとって、例外をチェックすることは無視しても安全であるとき、例1である。
は、この日に、私はこのイディオムを使用しても問題ありませんでした。
try {
final Resource resource = acquire();
try {
use(resource);
} finally {
resource.release();
}
} catch (ResourceException exx) {
... sensible code ...
}
求人行わ。ヌルのテストはありません。シングルキャッチ、取得した例外を解放します。もちろん、イディオムの周りに実行し、唯一の各リソースタイプのため、一度にそれを記述する必要がありますを使用することができます。
<のhref = "https://docs.oracle.com/に最良の答えするからResource
変更Java SE / 7 /ドキュメント/ API / Javaの/ IO / Closeable.html」のrel = "nofollowをnoreferrer"> Closeable
の
ストリーム実装は<=>したがって、あなたは、すべてのストリームのための方法を再利用することができます。
protected void closeQuietly(Closeable resource) {
if (resource == null)
return;
try {
resource.close();
} catch (IOException e) {
//log the exception
}
}