Java API Design: NumberFormatException для метода, который анализирует полу-числовую строку? - PullRequest
12 голосов
/ 15 апреля 2011

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

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

2. java.lang.NumberFormatException - он генерируется Integer.parseInt(String) и другими подобными методами синтаксического анализа в java.lang. Поэтому большинству разработчиков Java известно, что это исключение, которое нужно отлавливать, когда вы пытаетесь проанализировать строку, которая может или не может быть действительной (например, пользовательский ввод). Но у него есть «Число» в его названии, поэтому я не уверен, что оно действительно подходит для таких вещей, как даты и время, которые в некотором смысле являются числовыми, но концептуально отличаются в моем представлении. Если бы только это называлось "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 (также Дневной класс по Apache Axis)

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 для этого используется номер строковой версии с точками - вроде как дата или время в некотором смысле)

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

Ответы [ 4 ]

3 голосов
/ 15 апреля 2011

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

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

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

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

  • IllegalStateException
  • IllegalArgumentException
  • UnsupportedOperationException

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

1 голос
/ 15 апреля 2011

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

0 голосов
/ 15 апреля 2011

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

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

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

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

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

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

Я надеюсь, что это зацепит:)

0 голосов
/ 15 апреля 2011

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

...