Перехват исключения, вложенного в другое исключение

StackOverflow https://stackoverflow.com/questions/2955458

Вопрос

Я хочу перехватить исключение, вложенное в другое исключение.Сейчас я делаю это так:

} catch (RemoteAccessException e) {
    if (e != null && e.getCause() != null && e.getCause().getCause() != null) {
        MyException etrp = (MyException) e.getCause().getCause();
        ...
    } else {
        throw new IllegalStateException("Error at calling service 'service'");
    }
}

Есть ли способ сделать это более эффективно и элегантно?

Это было полезно?

Решение

Нет более элегантного способа выборочного «поймать» вложенных исключений. Я полагаю, что если вы сделали этот вид вложенного исключения, выявив много, вы могли бы переработать код в общий метод утилиты. Но это все еще не будет ни элегантным, ни эффективным.

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

Исключения, как правило, вложены по 3 причинам:

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

  2. Вы внедряете методы API, которые не позволяют конкретное проверенное исключение, но ваш код неизбежно бросает это исключение. Обычным обходным пути является «контрабанда» проверенное исключение в неконтролируемом исключении.

  3. Ты ленивый и поворачиваешь разнообразный Набор не связанных исключений в одно исключение, чтобы избежать много проверенных исключений в подписи метода1.

В первом случае, если вам теперь нужно различать обернутые исключения, то ваши первоначальные предположения были неверными. Лучшее решение - это подписи метода изменения, чтобы вы могли избавиться от гнездования.

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

В третьем случае вы должны переосмыслить стратегию обработки исключений; т.е. сделай это правильно2.


1-Действительно, одна из полу-легтиматических причин для этого исчезла из-за введения синтаксиса мульти-экспрессии в Java 7.

2 - Не меняйте методы API на throws Exception. Анкет Это только усугубляет. Теперь вы должны либо «обрабатывать» или распространить Exception Каждый раз, когда вы называете методы. Это рак ...

Другие советы

А ExceptionUtils#getRootcause () Метод может пригодиться в таких ситуациях.

Вы должны добавить несколько чеков, чтобы увидеть, если e.getCause().getCause() действительно MyException. Анкет В противном случае этот код бросит ClassCastException. Анкет Я бы, наверное, написал это как:

} catch(RemoteAccessException e) {
    if(e.getCause() != null && e.getCause().getCause() instanceof MyException) {
        MyException ex = (MyException)e.getCause().getCause();
        // Do further useful stuff
    } else {
        throw new IllegalStateException("...");
    }
}

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

  /**
   * Recursive method to determine whether an Exception passed is, or has a cause, that is a
   * subclass or implementation of the Throwable provided.
   *
   * @param caught          The Throwable to check
   * @param isOfOrCausedBy  The Throwable Class to look for
   * @return  true if 'caught' is of type 'isOfOrCausedBy' or has a cause that this applies to.
   */
  private boolean isCausedBy(Throwable caught, Class<? extends Throwable> isOfOrCausedBy) {
    if (caught == null) return false;
    else if (isOfOrCausedBy.isAssignableFrom(caught.getClass())) return true;
    else return isCausedBy(caught.getCause(), isOfOrCausedBy);
  }

Когда вы его используете, вы просто создаете список if от наиболее конкретного исключения до наименее конкретного, с запасным предложением else:

try {
  // Code to be executed
} catch (Exception e) {
  if (isCausedBy(e, MyException.class)) {
    // Handle MyException.class
  } else if (isCausedBy(e, AnotherException.class)) {
    // Handle AnotherException.class
  } else {
    throw new IllegalStateException("Error at calling service 'service'");
  }
}

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

Этот код будет кошмаром обслуживания. Разве вы не можете перепроектировать стек вызовов, чтобы бросить вас заинтересованное исключение? Если это важно, подписи метода должны показывать это и не скрывать его, завернутые в 2 других исключения.

Первый (e! = Null) не нужен.

И вы можете изменить 3 -е место лучше на e.getCause (). GetCause () экземпляр myException)

Вы можете сделать так, как ниже:

catch (RemoteAccessException e) {
    int index = ExceptionUtils.indexOfThrowable(e, MyExcetption.class)
    if (index != -1) {
         //handleMyException
    } else {
    }
}

Я сомневаюсь, но вы можете проверить с instanceof Если исключение имеет правильный тип.

РЕДАКТИРОВАТЬ: Должна быть причина, по которой вложенное исключение обернуто, поэтому вы должны спросить себя, какова цель поймать вложенную.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top