Как я могу передать коллекцию исключений в качестве основной причины?

52

Какой-то метод myMethodвызывает несколько параллельных выполнений и ожидает их завершения.

Эти параллельные исполнения могут заканчиваться исключениями. Так myMethodполучается список исключений.

Я хочу передать список исключений в качестве основной причины, но основной причиной может быть только одно исключение. Конечно, я могу создать свое собственное исключение для достижения того, чего я хочу, но я хочу знать, есть ли что-то подобное в Java, Spring или Spring Batch.

gstackoverflow
источник
3
В .NET есть AggregateExceptionсписок исключений. Эта идея должна быть применима и к Java.
USR
1
См. Также stackoverflow.com/q/8946661/821436
Восстановить Монику - М. Шредер

Ответы:

49

Я не уверен, что сделал бы это (хотя, учитывая JavaDoc, я не мог сказать вам, почему я колебался), но есть список исключенных исключений Throwable, к которым вы можете добавить с помощью addSuppressed. JavaDoc, похоже, не говорит, что это только для JVM для использования в try-with-resources:

Добавляет указанное исключение к исключениям, которые были подавлены для доставки этого исключения. Этот метод является поточно-ориентированным и обычно вызывается (автоматически и неявно) оператором try-with-resources.

Подавление поведения включено, если не отключено через конструктор. Когда подавление отключено, этот метод не делает ничего, кроме проверки своего аргумента.

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

Исключение могло подавлять исключения, но также вызываться другим исключением. Независимо от того, будет ли исключение иметь причину, семантически известно во время его создания, в отличие от того, будет ли исключение подавлять другие исключения, которые обычно определяются только после создания исключения.

Обратите внимание, что написанный программистом код также может воспользоваться вызовом этого метода в ситуациях, когда существует несколько исключений одного и того же уровня, и может распространяться только одно.

Обратите внимание на последний абзац, который, кажется, подходит для вашего случая.

TJ Crowder
источник
[...] будет ли исключение подавлять другие исключения [...], как правило, определяется только после создания исключения. Я полагаю, что это будет не тот случай, когда множественные исключенные исключения собираются из параллельных прогонов.
GOTO 0
24

Исключения и их причины всегда имеют значение 1: 1: вы можете выдать одно исключение, и каждое исключение может иметь только одну причину (которая снова может иметь одну причину ...).

Это можно считать ошибкой проектирования, особенно если учесть многопоточное поведение, как вы описали.

Это одна из причин, по которой Java 7 добавлена addSuppressedв throwable, которое может в основном присоединять произвольное количество исключений к одному другому (другой основной мотивацией была попытка с ресурсами, которой требовался способ обработки исключений в блоке finally без скрытого отбрасывания их).

Таким образом, в основном, когда у вас есть 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.
Ильмари
1
... Вместо этого я бы отметить все лежащие в основе исключения, подавляются SomethingWentWrongException, и дать это исключение сообщение ясно указывающее , что один или более подавленные исключения должны следовать, например , что - то вроде " X из Y задач не удалось, увидеть список отказов ниже ».
Илмари