Что такое исключенное исключение?

В комментарии (от пользователя soc) к ответу на вопрос об оптимизации хвостовых вызовов упоминается, что в Java 7 появилась новая функция, называемая "исключенные исключения", из-за "добавления ARM" (поддержка процессоров ARM?).

Что такое "исключенное исключение" в этом контексте? В других контекстах "подавленное исключение" будет исключением, которое будет поймано, а затем проигнорировано (редко хорошая идея); это явно что-то другое.

8 ответов

Решение

Я полагаю, что комментатор имеет в виду исключение, которое почти игнорируется, когда оно бросается в неявное finally блок try-with-resources, в контексте существующего исключения, генерируемого из try блок:

Исключение может быть вызвано из блока кода, связанного с оператором try-with-resources. В примере writeToFileZipFileContents, исключение может быть выдано из блока try, и до двух исключений может быть выдано из оператора try-with-resources, когда он пытается закрыть объекты ZipFile и BufferedWriter. Если исключение выдается из блока try, а одно или несколько исключений выбрасываются из оператора try-with-resources, то эти исключения, выбрасываемые из оператора try-with-resources, подавляются, и исключение, выбрасываемое блоком, является единственным это бросается методом writeToFileZipFileContents. Вы можете получить эти исключенные исключения, вызвав метод Throwable.getSuppressed из исключения, сгенерированного блоком try.

(Это цитата из раздела "Подавленные исключения" со связанной страницы.)

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

Компилятор должен определить, какой из них "реально" выбросить. Он выбрасывает исключение, возбуждаемое в явном коде (код в try блок), а не брошенный неявным кодом (finally блок). Поэтому исключение (я), выброшенное в неявном блоке, подавляется (игнорируется). Это происходит только в случае нескольких исключений.

До 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 {
}

Новый конструктор и два новых метода были добавлены в класс Throwable в JDK 7. Они перечислены ниже:

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() добавляется как подавленное исключение по умолчанию вместе с попыткой исключения.

Также известно, что это отличается от связанных исключений (были введены в JDK 1.4 и предназначались для того, чтобы можно было легко отслеживать причинно-следственные связи между исключениями).

Concending код ниже:

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

Подавленные исключения - это дополнительные исключения, которые возникают в операторе try-with-resources ( представлен в Java 7), когда AutoCloseable ресурсы закрыты. Потому что при закрытии может возникнуть несколько исключений AutoCloseable Ресурсы, дополнительные исключения прикрепляются к первичному исключению как исключенные исключения.

Рассматривая байт-код фрагмента примера кода try-with-resources, стандартные обработчики исключений JVM используются для учета семантики try-with-resources.

Вы также можете подавить исключения в Java 6 (немного хитрости),

Я создал утилиту, которая прозрачно обрабатывает подавление исключений в Java 1.6 и Java 1.7. Вы можете найти реализацию здесь

Все, что вам нужно, это позвонить:

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

подавить исключение и

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

чтобы получить исключенные исключения исключений, в случае, если кто-то все еще использует Java 1.6

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() функция [в блоке finally] выдает исключение, тогда последнему присваивается больший приоритет, и он возвращается к вызывающей функции. В этом случае 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 генерируется при закрытии ресурса [Представьте, что это происходит в неявном блоке finally, который создает оператор try-with-resource], тогда Exception1 подавляет Exception2.

Несколько замечаний, чтобы отметить здесь -

  1. Если блок try-with-resource выдает исключение, т.е. при создании экземпляра ресурса, блок try не будет выполнен и будет выдано то же исключение.
  2. Если создание экземпляра ресурса прошло успешно, блок try выдает исключение, и исключение выдается при закрытии ресурса, затем исключение, выдаваемое при закрытии ресурса, подавляется исключением, выданным из блока try.
  3. Если вы укажете явный блок finally и из этого блока будет сгенерировано исключение, оно подавит все остальные исключения. (Этот явный блок finally выполняется после закрытия ресурсов)

Я скомпилировал большинство возможных сценариев с фрагментами кода и выводил их в следующем посте.

Подавленные исключения в Java 7

Надеюсь, это поможет.

Я думаю, что это связано с "цепочкой исключений". Это повлияет на то, как исключение будет обрабатываться этим средством по мере развития трассировки стека. Со временем исключения, которые являются частью группы связанных исключений, могут быть подавлены. Посмотрите документацию Throwable для более подробной информации.

Другие вопросы по тегам