Исключения как публичные классы против публичных статических внутренних классов - PullRequest
30 голосов
/ 15 ноября 2010

У меня есть два варианта (которые технически совпадают, насколько я понимаю), чтобы объявить пользовательский класс исключений, выброшенный только из определенного класса com.XXX.Foo:

  • как открытый класс в пакете: com.XXX.CustomException
  • как открытый статический внутренний класс: com.XXX.Foo.CustomException

Какой вариант лучше?

Ответы [ 5 ]

15 голосов
/ 15 ноября 2010

В случае, если исключение очень специфично для класса Foo, я не против сохранить его в качестве public вложенного класса.И когда кажется, что пришло время извлечь это, просто извлеките это.

В общем, я никогда не видел ни одного вложенного класса, определенного для Exception.Я также не знаю, существует ли такой в ​​Java API.

10 голосов
/ 15 ноября 2010

За более чем 10-летний опыт работы с Java я не могу вспомнить, чтобы сталкивался с API, в котором общедоступный класс исключений был определен как статический внутренний класс. Я не могу дать вам конкретную причину, почему это было бы плохой идеей, но это, безусловно, сделает ваш код необычным .

Почему вы чувствуете, что это необходимо сделать, учитывая, что (по-видимому) никто не делает? Я надеюсь, что вы не просто делаете это, чтобы быть «инновационным».

(Кстати, я знаю, что некоторые хорошо известные API Java используют публичные статические внутренние классы и интерфейсы для других целей. Я специально говорю о случае классов исключений здесь.)

8 голосов
/ 17 марта 2014

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

Кажется, причины этого не делатьбыть:

  • Соединение исключения с классом, который выбрасывает его, делает его неуместным повторное использование в других контекстах
  • Никто другой не делает это

Я делаюне найти ни одного из этих аргументов вообще убедительным.

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

Но даже без точки "доведенных до крайности", рассмотрим исключение, предназначенное для передачи того, что классу Foo был дан неверный ввод.Если я назову это Foo.InvalidInput, название будет коротким, и ассоциацию с Foo невозможно пропустить.Если я помещу его вне класса Foo и назову его FooInvalidCriteria, то я все равно не смогу повторно использовать его из класса Bar, не изменив его имя (эквивалентно изменению его местоположения).

Нохуже всего, если я оставлю его снаружи Foo и оставлю его общее имя, например InvalidInput.Затем, когда я позже пойму, что Bar может иметь неверный ввод, я начну выдавать это исключение.Все компилируется и работает нормально, только теперь все места, которые ловили InvalidInput и предполагая, что они обрабатывали ошибки из Foo, теперь могут также обрабатывать ошибки из Bar, если Foo использует внутреннее Bar втаким образом, это может вызвать исключение.Это может легко привести к сбою кода.

Реальность такова, что за исключением исключения, которое ранее задумывалось как конкретно указывающее на ситуацию, возникающую в одном классе, и повторное использование его в качестве общего класса ошибок, является интерфейсом . изменение, а не только изменение внутренней реализации.В целом, чтобы сделать это правильно, вы должны повторно посетить все сайты, на которых перехвачено исключение, и убедиться, что они по-прежнему корректны, поэтому компилятор расскажет вам обо всех используемых сайтах (поскольку вам нужно изменитьимя и / или путь импорта) это хорошая вещь.Любое исключение, которое вы могли бы сделать статическим внутренним классом, не подходит для повторного использования в других контекстах, независимо от того, делаете ли вы его внутренним классом или нет.

И что касается второй точки... "никто больше этого не делает" никогда ни на что не влияет.Либо это действительно неправильно, поэтому будут другие причины не делать этого, поэтому аргумент «никто другой не делает» не нужен.Или это не так.И это не похоже на то, что этот конкретный пример будет ужасно сложным и трудным для понимания, поэтому даже аргумент «это неожиданно, так что у людей возникнут проблемы с этим, даже если это хорошая теоретическая идея», является очень сильным.

3 голосов
/ 15 ноября 2010

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

Aпользователь сразу увидит, что есть исключение, когда он смотрит на пакет и ему не нужно читать файл класса foo, что лучше по причинам обслуживания и ясности / читаемости / понимания.Очень хорошо определять пользовательские исключения и сообщать об этом API-пользователю!

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

Тем не менееМы говорим здесь о в основном обычной проблеме!

0 голосов
/ 03 июля 2013

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...