Когда следует исключить исключение IllegalArgumentException?

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

void setPercentage(int pct) {
    if( pct < 0 || pct > 100) {
         throw new IllegalArgumentException("bad percent");
     }
}

Но похоже, что это заставило бы следующий дизайн:

public void computeScore() throws MyPackageException {
      try {
          setPercentage(userInputPercent);
      }
      catch(IllegalArgumentException exc){
           throw new MyPackageException(exc);
      }
 }

Чтобы вернуться к проверке исключения.

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

public void scanEmail(String emailStr, InputStream mime) {
    try {
        EmailAddress parsedAddress = EmailUtil.parse(emailStr);
    }
    catch(ParseException exc){
        throw new IllegalArgumentException("bad email", exc);
    }
}

И хуже - при проверке 0 <= pct && pct <= 100 можно ожидать, что клиентский код будет делать статически, это не так для более продвинутых данных, таких как адрес электронной почты или, что еще хуже, что-то, что нужно проверить в базе данных, поэтому в общий код клиента не может быть предварительно проверен.

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

Ответ 1

Api doc для исключения IllegalArgumentException:

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

От взгляда на как он используется в библиотеках jdk, я бы сказал:

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

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

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

Ответ 2

Говоря о "плохом вводе", вы должны учитывать, откуда поступает вход.

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

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

Ответ 3

Исключение исключений во время выполнения "экономно" на самом деле не является хорошей политикой. Эффективная Java рекомендует использовать проверенные исключения, когда вызывающий абонент может разумно ожидать восстановления. (Ошибка программиста - это конкретный пример: если конкретный случай указывает на ошибку программиста, тогда вы должны выбросить исключенное исключение, вы хотите, чтобы у программиста была трассировка стека, где возникла логическая проблема, а не пытаться справиться с ней самостоятельно.)

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

Это не 100% ясно из вашего примера, какой случай этот пример находится в вашем коде.

Ответ 4

Как указано в официальном руководстве oracle, в нем указано, что:

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

Если у меня есть приложение, взаимодействующее с базой данных с помощью JDBC, и у меня есть метод, который принимает аргумент как int item и double price. Элемент price для соответствующего элемента считывается из таблицы базы данных. Я просто умножаю общее количество item, приобретенных с помощью значения price, и возвращаю результат. Хотя я всегда уверен в конце (конец приложения), что значение поля цены в таблице никогда не может быть отрицательным. Но что, если значение цены выходит отрицательно? Это показывает, что с базой данных существует серьезная проблема. Возможно, неправильный ввод цены оператором. Это та проблема, что другая часть приложения, вызывающая этот метод, не может ожидать и не может оправиться от него. Это BUG в вашей базе данных. Итак, и IllegalArguementException() следует выбросить в этом случае, чтобы указать, что the price can't be negative.
Надеюсь, что я четко изложил свою точку зрения.

Ответ 5

Любой API должен проверять правильность каждого параметра любого общедоступного метода перед его выполнением:

void setPercentage(int pct, AnObject object) {
    if( pct < 0 || pct > 100) {
        throw new IllegalArgumentException("pct has an invalid value");
    }
    if (object == null) {
        throw new IllegalArgumentException("object is null");
    }
}

Они представляют 99,9% случаев ошибок в приложении, потому что они запрашивают невозможные операции, поэтому в конце концов они являются ошибками, которые должны привести к сбою приложения (так что это невосстановимая ошибка).

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