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

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

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

8 ответов


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

исключение может быть вызвано из блока кода, связанного с инструкцией try-with-resources. В Примере writeToFileZipFileContents из блока try может быть создано исключение и до двух исключения могут быть вызваны из инструкции try-with-resources при попытке закрыть объекты ZipFile и BufferedWriter. Если исключение из try блока и одного или нескольких исключений из try-оператор с ресурсами, то эти исключения из try-оператор с ресурсами подавляются, и исключение в блоке-это одно, что бросается writeToFileZipFileContents способ. Эти подавленные исключения можно получить, вызвав Перекидным.метод 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:: закрыть() по умолчанию добавляется как подавленное исключение вместе с исключением try.

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


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

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


Concedering код ниже:

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

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


вы также можете подавлять исключения в 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();
    }
}