Подтвердить что ты не робот

Java API Design: NumberFormatException для метода, который анализирует полуцифровую строку?

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

1. java.lang.IllegalArgumentException - неверная строка явно является незаконным аргументом, но для меня IllegalArgumentException обычно означает ошибку программирования, и редко бывает необходимо сделать явный try catch для одного. Я считаю, что синтаксический анализ часто используется для внешнего ввода и представляет собой особый случай, заслуживающий особого внимания. Если, скажем, у вас был большой блок кода, который анализировал ввод пользователя и делал что-то еще с ним, вы можете захотеть обернуть этот код в блок catch try, чтобы вы могли обработать случай ввода пользователя, содержащий недопустимую строку. Но ловить IllegalArgumentException было бы не очень удобно для определения неверного ввода пользователя, потому что, скорее всего, в вашем коде было бы несколько мест, из которых он мог бы быть удален (не только синтаксический анализ пользователя).

2. java.lang.NumberFormatException - он подбрасывается Integer.parseInt(String) и другими подобными методами анализа в java.lang. Поэтому большинство разработчиков Java знакомы с тем, что это исключение для catch, когда вы пытаетесь разобрать строку, которая может быть или не быть действительной (например, пользовательский ввод). Но он получил "Number" в своем названии, поэтому я не уверен, что он действительно подходит для таких вещей, как даты и времена, которые в некотором смысле являются числовыми, но концептуально разные в моем сознании. Если бы это называлось "FormatException"...

3. java.text.ParseException - не вариант, потому что он проверен. Я не хочу отмечать это.

4. Пользовательское исключение - это обходит нижние стороны IllegalArgumentException и NumberFormatException, и это может также расширить IllegalArgumentException. Но я не думаю, что это хорошая идея добавить исключения в библиотеку, если они действительно не нужны. Цитата Джоша Блоха, "Если есть сомнения, оставьте это" . (Кроме того, в моем случае для пакета, который анализирует даты и время, довольно сложно назвать такое исключение: "DateFormatException", "TimeFormatException", "CalendricalFormatException" (например, JSR 310) - ничто не кажется идеальным для меня при применении к методам которые анализируют даты, времена, даты и т.д. И я думаю, было бы глупо создавать несколько исключений в одном пакете, если бы они были просто использованы для идентификации непревзойденных строк.)

Итак, какой вариант, по вашему мнению, имеет наибольший смысл?

NB Есть веские причины для меня не желать использовать java.util.Date или Joda Time, или JSR 310, поэтому нет необходимости предлагать их. Плюс, я думаю, было бы хорошо, если бы этот вопрос оставался достаточно общим, так как это должно быть проблемой, с которой боролись другие люди, разрабатывающие API. Даты и время также могут быть IP-адресами или URL-адресами или любой другой информацией, которая имеет строковые форматы, требующие разбора.

Прецеденты, установленные другими библиотеками

Всего несколько примеров, которые я нашел:

java.sql.Timestamp.valueOf(String) throws IllegalArgumentException

java.util.Date.parse(String) throws IllegalArgumentException (устаревший метод, и исключение не объявлено, но вы можете увидеть его в источнике)

java.util.UUID.fromString(String) throws IllegalArgumentException

org.apache.axis.types.Time(String) throws NumberFormatException (также Day class в оси Apache)

org.apache.tools.ant.util.DeweyDecimal(String) throws NumberFormatException

com.google.gdata.data.DateTime.parseDateTime(String) throws NumberFormatException

java.lang.Package.isCompatibleWith(String versionString) throws NumberFormatException (в Java 7 это принимает номер версии строки с точками - вроде даты или времени в некотором смысле)

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

4b9b3361

Ответ 1

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

  • IllegalArgumentException для небольшой API (несколько методов)
  • ваша собственная иерархия классов, которая наследует от IllegalArgumentException в противном случае.

В любом случае я бы использовал IllegalArgumentException как базовый класс.

В одном из моих предыдущих проектов руководство должно было только вызывать RuntimeExceptions, которые наследуют от

  • IllegalStateException
  • IllegalArgumentException
  • UnsupportedOperationException

Хотя это не официальная догма, я бы назвал ее хорошей практикой. Все три из них просты и самоописаны.

Ответ 2

Я бы выбрал ParseException, потому что тот, который выдает DateFormat.parse. Таким образом, это имеет то преимущество, о котором вы упомянете в 2. Программисты, знакомые с ним. Но так как вы хотите неконтролируемого, я думаю, это не вариант. Если вы будете вынуждены пойти для снятия флажка, я выберу 4.

Ответ 3

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

Ответ 4

В настоящее время я склоняюсь к использованию NumberFormatException. Я думал о старом IllegalArgumentException, но мне стало ясно, что это не идеально, когда я написал небольшой код, например:

try {
    final Day day = Day.fromString(userInputString);
    someMethodThatCouldAlsoThrowIllegalArgumentException(day);
} catch (IllegalArgumentException e) {
    ui.showWarningMessage("Invalid date: " + userInputString);
}

Предполагая, что вы проанализируете действительный Day, вам нужно что-то сделать с ним. И очень вероятно, что методы, которые вы передали бы ему, будут бросать IllegalArgumentException, если они получили недопустимый параметр (т.е. Ошибку программирования, а не ошибку пользователя). В коде, подобном приведенному выше примеру, вы должны быть осторожны, чтобы не путать ошибку программирования для недопустимого ввода пользователя, поэтому, чтобы быть в безопасности, вам понадобится что-то грязное, как пустая переменная, определенная до блока try/catch, и проверите значение null после него.

Сменить IllegalArgumentException для NumberFormatException или настраиваемое исключение, и проблема исчезнет.

Увидев, что JDK 1.7 java.lang.Package.isCompatibleWith(String versionNo) использует NumberFormatException для метода, который анализирует номер версии (полуцифровая строка типа "1.6.1.32"), я думаю, что это также может быть разумным выбором для методов, которые анализируют такие вещи, как даты и время.

NumberFormatException не идеально подходит для разбора строк, которые являются только полумиллиарными, но, возможно, это лучший вариант, когда вы не хотите загромождать API с настраиваемым исключением, которое действительно не нужно. Если они делают это в java.lang, то, возможно, это делает способ Java делать вещи по определению...

Я надеюсь, что это поймает:)