Есть ли преимущество в объявлении, что метод генерирует непроверенное исключение?

Если у меня есть метод, который выдает непроверенное исключение, например:

void doSomething(int i) {
  if (i < 0) throw new IllegalArgumentException("Too small");
  // ...
}

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

void doSomething(int i) throws IllegalArgumentException {
  if (i < 0) throw new IllegalArgumentException("Too small");
  // ...
}

в отличие от (или в дополнение к) описания поведения в javadoc:

/**
 * This method does something useful.
 * @param i some input value
 * @throws IllegalArgumentException if {@code i < 0}
 */
void doSomething(int i) {
  if (i < 0) throw new IllegalArgumentException("Too small");
  // ...
}

Причины, по которым я бы сказал, что бесполезно иметь throws, следующие:

  • throws не предоставляет информации об обстоятельствах, при которых будет сгенерировано исключение, а только то, что оно может быть сгенерировано;
  • Поскольку это непроверенное исключение, я не обязан обрабатывать исключение в вызывающем коде. Я действительно узнаю, что это может быть брошено, только если я пойду и посмотрю на реализацию doSomething;
  • Тело doSomething может вызывать код, который генерирует другие типы непроверенных исключений; утверждение, что «этот метод выдает IllegalArgumentException», кажется, что потенциально это только часть истории;
  • Если метод не является окончательным, его можно переопределить таким образом, что новая реализация будет объявлена ​​​​выбрасывающей дополнительные непроверенные исключения; вы не знаете, какую реализацию вы вызываете.

Причины, по которым я утверждаю, что было бы полезно иметь throws:

  • Он сообщает о проблеме, с которой можно было бы разумно столкнуться при вызове метода.

Короче, я думаю, что throws не нужен, а описание javadoc через @throws полезно. Мне было бы интересно узнать мнение других по этому поводу.


person Andy Turner    schedule 03.07.2014    source источник
comment
Надеюсь, этот поток поможет в решении этой проблемы - обработка исключений в соответствии со стандартами кодирования Java   -  person nIcE cOw    schedule 03.07.2014


Ответы (3)


Когда вы заявляете, что метод throws является исключением, вы говорите вызывающей стороне:

У вас есть два варианта:

  1. Повторно объявите себя создателем того же исключения.
  2. Поймать исключение и обработать его.

В случае 1 это может напомнить пользователю о необходимости реализовать finally, что может быть бонусом.

В случае 2 ум фокусируется на исключении, которое также может быть бонусом.

Если вы скроете эту возможность, то пользователю не придет ни одно из вышеперечисленных напоминаний.

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

Итог. Спросите себя, насколько раздражающим будет объявление исключения выброшенным (например, следует ли объявлять throws NullPointerException? - НЕТ!), и уравновешивается ли это раздражение положительной стороной сосредоточения внимания пользователей на catch, finally и throws.

person OldCurmudgeon    schedule 03.07.2014

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

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

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

Однако непроверенные исключения означают, что ситуация критическая и не может быть исправлена ​​программой во время выполнения. Если вы используете непроверенные исключения с целью проверенных исключений (вы предполагаете, что ситуация может быть исправлена), но по какой-то причине вы не хотите, чтобы компилятор принудительно перехватывал исключение, я рекомендую также поместить исключение в предложение throws.

person Nailgun    schedule 03.07.2014
comment
Вы делаете разумное замечание, но на самом деле это только помогает узнать об исключениях, генерируемых непосредственно в моем методе - предположим, что doSomething вызывает метод, который генерирует NullPointerException. Есть два обстоятельства: 1) они заявляют, что метод throws NullPointerException - должен ли я заявлять, что мой метод тоже выдает этот тип исключения? Должен ли я объявить, что могу генерировать все транзитивно сгенерированные непроверенные исключения в вызываемом коде? 2) Если они не заявляют, что метод throws NPE, могу ли я знать, что он выдает NPE без доступа к их коду? - person Andy Turner; 03.07.2014
comment
1) Если вы ожидаете, что ваш NPE не критическая ситуация, т.е. это часть вашей бизнес-логики (я не рекомендую такое поведение) - тогда включите его в throws 2) Нет, вы не можете - person Nailgun; 03.07.2014
comment
Я думаю, что если вы собираетесь использовать API без связанной с ним документации, вы все равно идете по опасной линии. Я поддерживаю только указания Javadoc. - person Duncan Jones; 09.09.2014

Исключения используются для сообщения о 3 типах проблем:

  • Проблемы с JVM и низкоуровневой средой выполнения.
  • Обнаружены логические ошибки (баги).
  • Проблемы во время выполнения, которые программист не может предсказать до выполнения операции.

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

Теперь мне кажется очевидным, что разработчики языка Java намеревались использовать проверенные исключения и только проверенные исключения для этого третьего типа. Если бы так было всегда, простым ответом на ваш вопрос было бы: нет, не объявлять непроверенные исключения в предложении throws.

Но есть осложнение. Это теперь довольно распространено (популяризировано Spring), чтобы избежать проверенных исключений для этого третьего типа и почти во всех случаях использовать непроверенные исключения. Если вы программируете в этом стиле, может быть полезно использовать предложение throws для объявления непроверенных исключений.

person Raedwald    schedule 22.11.2017