Вопрос

Я работаю на .NET и сейчас увлекаюсь Java.

В настоящее время у меня большие проблемы с разработкой API, защищающего от ошибочных входных данных.Допустим, у меня есть следующий код (достаточно близко):

public void setTokens(Node node, int newTokens) {
    tokens.put(node, newTokens);
}

Однако этот код может дать сбой по двум причинам:

  1. Пользователь передает null узел.
  2. Пользователь передает недопустимый узел, т.е.тот, который не содержится в графике.

В .NET я бы бросил ArgumentNullException (а не NullReferenceException!) или ArgumentException соответственно, передавая имя нарушающего аргумента (node) как string аргумент.

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

Это лучшая практика?Или существуют классы общего назначения, подобные ArgumentException в .NET?

Имеет ли вообще смысл проверять null в этом случае?Код в любом случае завершится ошибкой, и трассировка стека исключения будет содержать указанный выше вызов метода.Проверка против null кажется излишним и чрезмерным.Конечно, трассировка стека будет немного очиститель (поскольку его целью является описанный выше метод, а не внутренняя проверка в HashMap реализация JRE).Но это необходимо компенсировать стоимостью дополнительного if заявление, которое, кроме того, должно никогда произойти в любом случае – в конце концов, проходя null к вышеописанному методу — это не ожидаемая ситуация, это довольно глупая ошибка.Ожидать этого — это просто параноидально — и произойдет сбой с тем же исключением, даже если я его не проверю.

[Как было отмечено в комментариях, HashMap.put на самом деле позволяет null значения для ключа.Итак, проверка против null здесь не обязательно будет лишним.]

Это было полезно?

Решение

В разных группах разные стандарты.

Во-первых, я предполагаю, что вы знаете разницу между RuntimeExceptions (не отмечено) и нормально Exceptions (проверено), если нет, то см. этот вопрос и ответы.Если вы напишете собственное исключение, вы можете принудительно его перехватить, тогда как оба NullPointerException и IllegalArgumentException являются RuntimeExceptions, которые не одобряются в некоторых кругах.

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

Если бы я был тобой, я бы использовал NullPointerException.Причиной тому является прецедент.Возьмем, к примеру, Java API от Sun. java.util.TreeSet.Здесь используются NPE именно для таких ситуаций, и хотя выглядит так, будто ваш код только что использовал ноль, это вполне уместно.

Как говорили другие IllegalArgumentException это вариант, но я думаю, что NullPointerException более коммуникативен.

Если этот API предназначен для использования сторонними компаниями/командами, я бы придерживался NullPointerException, но убедитесь, что он объявлен в javadoc.Если это для внутреннего использования, вы можете решить, что добавление собственной иерархии исключений имеет смысл, но лично я считаю, что API, которые добавляют огромные иерархии исключений, которые будут только printStackTrace()d или logged — это просто пустая трата усилий.

В конце концов, главное, чтобы ваш код был понятен.Локальная иерархия исключений похожа на местный жаргон: она добавляет информацию для инсайдеров, но может сбить с толку посторонних.

Что касается проверки на ноль, я бы сказал, что это имеет смысл.Во-первых, это позволяет вам добавлять сообщение о том, что было нулевым (т.е. узел или токены) при создании исключения, что было бы полезно.Во-вторых, в будущем вы можете использовать Map реализация, которая позволяет null, и тогда вы потеряете проверку ошибок.Стоимость почти ничего не стоит, поэтому, если профилировщик не скажет, что это проблема внутреннего цикла, я бы не стал об этом беспокоиться.

Другие советы

Стандартное исключение Java - IllegalArgumentException . Некоторые выдают NullPointerException , если аргумент равен нулю, но для меня в NPE это "кто-то облажался" коннотации, и вы не хотите, чтобы клиенты вашего API думали, что вы не знаете, что делаете.

Для общедоступных API проверьте аргументы и проваливайтесь рано и аккуратно. Время / стоимость едва ли имеют значение.

В Java обычно выдается исключение IllegalArgumentException

Если вы хотите получить руководство о том, как писать хороший код Java, я настоятельно рекомендую книгу Эффективная Java Джошуа Блоха.

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

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

Однако, если вы, например, предоставляете стороннюю библиотеку, которая распространяется, вам нужно проверить узел на null, etcs ...

Незаконное исключение ArugementException является стандартом Java, но также является исключением RunTimeException. Поэтому, если вы хотите, чтобы вызывающая сторона обрабатывала исключение, вам нужно предоставить исключение проверки, возможно, пользовательское, которое вы создаете.

Лично я бы хотел, чтобы исключения NullPointerException происходили ТОЛЬКО случайно, поэтому необходимо указать что-то еще, чтобы указать, что было передано недопустимое значение аргумента. IllegalArgumentException отлично подходит для этого.

if (arg1 == null) {
 throw new IllegalArgumentException("arg1 == null");
}

Этого должно быть достаточно как для тех, кто читает код, так и для бедной души, которая получает звонок в службу поддержки в 3 часа утра.

(и, ВСЕГДА, предоставьте пояснительный текст для ваших исключений, вы оцените их в один печальный день)

как и другие: java.lang.IllegalArgumentException. О проверке нулевого узла, как насчет проверки неверного ввода при создании узла?

Мне не нужно никому угодить, так что теперь я делаю канонический код

void method(String s) 

if((s != null) && (s instanceof String) && (s.length() > 0x0000))
{

который дает мне много сна.

Другие не согласятся.

scroll top