[java] 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입니다. (실제 테스트와 동일합니다.)

제 질문은 Exception ( “2”)이 어디로 갔습니까?



답변

로부터 Java 언어 사양 14.20.2. :

이유 R로 인해 catch 블록이 갑자기 완료되면 finally 블록이 실행됩니다. 그런 다음 선택이 있습니다.

  • finally 블록이 정상적으로 완료되면 이유 R로 인해 try 문이 갑자기 완료됩니다.

  • 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 메소드와 두 예외 모두를 처리하는 경우 readFirstLineFromFileWithFinallyBlock 메소드는 finally 블록에서 발생한 예외를 처리합니다. try 블록에서 발생한 예외는 억제됩니다.


try-withJava 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-with-resources 문과 관련된 코드 블록에서 예외가 발생할 수 있습니다. 위의 예에서, try 블록에서 예외가 발생 될 수 있으며 ZipFile 및 BufferedWriter 객체를 닫으려고 할 때 try-with-resources 문에서 최대 2 개의 예외가 발생 될 수 있습니다. try 블록에서 예외가 발생하고 try-with-resources 문에서 하나 이상의 예외가 발생하면 try-with-resources 문에서 발생 된 예외가 억제되고 블록에서 발생한 예외는 예외입니다. 이것은 writeToFileZipFileContents 메소드에 의해 발생합니다. try 블록에서 발생한 예외에서 Throwable.getSuppressed 메소드를 호출하여 이러한 억제 된 예외를 검색 할 수 있습니다.


문제의 코드에서 각 블록은 오래된 예외를 무시하고 로깅조차하지 않으며 버그를 해결하려고 할 때 좋지 않습니다.

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”인 Exception 객체는 메시지가 “3”인 Exception 객체로 덮어 씁니다.

설명 :
예외가 발생하면 처리 할 블록을 잡기 위해 발생한 객체입니다. 그러나 catch 블록 자체에서 예외가 발생하면 예외 처리를 위해 해당 개체가 OUTER CATCH Block (있는 경우)으로 전송됩니다. 그리고 여기에서도 마찬가지입니다. 메시지가 “2”인 예외 오브젝트가 OUTER catch 블록으로 전송됩니다. 그러나 기다립니다 . 내부 try-catch 블록을 떠나기 전에 마지막으로 실행해야합니다. 여기에 우리가 걱정하는 변화가 일어났습니다. 새로운 EXCEPTION 객체 (메시지 “3”)가 발생하거나 이미 발생 된 Exception 객체 (메시지 “2”)를 대체 한이 블록이 최종적으로 차단되어 결과적으로 Exception 객체의 메시지가 인쇄 될 때 재정의 된 값, 즉 “2”가 아닌 “3”입니다.

주의 사항 : CATCH 블록에서는 하나의 예외 객체 만 처리 할 수 ​​있습니다.


답변

finally블록은 항상 실행됩니다. 어느 쪽이든 당신 returntry 블록 또는 예외 내부에서가 발생합니다. finally블록 에서 발생한 예외 는 catch 분기에서 발생한 예외 를 무시합니다.

또한 예외를 throw해도 자체 출력이 발생하지 않습니다. 줄 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. A를 인쇄하고 예외를 던집니다 # 1.
  2. 이 예외는 catch 문과 print에 의해 포착되었습니다 B - # 2.
  3. block은 # 3try-catch (또는 예외가 발생하지 않은 경우에만 시도) 명령문 이후에 마지막으로 실행 C - # 4되고 새 예외를 인쇄 하고 발생시킵니다.
  4. 이것은 외부 catch 문에 의해 잡혔다 # 5;

결과는 ABC3입니다. 그리고 2같은 방식으로 생략1


답변