근본 원인으로 예외 모음을 전달하려면 어떻게해야합니까?


52

일부 메소드 myMethod는 여러 병렬 실행을 호출하고 종료를 기다립니다.

이러한 병렬 실행은 예외로 끝날 수 있습니다. 그래서 myMethod예외 목록을 가져옵니다.

예외 목록을 근본 원인으로 전달하고 싶지만 근본 원인은 단일 예외 일 수 있습니다. 물론 원하는 것을 달성하기 위해 나만의 예외를 만들 수는 있지만 Java, Spring 또는 Spring Batch에 이와 같은 것이 있는지 알고 싶습니다.


3
.NET에는 AggregateException예외 목록이 포함되어 있습니다. 이 아이디어는 Java에도 적용 할 수 있어야합니다.
usr

답변:


49

JavaDoc을 사용하면 주저 이유를 알 수 없지만 확실하지는 않지만에 대한 예외 목록이 Throwable있으며를 통해 추가 할 수 있습니다 addSuppressed. JavaDoc은 이것이 JVM이 try-with-resources에서 사용하기위한 것이라고 말하지 않는 것 같습니다.

이 예외를 전달하기 위해 억제 된 예외에 지정된 예외를 추가합니다. 이 메소드는 스레드로부터 안전하며 일반적으로 try-with-resources 문에 의해 (자동 및 암시 적으로) 호출됩니다.

생성자를 통해 비활성화하지 않으면 억제 동작이 활성화됩니다. 억제를 무효로하면 (자),이 메소드는 인수를 검증하는 것 외에는 아무것도하지 않습니다.

한 예외에서 다른 예외가 발생하면 일반적으로 첫 번째 예외가 발생하고 두 번째 예외가 응답으로 발생합니다. 다시 말해, 두 예외 사이에는 인과 관계가 있습니다. 반대로 형제 코드 블록, 특히 try-with-resources 문의 try 블록 및 리소스를 닫는 컴파일러 생성 finally 블록에서 두 개의 독립적 인 예외가 발생할 수있는 상황이 있습니다. 이러한 상황에서는 예외 중 하나만 전파 될 수 있습니다. try-with-resources 문에서 이러한 예외가 두 개 있으면 try 블록에서 시작된 예외가 전파되고 finally 블록의 예외가 try 블록의 예외에 의해 억제 된 예외 목록에 추가됩니다. 예외로 스택이 풀리면

예외는 다른 예외로 인해 예외를 억제했을 수 있습니다. 예외가 원인을 갖는지 여부는 예외가 예외가 발생한 후에 만 ​​결정되는 다른 예외를 억제하는지 여부와 달리, 작성시 의미 상으로 알려져 있습니다.

프로그래머가 작성한 코드는 또한 여러 형제 예외가 있고 하나만 전파 될 수있는 상황에서이 메소드를 호출 할 수 있습니다.

마지막 단락은 귀하의 경우에 맞는 것 같습니다.


[...] 예외가 다른 예외를 억제할지 여부 [...]는 일반적으로 예외가 발생한 후에 만 ​​결정됩니다. 병렬 실행에서 여러 억제 된 예외가 수집되는 경우에는 해당되지 않습니다.
GOTO 0

24

예외와 그 원인은 항상 1 : 1 일뿐입니다. 하나의 예외를 던질 수 있으며 각 예외에는 한 가지 원인 만있을 수 있습니다 (다시 한 가지 원인이있을 수 있음 ...).

설명 된대로 다중 스레드 동작을 고려할 때 이는 설계 결함으로 간주 될 수 있습니다.

이것이 Java 7 addSuppressed이 Throwable에 추가 된 이유 중 하나입니다. 기본적으로 임의의 예외를 하나의 다른 예외에 첨부 할 수 있습니다 (다른 주요 동기는 리소스를 사용하지 않고 try-with-resources였습니다. 그들).

따라서 기본적으로 프로세스 실패를 유발하는 1 개의 예외가있는 경우 상위 예외의 원인으로 해당 예외를 추가하고, 더있는 경우을 사용하여 해당 예외를 원래 예외에 추가합니다 addSuppressed. 아이디어는 첫 번째 예외가 "실제 예외 체인"의 구성원이되는 다른 예외를 "억제했다"는 것입니다.

샘플 코드 :

Exception exception = null;
for (Foobar foobar : foobars) {
  try {
    foobar.frobnicate();
  } catch (Exception ex) {
    if (exception == null) {
      exception = ex;
    } else {
      exception.addSuppressed(ex);
    }
  }
}
if (exception != null) {
  throw new SomethingWentWrongException(exception);
}

4
근본적인 예외 중 하나가 실제로 "주요한"예외로 분류 될 수 없다면, 당신이 제안한 방식대로하지 않을 것입니다. 예외 중 하나를 기본 예외로 선택하고 다른 예외는 억제 된 것으로 선택하는 경우, "주"예외가 TypoInUserInputException 및 다음 중 하나 인 경우에도 호출자에게 억제 ​​된 예외를 무시하고 기본 예외를보고 하도록 초대 합니다. 억제 된 것은 DatabaseCorruptedException입니다.
Ilmari Karonen

1
... 대신에, 나는 표시 줄 의 모든 SomethingWentWrongException 억제로서 기본이되는 예외를, 그 예외를 명확하게 하나 이상의 억제 예외가 있음을 나타내는 메시지를 제공 한다 "와 같은에 따라, 예를 들어 어떤 XY의 아래에 실패의 목록을 보려면, 작업 실패를 ".
Ilmari Karonen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.