Пользовательские исключения: различать через многие подклассы или один класс с поддержкой перечисления?
Я хочу реализовать свой собственный набор Exceptions
для проектов, над которыми я сейчас работаю. Проект опирается на основную структуру с базовым исключением MyFrameworkException
(я также пишу эту структуру).
Для любого данного проекта я хотел бы задать несколько разных типов Exceptions
, и я не могу решить между использованием нескольких подклассов или одного подкласса с некоторой формой Enum
в качестве параметра конструктора.
В обоих случаях я:
public class MyFrameworkException extends Exception { /*...*/ }
Вариант 1:
public class MyProjectBaseException extends MyFrameworkException { /*...*/ }
public class SpecificExceptionType1 extends MyProjectBaseException { /*...*/ }
public class SpecificExceptionType1 extends MyProjectBaseException { /*...*/ }
public class SpecificExceptionType1 extends MyProjectBaseException { /*...*/ }
Затем во всем проекте я бы выбрал конкретное исключение для любой возникающей проблемы.
Вариант 2:
public class MyProjectException extends MyFrameworkException {
public static enum Type {
SpecificType1, SpecificType2, SpecificType3
}
public MyProjectException( Type type ) { /*...*/ }
}
Здесь я всегда буду бросать MyProjectException
с конкретным типом перечисления для любой возникающей проблемы. Я бы предоставил некоторый механизм, чтобы оператор switch мог выполняться на любом MyProjectException
на основе перечисления типа.
Каков наилучший способ обработки исключений в проектах, особенно тех, которые используют общую инфраструктуру? Являются ли два варианта выше хорошими? Почему или почему нет? И какие еще лучшие решения?
Ответы
Ответ 1
Главный недостаток варианта 2 (общее исключение + перечисление) заключается в том, что вы теряете часть полезности проверенных исключений. Метод в значительной степени должен сказать просто "что-то связанное с каркасом может пойти не так":
public void foo()
throws MyFrameworkException
... а не "x или y может пойти не так":
public void foo()
throws SomethingWentWrongException, SomethingElseWentWrongException
Это означает, что функция, которая может потребоваться для обработки одного фрейм-исключения, должна быть готова обрабатывать любой из них, тогда как если вы специфичны, функция должна быть подготовлена только для обработки исключений, которые генерируются с помощью методов framework вызовы.
Итак, для меня иерархия, такая как Вариант 1 (она не должна быть настолько плоской, если сама структура предлагает) - путь. Тем не менее, есть люди, которые не любят проверенные исключения вообще, и для них я подозреваю, что вышеизложенное не является веским аргументом.: -)
Изменить И поднять тупик: я предположил, что вы говорили об исключениях, которые вам действительно нужно создавать. Абсолютно бросайте стандартные исключения везде, где это имеет смысл (что почти повсеместно). Не создавайте свой собственный MyFrameworkIllegalArgumentException
, например, просто используйте IllegalArgumentException
(или его различные подклассы).
Ответ 2
Я бы использовал исключения, расширяющие java.lang.RuntimeException с описательными именами классов.
Если у вас так много исключений для конкретного бизнеса, что это становится репрессивным, это означает, что вы, вероятно, ошибаетесь.
См. совет Джошуа Блоха о в пользу стандартных исключений.
Ответ 3
Я бы не наследовал от общего MyFrameworkException
, если вы не предоставляете никаких функций, общих для всех проектов. Else, всегда расширяйте Exception.
Обычно вы должны бросать значимые исключения на границе домена/уровня. Поэтому в отношении вашего вопроса вы должны пойти с вариантом 1, имея в виду пункт выше. Вариант 2 увеличил бы сложность кода, так как вам всегда нужно будет проверить тип исключения, чтобы определить, что пошло не так. Пусть класс исключений говорит сам за себя.