Когда следует создать исключение 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. Похоже, его не следует использовать, и мы должны придерживаться наших собственных отмеченное исключение. Что такое хороший случай использования, чтобы бросить это?

565   6  

6 ответов:

API doc для IllegalArgumentException является:

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

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

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

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

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

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

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

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

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

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

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

любой 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% ошибок времени в приложении, потому что он запрашивает невозможные операции, поэтому в конце концов они являются ошибками, которые должны привести к сбою приложения (так что это не восстанавливаемая ошибка).

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

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

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

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

лечения IllegalArgumentException как предпосылки проверьте и рассмотрите принцип проектирования:публичный метод должен знать и публично документировать свои собственные предварительные условия.

Я бы согласился, что этот пример правильный:

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

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

import com.someoneelse.EmailUtil;

public void scanEmail(String emailStr, InputStream mime) throws ParseException {
    EmailAddress parsedAddress = EmailUtil.parseAddress(emailStr);
}

если EmailUtil прозрачен, например, возможно, это частный метод, принадлежащий рассматриваемому классу,IllegalArgumentException правильно тогда и только тогда, когда его предварительные условия могут быть описаны в документации по функции. Это правильная версия, а также:

/** @param String email An email with an address in the form [email protected]
 * with no nested comments, periods or other nonsense.
 */
public String scanEmail(String email)
  if (!addressIsProperlyFormatted(email)) {
      throw new IllegalArgumentException("invalid address");
  }
  return parseEmail(emailAddr);
}
private String parseEmail(String emailS) {
  // Assumes email is valid
  boolean parsesJustFine = true;
  // Parse logic
  if (!parsesJustFine) {
    // As a private method it is an internal error if address is improperly
    // formatted. This is an internal error to the class implementation.
    throw new AssertError("Internal error");
  }
}

эта конструкция может пойти в любую сторону.

  • если предварительные условия дорого описывать, или если класс предназначен для использования клиенты, которые не знают, действительны ли их электронные письма, затем используют ParseException. Метод верхнего уровня здесь называется scanEmail который намекает, что конечный пользователь намерен отправить неизученную электронную почту, поэтому это, вероятно, правильно.
  • если предварительные условия могут быть описаны в документации по функциям, а класс не предназначен для недопустимого ввода и поэтому указана ошибка программиста, используйте IllegalArgumentException. Хотя и не "проверил" "проверить" движется к javadoc документирования функций, которые клиент должны придерживаться. IllegalArgumentException где клиент не может сказать, что их аргумент является незаконным заранее неправильно.

примечание о IllegalStateException: это означает, что " внутреннее состояние этого объекта (частные переменные экземпляра) не может выполнить это действие."Конечный пользователь не может видеть частное государство так свободно говоря, что оно имеет приоритет над IllegalArgumentException в случае, когда вызов клиента не имеет возможности узнать состояние объекта, является необоснованной. Я у вас нет хорошего объяснения, когда это предпочтительнее, чем проверенные исключения, хотя такие вещи, как инициализация дважды или потеря соединения с базой данных, которое не восстановлено, являются примерами.

Comments

    Ничего не найдено.