Исключение Java не поймали?


У меня маленький теоретической проблема с конструкциями try-catch.

вчера я сдал практический экзамен по Java, и я не понимаю следующий пример:

try {
    try {
        System.out.print("A");
        throw new Exception("1");
    } catch (Exception e) {
        System.out.print("B");
        throw new Exception("2");
    } finally {
        System.out.print("C");
        throw new Exception("3");
    }
} catch (Exception e) {
    System.out.print(e.getMessage());
}

вопрос был "как будет выглядеть выход?"

Я был почти уверен, что это будет AB2C3, но удивительно, это неправда.

правильный ответ-ABC3 (проверено и действительно так).

мой вопрос в том, откуда взялся Исключение("2") идут?

6 168

6 ответов:

С Спецификация Языка Java 14.20.2.:

если блок catch завершается внезапно по причине R, то выполняется блок finally. Тогда есть выбор:

  • если блок finally завершается нормально, то оператор try завершается резко по причине R.

  • если блок finally завершается внезапно по причине S, то оператор try завершается внезапно для причина S (и причина R отбрасывается).

Итак, когда есть блок catch, который выдает исключение:

try {
    // ...
} catch (Exception e) {
    throw new Exception("2");
}

но есть также блок finally, который также выдает исключение:

} finally {
    throw new Exception("3");
}

Exception("2") будут отброшены и только Exception("3") будут распространяться.

исключения, созданные в блоке finally подавляют исключение, созданное ранее в блоке try или catch.

Java 7 пример:http://ideone.com/0YdeZo

С документация по пример:


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 и close оба броска исключения, то метод readFirstLineFromFileWithFinallyblock создает исключение, созданное из блока finally; исключение выброшенный из блока try подавляется.


новая try-with синтаксис Java 7 добавляет еще один шаг подавления исключений: исключения, брошенные в блоке try, подавляют те, которые были брошены ранее в части try-with.

из того же примера:

try (
        java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName);
        java.io.BufferedWriter writer = java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
    ) {
        for (java.util.Enumeration entries = zf.entries(); entries.hasMoreElements();) {
            String newLine = System.getProperty("line.separator");
            String zipEntryName = ((java.util.zip.ZipEntry)entries.nextElement()).getName() + newLine;
            writer.write(zipEntryName, 0, zipEntryName.length());
        }
    }

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


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

http://en.wikipedia.org/wiki/Error_hiding

С throw new Exception("2"); выдает catch и try, это не будет пойман снова.
посмотреть 14.20.2. Выполнение попробовать-наконец-то и попробовать-поймать-наконец-то.

вот что происходит:

try {
    try {
        System.out.print("A");         //Prints A
        throw new Exception("1");   
    } catch (Exception e) { 
        System.out.print("B");         //Caught from inner try, prints B
        throw new Exception("2");   
    } finally {
        System.out.print("C");         //Prints C (finally is always executed)
        throw new Exception("3");  
    }
} catch (Exception e) {
    System.out.print(e.getMessage());  //Prints 3 since see (very detailed) link
}

Ваш вопрос очень очевиден, и ответ прост в той же степени.. объект исключения с сообщением как " 2 "перезаписывается объектом исключения с сообщением как" 3".

объяснение : Когда возникает исключение, его объект он бросил, чтобы поймать блок для обработки. Но когда исключение происходит в самом блоке catch, его объект передается во внешний блок CATCH (если таковой имеется) для обработки исключений. И то же самое произошло здесь. Этот Объект исключения с сообщением " 2 " передается во внешний блок catch . но ждать.. Перед выходом из внутреннего блока try-catch он должен выполнить окончательно. Здесь произошло изменение, о котором мы беспокоимся. Выбрасывается новый объект исключения (с сообщением "3") или этот последний блок, который заменил уже брошенный объект исключения(с сообщением"2"). в результате чего , когда выводится сообщение объекта исключения, мы получаем переопределенное значение т. е." 3", а не"2".

сохранить Помните:только один объект исключения может быть обработан блоком CATCH.

The finally блок всегда работает. Либо ты return изнутри блока try или создается исключение. Исключение, брошенное в finally блок переопределит тот, который был брошен в ветке catch.

кроме того, выбрасывание исключения не вызовет никаких выходных данных само по себе. Линия throw new Exception("2"); ничего не будет выписывать.

согласно вашему коду:

try {
    try {
        System.out.print("A");
        throw new Exception("1");   // 1
    } catch (Exception e) {
        System.out.print("B");      // 2
        throw new Exception("2");
    } finally {                     // 3
        System.out.print("C");      // 4 
        throw new Exception("3");
    }
} catch (Exception e) {             // 5
    System.out.print(e.getMessage());
}

как вы можете увидеть здесь:

  1. print A и выбрасывает исключение # 1;
  2. это исключение было поймано оператором catch и print B - # 2;
  3. блок наконец-то # 3 выполняет после try-catch (или только try, если не произошло никакого исключения) заявление и печатает C - # 4 и выбрасывается новое исключение;
  4. этот поймал внешний оператор catch # 5;

результат ABC3. И 2 опускается так же, как и 1