web-dev-qa-db-ja.com

抑制された例外とは何ですか?

answer に対する 末尾呼び出しの最適化に関する質問 に関するコメント(ユーザーによる soc )Java 7には、「ARMの追加」のために、「抑制された例外」と呼ばれる新しい機能があります(ARM CPUsのサポート?)。

このコンテキストでの「抑制された例外」とは何ですか?他のコンテキストでは、「抑制された例外」は、キャッチされて無視された例外です(まれに良い考えです)。これは明らかに異なるものです。

65
Raedwald

コメンターが言及しているのは、既存のコンテキストで try-with-resources ブロックの暗黙的なfinallyブロック内でスローされた場合に半無視される例外であると思いますtryブロックからスローされる例外:

Try-with-resourcesステートメントに関連付けられたコードブロックから例外をスローできます。 writeToFileZipFileContentsの例では、tryブロックから例外をスローできます。また、ZipFileオブジェクトとBufferedWriterオブジェクトを閉じようとしたときに、try-with-resourcesステートメントから最大2つの例外をスローできます。 tryブロックから例外がスローされ、try-with-resourcesステートメントから1つ以上の例外がスローされる場合、try-with-resourcesステートメントからスローされる例外は抑制され、ブロックによってスローされる例外が1つになります。 writeToFileZipFileContentsメソッドによってスローされます。 tryブロックによってスローされた例外からThrowable.getSuppressedメソッドを呼び出すことで、これらの抑制された例外を取得できます。

(リンクされたページから「抑制された例外」と呼ばれるセクションを引用しています。)

50
Jon Skeet

Jonの答えの引用を明確にするために、メソッドによって(実行ごとに)スローされる例外は1つだけですが、try-with-resourcesの場合、複数の例外がスローされる可能性があります。たとえば、1つはブロック内でスローされ、もう1つはtry-with-resourcesによって提供される暗黙のfinallyからスローされます。

コンパイラは、これらのどれを「実際に」スローするかを決定する必要があります。暗黙的なコード(tryブロック)によってスローされる例外ではなく、明示的なコード(finallyブロック内のコード)で発生した例外をスローすることを選択します。したがって、暗黙ブロックでスローされた例外は抑制されます(無視されます)。これは、複数の例外の場合にのみ発生します。

56
John B

Java7より前。コードには例外がスローされますが、どういうわけか無視されました。

例えば。)

public class SuppressedExceptions {
  public static void main(String[] args) throws Exception {
    try {
        callTryFinallyBlock();
    } catch (Exception e) {
        e.printStackTrace(); **//Only Finally Exception is Caught**
    }
  }

  private static void callTryFinallyBlock() throws Exception {
    try 
    {
        throw new TryException(); **//This is lost**
    }
    finally
    {
        FinallyException fEx = new FinallyException();
        throw fEx;
    }
  }
}

class TryException extends Exception {
}

class FinallyException extends Exception {
}

新しいコンストラクターと2つの新しいメソッドがJDK 7のThrowableクラスに追加されました。これらは次のとおりです。

Throwable.getSupressed(); // Returns Throwable[]
Throwable.addSupressed(aThrowable);

この新しいアプローチにより、抑制された例外も処理できます。

public class SuppressedExceptions {
  public static void main(String[] args) throws Exception {
    try {
        callTryFinallyBlock();
    } catch (Exception e) {
        e.printStackTrace();
        for(Throwable t: e.getSuppressed())
        {
            t.printStackTrace();
        }
    }
  }

  private static void callTryFinallyBlock() throws Exception {
    Throwable t = null;
    try 
    {
        throw new TryException();
    }
    catch (Exception e) {
        t = e;
    }
    finally
    {
        FinallyException fEx = new FinallyException();
        if(t != null)fEx.addSuppressed(t);
        throw fEx;
    }
  }
}

class TryException extends Exception {
}

class FinallyException extends Exception {
}

Java7では、try-with-resources; AutoCloseable :: close()の例外は、try例外とともにデフォルトで抑制された例外として追加されます。

また、これは 連鎖例外 とは異なることに注意してください(JDK 1.4で導入され、例外間の因果関係を簡単に追跡できるようにすることを目的としていました)。

17

抑制された例外 は、try-with-resourcesステートメント内で発生する追加の例外です( Java 7 で導入) AutoCloseable リソースが閉じられています。AutoCloseableリソースを閉じるときに複数の例外が発生する可能性があるため、追加の例外が 抑制された例外としてのプライマリ例外 に付加されます。

Try-with-resourcesサンプルコードのバイトコードを見ると、標準の JVM例外ハンドラ がtry-with-resourcesセマンティクスに対応するために使用されています。

9
Dan Cruz

以下のコードを認める:

public class MultipleExceptionsExample {

   static class IOManip implements Closeable{
       @Override
       public void close() {
           throw new RuntimeException("from IOManip.close");
       }
   }

   public static void main(String[] args) {
       try(IOManip ioManip = new IOManip()){
           throw new RuntimeException("from try!");
       }catch(Exception e){
           throw new RuntimeException("from catch!");
       }finally{
           throw new RuntimeException("from finally!");
       }
   }
}

すべての行で次のようになります:Java.lang.RuntimeException: from finally!

finallyブロックを削除すると、次の結果が得られます:Java.lang.RuntimeException: from catch!

catchブロックを削除すると、次の結果が得られます。

Exception in thread "main" Java.lang.RuntimeException: from try!
    Suppressed: Java.lang.RuntimeException: from IOManip.close
6
Adil

これは「連鎖例外機能」に関係していると思います。スタックトレースが進化するにつれて、この機能による例外の処理方法に影響します。連鎖した例外のグループの一部である時間の経過した例外は抑制できます。詳細については、 Throwable documentation をご覧ください。

ARM-自動リソース管理(Java 7)以降導入

非常に単純な例を取り上げます

_static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}
_

readLine()関数がExceptionをスローし、さらにclose() function [in finally block]が例外をスローした場合、後者の優先度が高くなり、呼び出し元の関数にスローバックされます。この場合、Exception thrown by the readLine() method is ignored/suppressed。例外の原因となっている例外を連鎖させ、finallyブロックから例外を再スローできます。

抑制された例外を取得する_Java 7_機能が提供されているため。キャッチされたスロー可能オブジェクトでpublic final Java.lang.Throwable[] getSuppressed()関数を呼び出して、抑制された例外を表示できます。

例えば.

_static String readFirstLineFromFileWithFinallyBlock(String path)
        throws Exception {
    try (BufferedReader br = new BufferedReader(new FileReader(path));) {
        return br.readLine();
    }
}
_

br.readLine();行が_Exception1_をスローし、リソースを閉じるときに_Exception2_がスローされる場合Exception1は、Exception2を抑制します。

ここで注意すべき点はほとんどありません-

  1. Try-with-resourceブロックが例外をスローした場合、つまりリソー​​スのインスタンス化中にtryブロックが実行されず、同じ例外がスローされます。
  2. リソースのインスタンス化が成功すると、tryブロックは例外をスローし、リソースを閉じるときに例外がスローされ、リソースを閉じるときにスローされる例外はtryブロックからスローされる例外によって抑制されます。
  3. 最終ブロックを明示的に指定し、そのブロックから例外がスローされると、他のすべての例外が抑制されます。 (この明示的なfinallyブロックは、リソースが閉じられた後に実行されます)

次の投稿で、コードスニペットと出力を使用して、考えられるシナリオのほとんどをコンパイルしました。

Java 7 で抑制された例外

お役に立てば幸いです。

0
Aniket Thakur

Java 6でも例外を抑制することができます(少し手間がかかります)、

Java 1.6およびJava 1.7。実装を見つけることができます here

必要なのは、電話するだけです:

public static <T extends Throwable> T suppress(final T t, final Throwable suppressed) 

例外を抑制する

public static Throwable [] getSuppressed(final Throwable t) {

誰かがまだJava 1.6を使用している場合、例外の抑制された例外を取得する

0
user2179737