Як я можу передати колекцію винятків як першопричину?


52

Деякий метод, myMethodвикликає кілька паралельних виконання та чекає їх закінчення.

Ці паралельні страти можуть закінчуватися винятками. Так myMethodпотрапляє список виключень.

Я хочу передати список виключень як першопричину, але першопричиною може бути лише один виняток. Звичайно, я можу створити власний виняток, щоб досягти того, що я хочу, але я хочу знати, чи немає у Java, Spring або Spring Batch щось подібне.


3
.NET має AggregateExceptionопис, який містить список винятків. Ця ідея повинна бути застосовна і для Java.
usr

Відповіді:


49

Я не впевнений, що зробив би це (хоча, враховуючи JavaDoc, я не міг сказати, чому я вагаюся), але є список прихованих винятків Throwable, до яких ви можете додати addSuppressed. Здається, JavaDoc не каже, що це лише для JVM, який використовується у спробу використання ресурсів:

Додає вказаний виняток до винятків, які були придушені для доставки цього винятку. Цей метод є безпечним для потоків і, як правило, викликається (автоматично і неявно) оператором "спробувати ресурси".

Поведінка придушення вмикається, якщо відключено через конструктор. Коли придушення вимкнено, цей метод не робить нічого іншого, крім перевірки свого аргументу.

Зауважте, що коли один виняток спричиняє інший виняток, перший виняток зазвичай виловлюється, а потім другий виняток кидається у відповідь. Іншими словами, між двома винятками існує причинний зв'язок. На відміну від цього, бувають ситуації, коли два блоки винятків можуть бути кинуті в блоки кодових братів, зокрема, у блок спробу оператора «спробу-ресурсів» та згенерований компілятором нарешті блок, який закриває ресурс. У цих ситуаціях можна поширювати лише один із закинутих винятків. У операторі спробу використання ресурсів, коли є два такі винятки, поширюється виняток, що походить з блоку спробу, і виняток з остаточно блоку додається до списку винятків, придушених виключенням з блоку спробу. Як виняток розгортає стек,

Виняток, можливо, придушив винятки, а також був викликаний іншим винятком. Наявність причини винятку чи ні, семантично відомо під час її створення, на відміну від того, чи буде виняток придушувати інші винятки, які, як правило, визначаються лише після викиду виключення.

Зауважте, що письмовий код програміста також може скористатися викликом цього методу в ситуаціях, коли є декілька винятків побратимів, і лише один може бути розповсюджений.

Зауважте, останній абзац, який, здається, відповідає вашому випадку.


[...] чи виняток буде придушувати інші винятки [...], як правило, визначається лише після скидання виключення. Я думаю, що це не буде, коли збираються кілька витіснених винятків з паралельних прогонів.
GOTO 0

24

Винятки та їх причини завжди є лише справою 1: 1: ви можете викинути один виняток, і кожен виняток може мати лише одну причину (яка знову може мати одну причину ...).

Це можна вважати помилкою дизайну, особливо якщо розглядати багатопотокові поведінки, як ви описали.

Це одна з причин, чому Java 7 додав addSuppressedдо перезавантажувальних даних, які в основному можуть приєднувати довільну кількість винятків до однієї іншої (інша основна мотивація - це "пробний ресурс", який потребував способу обробляти винятки в остаточному блоці без мовчазного падіння їх).

Таким чином, коли у вас є 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 завдань не вдалося, побачити список відмов нижче ".
Ільмарі Каронен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.