У меня довольно подробный вопрос о том, как правильно обернуть проверенное исключение и как это делает Guava.(Извиняюсь за длину, но я хочу, чтобы мой мыслительный процесс не работал)
Стандартный интерфейс Runnable выглядит следующим образом:
public interface Runnable
{
public void run();
}
, где run()
не может выброситьпроверенное исключение.
Поэтому, если я хочу иметь Runnable
, который используется для переноса задач, которые выдают проверенные исключения, и я намереваюсь иметь вещь, которая вызывает Runnable.run()
, обрабатывает эти исключения, а не в Runnable.run()
сам, я должен обернуть исключение в непроверенное исключение.
Итак, какое-то время я использовал:
Runnable r = new Runnable {
@Override public void run()
{
try {
doNastyStuff();
}
catch (NastyException e)
{
throw new RuntimeException(e);
}
}
};
, а затем я могу обработать RuntimeException на более высоком уровне.Кроме того, я решил, что мне действительно нужно обрабатывать обернутое исключение отдельно, так как я знаю, что его семантика заключается в обертывании проверенного исключения, поэтому я написал этот вспомогательный класс:
/**
* Wrapped exception: the purpose of this is just to wrap another exception,
* and indicate that it is a wrapped exception
*/
public class WrappedException extends RuntimeException
{
/**
* @param t any throwable
*/
public WrappedException(Throwable t)
{
super(t);
}
}
и тогда я смогусделайте это:
/* place that produces the exception */
...
catch (NastyException e)
{
throw new WrappedException(e);
}
...
/* upper level code that calls Runnable.run() */
try
{
...
SomeOtherNastyCode();
r.run();
...
}
catch (SomeOtherNastyException e)
{
logError(e);
}
catch (WrappedException e)
{
logError(e.getCause());
}
, и, кажется, это прекрасно работает.
Но теперь я думаю, хорошо, если я хочу использовать это в библиотеке, а также в приложении, которое используетбиблиотеки, теперь они оба зависят от WrappedException, так что он действительно должен находиться в базовой библиотеке, которую я могу включить везде.
Что заставляет меня задуматься, может быть, у Guava есть где-то стандартный класс WrappedException, поскольку теперь я включаю Guavaкак зависимость по умолчанию.Так что я могу просто сделать
throw new WrappedException(e);
или
throw Exceptions.wrap(e);
или
Exceptions.rethrow(e);
Я только что оглянулся в Гуаве и нашел Throwables , которыеимеет Throwables.propagate()
, который выглядит аналогично, но он просто включает проверенные исключения в RuntimeException
, а не в специальный подкласс RuntimeException.
Какой подход лучше?Не следует ли использовать специальное исключение WrappedException по сравнению с RuntimeException?Мой код верхнего уровня хочет знать самое верхнее исключение, которое добавляет информационную ценность.
Если у меня есть RuntimeException, которое оборачивает NastyException, которое оборачивает NullPointerException, обертка RuntimeException не добавляет информационное значение, и я не беспокоюсь об этом, поэтому ошибка, которую я регистрирую, будет NastyException.
Если у меня есть IllegalArgumentException, который оборачивает NastyException, IllegalArgumentException, как правило, добавляет информационное значение.
Так что в моем верхнем коде, который ведет журнал ошибок, я должен был бы сделать что-то вроде этого:
catch (RuntimeException re)
{
logError(getTheOutermostUsefulException(re));
}
/**
* heuristics to tease out whether an exception
* is wrapped just for the heck of it, or whether
* it has informational value
*/
Throwable getTheOutermostUsefulException(RuntimeException re)
{
// subclasses of RuntimeException should be used as is
if (re.getClass() != RuntimeException)
return re;
// if a runtime exception has a message, it's probably useful
else if (re.getMessage() != null)
return re;
// if a runtime exception has no cause, it's certainly
// going to be more useful than null
else if (re.getCause() == null)
return re;
else
return re.getCause();
}
Философия мне подходит, но реализация - плохо.Есть ли лучший способ обработки обернутых исключений?
связанные вопросы: