Мне интересно, должен ли я защищаться от возвращаемого значения вызова метода, проверяя, соответствуют ли они моим ожиданиям, даже если я знаю, что метод, который я вызываю, будет соответствовать этим ожиданиям.
ДАННЫЙ
User getUser(Int id)
{
User temp = new User(id);
temp.setName("John");
return temp;
}
Я ДОЛЖЕН ДЕЛАТЬ
void myMethod()
{
User user = getUser(1234);
System.out.println(user.getName());
}
ИЛИ
void myMethod()
{
User user = getUser(1234);
// Validating
Preconditions.checkNotNull(user, "User can not be null.");
Preconditions.checkNotNull(user.getName(), "User's name can not be null.");
System.out.println(user.getName());
}
Я спрашиваю об этом на концептуальном уровне. Если я знаю внутреннюю работу метода, который я вызываю. Либо потому что я это написал, либо я его осмотрел. И логика возможных значений, которые он возвращает, отвечает моим предварительным условиям. Является ли «лучше» или «более подходящим» пропустить проверку, или мне все равно следует защищаться от неправильных значений, прежде чем продолжить с методом, который я сейчас реализую, даже если он всегда должен проходить.
Мой вывод из всех ответов (смело приходите к своим):
Утверждать когда- Метод показал себя плохо в прошлом
- Метод из ненадежного источника
- Этот метод используется из других мест и явно не указывает его постусловия
- Метод живет близко к вашему (подробности см. В выбранном ответе)
- Метод явно определяет его контракт с чем-то вроде надлежащего документа, безопасности типа, модульного теста или проверки после условия
- Производительность имеет решающее значение (в этом случае утверждение режима отладки может работать как гибридный подход)
Null
)? Вероятно, одинаково проблематично, если имя""
(не ноль, а пустая строка) или"N/A"
. Либо вы можете доверять результату, либо вы должны быть соответственно параноиком.Ответы:
Это зависит от того, насколько вероятны изменения getUser и myMethod, и, что более важно, насколько вероятно, что они изменятся независимо друг от друга .
Если вы как-то точно знаете, что getUser никогда и никогда не изменится в будущем, тогда да, это пустая трата времени на его проверку, равно как и на потерю времени на проверку,
i
значение которой равно 3 сразу послеi = 3;
выражения. На самом деле, вы этого не знаете. Но есть некоторые вещи, которые вы знаете:Эти две функции "живут вместе"? Другими словами, поддерживают ли их одни и те же люди, являются ли они частью одного и того же файла, и, следовательно, могут ли они оставаться "синхронизированными" друг с другом самостоятельно? В этом случае, вероятно, излишне добавлять проверочные проверки, поскольку это просто означает, что больше кода должно изменяться (и потенциально вызывать ошибки) каждый раз, когда две функции изменяются или подвергаются рефакторингу в разное количество функций.
Является ли функция getUser частью документированного API с конкретным контрактом, а myMethod - просто клиентом указанного API в другой кодовой базе? Если это так, вы можете прочитать эту документацию, чтобы узнать, должны ли вы проверять возвращаемые значения (или предварительно проверять входные параметры!) Или действительно ли безопасно слепо следовать счастливому пути. Если документация не проясняет это, попросите сопровождающего исправить это.
Наконец, если эта конкретная функция внезапно и неожиданно изменила свое поведение в прошлом, таким образом, что это нарушило ваш код, вы имеете полное право быть параноиком по этому поводу. Ошибки склонны к скоплению.
Обратите внимание, что все вышеперечисленное применимо, даже если вы являетесь автором обеих функций. Мы не знаем, будут ли эти две функции «жить вместе» всю оставшуюся жизнь, или они медленно разойдутся на отдельные модули, или вы как-то застрелились в ноге с ошибкой в старшей версии версии getUser. Но вы, вероятно, можете сделать довольно приличное предположение.
источник
getUser
позже, чтобы он мог вернуть ноль, даст ли явная проверка информацию, которую вы не можете получить из «NullPointerException», и номер строки?Ответ Икрека хорош, но я выберу другой подход, потому что считаю, что его стоит рассмотреть. В целях этой дискуссии я буду говорить об утверждениях, так как это имя, под которым вы
Preconditions.checkNotNull()
традиционно известны.Я хотел бы предложить, чтобы программисты часто переоценивали степень уверенности в том, что что-то будет вести себя определенным образом, и недооценивали последствия того, что это не будет вести себя таким образом. Кроме того, программисты часто не осознают силу утверждений в качестве документации. Впоследствии, по моему опыту, программисты утверждают вещи гораздо реже, чем следовало бы.
Мой девиз:
Естественно, если вы абсолютно уверены , что что-то ведет себя определенным образом, вы воздержитесь от утверждения, что оно действительно ведет себя таким образом, и это по большей части разумно. На самом деле невозможно писать программы, если вы не можете доверять чему-либо.
Но есть исключения даже из этого правила. Как ни странно, если взять пример Иксрека, существует тип ситуации, когда совершенно желательно следовать
int i = 3;
утверждению,i
которое действительно находится в определенном диапазоне. Это ситуация, в которойi
может измениться кто-то, кто пробует различные сценарии типа «что-если», а следующий код полагается наi
наличие значения в определенном диапазоне, и это не сразу становится очевидным, если быстро взглянуть на следующий код, что приемлемый диапазон Таким образом,int i = 3; assert i >= 0 && i < 5;
на первый взгляд это может показаться бессмысленным, но если вы подумаете об этом, это говорит о том, что вы можете играть с нимi
, а также о диапазоне, в котором вы должны оставаться. Утверждение является лучшим типом документации, потому чтоэто обеспечивается машиной , поэтому это идеальная гарантия, и он подвергается рефакторингу вместе с кодом , поэтому он всегда остается актуальным.Ваш
getUser(int id)
пример не очень отдаленный концептуальный родственникassign-constant-and-assert-in-range
примера. Вы видите, по определению, ошибки случаются, когда вещи демонстрируют поведение, отличное от ожидаемого нами поведения. Правда, мы не можем утверждать все, поэтому иногда будет некоторая отладка. Но в отрасли хорошо известно, что чем быстрее мы обнаружим ошибку, тем меньше она будет стоить. Вопросы, которые вы должны задать, касаются не только того, насколько вы уверены, чтоgetUser()
никогда не вернете нулевое значение (и никогда не вернете пользователя с нулевым именем), но и того, какие плохие вещи будут происходить с остальным кодом, если это произойдет в факт один день возвращения что - то неожиданное, и как легко, быстро , глядя на остальной части кода , чтобы знать точно , что ожидалосьgetUser()
.Если непредвиденное поведение приведет к повреждению базы данных, возможно, вам следует заявить об этом, даже если вы на 101% уверены, что этого не произойдет. Если
null
имя пользователя вызовет какую-то странную загадочную нерасследуемую ошибку на тысячи строк дальше и на миллиарды тактов позже, то, возможно, лучше всего потерпеть неудачу как можно раньше.Поэтому, даже если я не согласен с ответом Ixrec, я бы посоветовал вам серьезно рассмотреть тот факт, что утверждения ничего не стоят, поэтому на самом деле ничего нельзя потерять, только получить, используя их свободно.
источник
... && sureness < 1)
.Определенное нет.
Вызывающий никогда не должен проверять, соблюдает ли вызываемая функция свой контракт. Причина проста: потенциально вызывающих абонентов очень много, и с концептуальной точки зрения непрактично и, возможно, даже неправильно для каждого вызывающего абонента дублировать логику для проверки результатов других функций.
Если необходимо выполнить какие-либо проверки, каждая функция должна проверять свои собственные пост-условия. Постусловия дают вам уверенность в том, что вы правильно реализовали функцию, и пользователи смогут рассчитывать на контракт вашей функции.
Если определенная функция не предназначена для возврата нуля, это должно быть задокументировано и стать частью контракта этой функции. В этом смысл этих контрактов: предлагайте пользователям некоторые инварианты, на которые они могут положиться, чтобы они сталкивались с меньшими трудностями при написании своих собственных функций.
источник
Если null является допустимым возвращаемым значением метода getUser, то ваш код должен обрабатывать это с помощью If, а не Exception - это не исключительный случай.
Если null не является допустимым возвращаемым значением метода getUser, то в getUser есть ошибка - метод getUser должен генерировать исключение или иным образом исправляться.
Если метод getUser является частью внешней библиотеки или не может быть изменен иным образом, и вы хотите, чтобы исключения генерировались в случае нулевого возврата, оберните класс и метод для выполнения проверок и сгенерируйте исключение, чтобы каждый экземпляр вызов getUser соответствует вашему коду.
источник
Я бы сказал, что предпосылка вашего вопроса не верна: зачем использовать нулевую ссылку для начала?
Модель объекта нулевого способ вернуть объекты , которые по существу ничего не делать: вместо возврата NULL для вашего пользователя, возвращает объект , который не представляет «нет пользователя.»
Этот пользователь будет неактивен, будет иметь пустое имя и другие ненулевые значения, указывающие «здесь ничего нет». Основным преимуществом является то, что вам не нужно мусорить, ваша программа будет иметь нулевые проверки, ведение журнала и т. Д. Вы просто используете свои объекты.
Почему алгоритм должен заботиться о нулевом значении? Шаги должны быть одинаковыми. Так же просто и намного понятнее иметь нулевой объект, который возвращает ноль, пустую строку и т. Д.
Вот пример проверки кода на ноль:
Вот пример кода, использующего нулевой объект:
Что яснее? Я считаю, что второй.
Хотя вопрос помечен как java , стоит отметить, что шаблон нулевого объекта действительно полезен в C ++ при использовании ссылок. Ссылки на Java больше похожи на указатели C ++ и допускают null. C ++ ссылки не могут храниться
nullptr
. Если кто-то хотел бы иметь что-то аналогичное нулевой ссылке в C ++, шаблон нулевого объекта - единственный способ, которым я знаю, для достижения этой цели.источник
getCount()
документы гарантируют, что она не вернет 0 и не будет делать это в будущем, за исключением случаев, когда кто-то решит внести решающее изменение и попытается обновить все, что вызывает его, чтобы справиться с ним. новый интерфейс. Просмотр того, что в данный момент делает код, не поможет, но если вы собираетесь проверять код, то проверяемый код - это модульные тестыgetCount()
. Если они проверят, чтобы оно не возвращало 0, то вы знаете, что любое будущее изменение с возвратом 0 будет считаться критическим изменением, потому что тесты не пройдут.Как правило, я бы сказал, что это зависит главным образом от следующих трех аспектов:
Надежность: может ли вызывающий метод справиться со
null
значением? Еслиnull
значение может привестиRuntimeException
к проверке, я бы порекомендовал проверить - если сложность не низкая, а вызываемые / вызывающие методы создаются одним и тем же автором иnull
не ожидаются (например, обаprivate
в одном пакете).ответственность за код: если разработчик A отвечает за
getUser()
метод, а разработчик B использует его (например, как часть библиотеки), я настоятельно рекомендую проверить его значение. Просто потому, что разработчик B может не знать об изменении, которое может привести к потенциальномуnull
возвращаемому значению.сложность: чем выше общая сложность программы или среды, тем больше я бы рекомендовал проверить возвращаемое значение. Даже если вы уверены в том, что это не может быть
null
сегодня в контексте вызывающего метода, возможно, вам придется изменитьgetUser()
другой вариант использования. По прошествии нескольких месяцев или лет и добавления нескольких тысяч строк кодов это может стать ловушкой.Кроме того, я бы порекомендовал документировать потенциальные
null
возвращаемые значения в комментарии JavaDoc. Благодаря выделению описаний JavaDoc в большинстве IDE, это может быть полезным предупреждением для тех, кто их используетgetUser()
.источник
Вы определенно не должны.
Например, если вы уже знаете, что возврат никогда не может быть нулевым - зачем вам добавлять пустую проверку? Добавление нулевой проверки ничего не сломает, а просто избыточно. И лучше не кодировать избыточную логику, пока вы можете ее избежать.
источник