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

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

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 полезно. Мне было бы интересно узнать мнение других об этом.

Ответ 1

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

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

  • Переобрести себя как бросание того же исключения.
  • Поймать исключение и справиться с ним.

В случае 1 он может напомнить пользователю реализовать finally - который может быть бонусом.

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

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

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

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

Ответ 2

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

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

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

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

Ответ 3

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

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

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

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

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