Метод JDK 1.7 Throwable ' addSuppressed ()'

Ну, я получаю через связанные вопросы, я читаю исходный код JDK 1.7, но я не нахожу ответа.

в этом вопросе я хочу полностью игнорировать fillInStackTrace.

начиная с JDK 1.4 initCause() добавлен метод. Например, при использовании отражения ядра для вызова метода, который получает InvocationTargetException с причиной, имеющей целевое исключение в нем.

когда я увидел эту функцию, я начал использовать его также в сценарии как это

    try {
        //contains some code that can throw new IOException();
    }
    catch(IOException e){
        throw new RuntimeException(e);
    }

Итак, я ловлю исключение, я не готов иметь дело с ним здесь, и я переосмысливаю новое исключение, где у меня есть оригинальное исключение в качестве причины. В некоторых сценарных не RuntimeException, но мое пользовательское исключение используется, поэтому иногда я также вызываю e.getCause() для правильной обработки этого исключения во внешнем блоке.

это ситуация в pre JDK 1.7. Почему и когда я должен использовать addSuppressed()? Должен ли я изменить код выше к

    try {
        //contains some code that can throw new IOException();
    }
    catch(IOException e){
        RuntimeException re= new RuntimeException(e.getMessage());
        re.addSuppressed(e);
        throw re;
    }

и в качестве бонуса вопрос, почему не addSuppressed() возвращение Throwable as initCause() позволяет throw (RuntimeException)new RuntimeException().initCause(e);? Например, почему я не могу?:

    try {
        //contains some code that can throw new IOException();
    }
    catch(IOException e){
        throw (RuntimeException)new RuntimeException(e.getMessage()).addSuppressed(e);
    }

я извлек ответ на отдельный пост.

2 ответов


В общем, Throwable addSuppressed() метод должен использоваться, когда в некотором роде у нас есть параллельно выполнение которого может произвести исключение, что где подавленные. Я нашел 2 примера;

  • блок Try-with-resource (блок try-finally), когда вызывающий код увидит исходное исключение (в блоке try или catch) и исключение, которое произошло в блоке finally.

  • пакетные задания (Навальный операции), когда мы должны перейти к следующему элементу, независимо от того, была ли операция над текущим элементом успешной или нет

прежде чем перейти к деталям, как заявил @sarelbotha, в моем случае я просто должен продолжать обертывать исходное исключение как причину моего нового исключения.

поведение по умолчанию в блоке try-finally, где у нас есть 2 исключения, исходное исключение -подавленные и мы видим только исключение из finally block. Если мы используем finally block Для закрытия ресурса, мы действительно хотим видеть исходное исключение, но, возможно, мы хотим видеть также исключения из finally block, которые закрыли наш ресурс и терпят неудачу.

начиная с выпуска 7 платформа поддерживает понятие подавленных исключений (в сочетании с инструкцией try-with-resources). Все исключения, которые были подавлены для доставки исключения, распечатываются под трассировкой стека.

http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html#printStackTrace%28%29

сначала следует прочитать о новой функции try-with-resource. Вы можете прочитать его здесь http://www.baptiste-wicht.com/2010/08/java-7-try-with-resources-statement/ например или здесь что такое эквивалент байт-кода Java 7 try-with-resources с использованием try-catch-finally?. Короче говоря, вы можете иметь 2 Throwable параллельно в некоторый смысл, как правило, от вас пытаются блокировать и от вашего наконец блока. Старая семантика try-catch вернет исключение из блока finally whule подавленные исключение из блока try (или перестроение исключения из блока catch). Новая функция try-with-resource позволяет получить оба исключения. Более того, вы получите оригинальное исключение, где исключение из блока finally будет подавленные

обратите внимание, что, когда один исключение вызывает другое исключение, первое исключение обычно ловится, а затем в ответ возникает второе исключение. Другими словами, между двумя исключениями существует причинная связь. В отличие от этого, существуют ситуации, когда два независимых исключения могут быть брошены в блоках кода брата, в частности в блоке try оператора try-with-resources и сгенерированном компилятором блоке finally, который закрывает ресурс. В этих ситуациях только одно из брошенных исключений может быть распространены. В инструкции try-with-resources при наличии двух таких исключений распространяется исключение, исходящее из блока try, и исключение из блока finally добавляется в список исключений, подавляемых исключением из блока try. Когда исключение разматывает стек, оно может накапливать несколько подавленных исключений.

пример:

    public class TestClass {
static class ResourceA implements AutoCloseable{
      public void read() throws Exception{
        throw new Exception("ResourceA read exception");
      }
      @Override
      public void close() throws Exception {
        throw new Exception("ResourceA close exception");
      }
    };

static class ResourceB implements AutoCloseable{
      public void read() throws Exception{
        throw new Exception("ResourceB read exception");
      }
      @Override
      public void close() throws Exception {
        throw new Exception("ResourceB close exception");
      }
    };

    //a test method
    public static void test() throws Exception{
      try (ResourceA a = new ResourceA();
           //ResourceB b = new ResourceB()
              ) {
        a.read();
        //b.read();
      } catch (Exception e) {
        throw e;
      }
    }

    public static void main(String[] args)  throws Exception {
        test();
    }

}

выход будет следующий:

Exception in thread "main" java.lang.Exception: ResourceA read exception
at TestClass$ResourceA.read(TestClass.java:6)
at TestClass.test(TestClass.java:29)
at TestClass.main(TestClass.java:39)
Suppressed: java.lang.Exception: ResourceA close exception
    at TestClass$ResourceA.close(TestClass.java:10)
    at TestClass.test(TestClass.java:31)
    ... 1 more

пакетные задания (массовые операции). Ну, я нашел некоторое использование этого метода вне try-with-resources. Ниже приведен исходный код из java.net.URLClassLoader.close

 public void close() throws IOException {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkPermission(new RuntimePermission("closeClassLoader"));
    }
    List<IOException> errors = ucp.closeLoaders();
    // now close any remaining streams.
    synchronized (closeables) {
        Set<Closeable> keys = closeables.keySet();
        for (Closeable c : keys) {
            try {
                c.close();
            } catch (IOException ioex) {
                errors.add(ioex);
            }
        }
        closeables.clear();
    }
    if (errors.isEmpty()) {
        return;
    }
    IOException firstex = errors.remove(0);
    // Suppress any remaining exceptions
    for (IOException error: errors) {
        **firstex.addSuppressed(error);**
    }
    throw firstex;
}

В общем, такой подход можно использовать в пакетные задания (массовые операции), когда мы должны перейти к следующему элементу (закрытие следующих открытых потоков, как в этом примере), независимо от того, была ли операция над текущим элементом успешной или нет. В таких способ, как я уже говорил, в некотором роде параллельно выполнение которого может произвести исключение, что где подавленные. В таких случаях мы должны использовать подход выше, чтобы бросить на исключение с оставшимся подавленным исключением в нем.


подавленные исключения будут сохранены, если код, выполняемый в блоке finally, выдает исключение. Это исключение, которое произошло, что вы, вероятно, не волнует. В Java 6 такое исключение в блоке finally станет единственным исключением, которое увидит ваш вызывающий код, но с новым блоком try-with-resource ваш вызывающий код увидит исходное исключение, и исключение, которое произошло в виртуальном блоке finally, будет в getSuppressed().

в вашем случае просто продолжайте обертывать исходное исключение как причину вашего нового исключения.