53

私はまた閉じる必要があるいくつかのリソースを作成するいくつかのjunitテストがあります。

このロジックを実装する1つの方法は、@Beforeそして@Afterアプローチ。

私がしたのは、作成したものを再利用できるように何らかのユーティリティクラスにカプセル化することでした。例えば:

class UserCreatorTestUtil implements AutoClosable {
  User create() {...}
  void close() {...}
}

要するに、オブジェクトを閉じることを忘れずに、オブジェクトが自分自身を閉じることです。@After

使い方は次のようになります。

@Test
void test() {
  try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
    User user = userCreatorTestUtil.create();
    // Do some stuff regarding the user's phone
    Assert.assertEquals("123456789", user.getPhone());
  }
}

問題は、junitのassertキーワードがError - ではないException

try-with-resourceは「キャッチ」しますかErrorそしてcloseメソッドを呼び出しますか?

*で答えが見つかりませんでしたtry-with-resourcesのドキュメント


  • OT:レコードのためだけに:"いくつかのリソースを作成するためのjunitテストがあります"あなたは持っていませんUnitTests、あなたが持っているのはモジュールテストを使って単体テスト - フレームワーク。 - Timothy Truckle
  • @TimothyTruckle - 悪魔を摘みながら:いくつかのリソースモックアウトされたバージョンを指すこともあるかもしれませんが、それでもすべてを理解するには閉じておく必要があります。 - Martin Ba
  • エラーと例外(大文字のE)はどちらも例外(小文字のe)です。 - immibis
  • @immibisですが、Throwablesを大文字と小文字を区別しない、あいまいさのないものとすることができます。 - Thilo
  • @ティロしかし、大文字と小文字を区別しない言語は文字通りサタンです。 - immibis

5 답변


74

ありませんcatch何でも。しかしそれはするfinallyすべてのリソースを閉じます。

finallyブロックErrorが投げられても実行される


  • いいえ、例外やエラーについては認識していません。 - Stephan Bijzitter
  • はい、それはマニュアルと同じ方法でそのクリーンアップを行いますfinallyブロックします。 - Thilo
  • を除いてようやくうまくいくことに注意してくださいSystem.exit()stackoverflow.com/questions/14905006/… - Christophe Roussy
  • ふるまいますほとんどのようなfinallyブロックと同じように、finallyブロックすると、それ以降のすべてがキャッチされます。Throwableのsclose()操作を追加し、抑制された1次スロー可能へのスロー可能。 Afinallyそれがあるならば、blockはそれが一次投棄物についての知識を持っていないのでそれをすることができません。 - Holger
  • @ホルガー:まあ、それはとして実装されていますfinallyブロック加えてcatch実際には何もキャッチしないブロック(ただ一次スロー可能オブジェクトを記録して再スローするだけです)。すべての「アクション」 finallyブロックで発生します。詳細は@Nicolasの回答を見てください。 - Thilo

37

基本の擬似コードリソースを使ってみるステートメントは(cfJava Language Specification §14.20.3.1):

final VariableModifiers_minus_final R Identifier = Expression;
Throwable #primaryExc = null;

try ResourceSpecification_tail
    Block
catch (Throwable #t) {
    #primaryExc = #t;
    throw #t;
} finally {
    if (Identifier != null) {
        if (#primaryExc != null) {
            try {
                Identifier.close();
            } catch (Throwable #suppressedExc) {
                #primaryExc.addSuppressed(#suppressedExc);
            }
        } else {
            Identifier.close();
        }
    }
}

ご覧のとおり、キャッチThrowableではないException含まれますErrorしかし主な例外を取得するためだけにリソースのクローズ中に発生した例外を抑制された例外として追加するため。

また、あなたのリソースがfinallyそれを意味するブロック何があってもそれらは閉じられます(を除くSystem.exit当然のことながら、現在実行中のJava仮想マシンは終了します。ErrorまたはのサブクラスThrowableスローされます。


  • 残念ながらjavac文字通り、この複雑な形式仕様に従います。考えてfinally2つのケースではコードの複製を介して最終的に実装されていますが、例外を変数に格納し、それに対してテストすることはまったく意味がありません。null例外があるかどうかにかかわらず、コードパスで既に暗黙のうちに暗示されている場合… - Holger
  • @ホルガー:例外があったかどうかはではないコードパスによって暗示されます。覚えているfinallyブロックは、例外があったかどうかにかかわらず実行されます。どのようなコードの重複を意味しますか。Identifier.close()そしてそれはなぜあなたを悩ませるのですか? try-with-resourcesで代わりに何をすべきですか? - siegi
  • @siegi:バイトコードレベルでは、ありませんfinally機能、したがって、finallyブロックは、そのブロックを離れる可能性のあるすべてのコードパスにアクションをコピーし、さらに例外ハンドラを追加することによってコンパイルされます。try { foo(); } finally { bar(); }にコンパイルされますtry { foo(); } catch(Throwable t) { bar(); throw t; } bar();複製するbar()呼び出しコードそこでは、例外が発生したか否か、すなわち最初のものがコードパスによって暗示される。bar();呼び出しは例外的な条件下でのものであり、2番目はなしのものです。 - Holger
  • @siegi:によって生成されたコードjavacこの結果として、で議論されています。この質問。私の答えでは、私はこの振る舞いを「javac命名せずに「内部的に動作します」finallyこの時点では正式な仕様がわからなかったからといって単純にブロックすることができますが、それを見れば、物事は完全に明確になります(そして一般的な記述は依然として有効です)。 - Holger
  • @ホルガー:ああ、私はバイトコードレベルではなく、Java言語レベルでコードの重複について考えました。でtry-with-resourcesのための特別なケース処理を行わないことは設計上の決定だったと思います。javacしかし単に" desugar"すること。それは言語仕様に従ってそれからJITコンパイラにその仕事をさせます。 - siegi

13

リソースを使ってみても、自分自身では何も捉えられません。

しかし、あなたは添付することができますcatchtry-with-resourcesブロックの最後までブロックします。Throwableあなたが好きです:

try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
  // ... Whatever
} catch (RuntimeException e) {
  // Handle e.
} catch (Exception | Throwable t) {
  // Handle t.
}


9

背後にあるアイデアtry-with-resourcesリソースが閉じられるべきであることを確認することです。

従来の問題try-catch-finally文はあなたのことを想定しましょうtryblockは例外をスローします。通常は、その例外を次のように処理します。finallyブロック。

今度はfinallyブロックでも例外が発生したとします。そのような場合、try catchによってスローされる例外は迷ったそしてで発生した例外finallyブロックは伝播します。

try {
    // use something that's using resource
    // e.g., streams
} catch(IOException e) {
   // handle 
} finally {
    stream.close();
    //if any exception occurs in the above line, than that exception
    //will be propagated and the original exception that occurred
    //in try block is lost.
}

try-with-resourcesclose()リソースのメソッドは自動的に呼び出されます。close()例外をスローします。finally達していない、と元の例外が失われます。

これとは対照的に:

try (InputStream inputStream= new FileInputStream("C://test.txt")){
    // ... use stream
} catch(IOException e) {
   // handle exception
}

上記のコードスニペットでは、close()メソッドは自動的に呼び出されます。close()methodも例外を生成しました。その例外は自動的に抑制されます。

また見なさい:Java言語仕様14.20.3


5

あなたの側での誤解:try-with-resourcesはしますではないするキャッチ

それはする最後の 最後にしたがって、「問題」の種類は関係ありません。

を参照してくださいJLS詳細については!


  • ただし、元の例外がある場合はそれを保持し、後続の例外を抑制された例外として追加できるように、キャッチを行います。 - Mark Rotteveel

リンクされた質問


関連する質問

最近の質問