У меня есть код, который терпит неудачу из-за NullPointerException. Метод вызывается на объекте, где объект не существует.
Однако это заставило меня задуматься о том, как лучше это исправить. Всегда ли я кодирую для защиты нулевых значений, чтобы я мог в будущем использовать код для исключений нулевого указателя, или я должен исправить причину нулевого значения, чтобы это не происходило в нисходящем направлении.
о чем ты думаешь?
Ответы:
Если для вашего метода приемлемый входной параметр, исправьте метод. Если нет, исправьте звонящего. «Разумный» - это гибкий термин, поэтому я предлагаю следующий тест: Как метод должен обрабатывать нулевой ввод? Если вы найдете более одного возможного ответа, то null не является разумным вводом.
источник
Precondition.checkNotNull(...)
. См stackoverflow.com/questions/3022319/...IllegalArgumentException
null. Это сигнализирует вызывающим методам, что ошибка в их коде (а не в самом методе).Не используйте ноль, используйте Необязательный
Как вы указали, одной из самых больших проблем
null
в Java является то, что он может использоваться везде или, по крайней мере, для всех ссылочных типов.Невозможно сказать, что может быть,
null
а что нет.Java 8 предоставляет гораздо лучше картина:
Optional
.И пример из Oracle:
Если каждый из них может или не может вернуть успешное значение, вы можете изменить API на
Optional
s:Благодаря явному кодированию опциональности в типе ваши интерфейсы будут намного лучше, а ваш код - более чистым.
Если вы не используете Java 8, вы можете посмотреть
com.google.common.base.Optional
в Google Guava.Хорошее объяснение от команды Guava: https://github.com/google/guava/wiki/UsingAndAvoidingNullExplained
Более общее объяснение недостатков, связанных с нулем, с примерами на нескольких языках: https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/
@Nonnull, @Nullable
Java 8 добавляет эти аннотации, чтобы помочь инструментам проверки кода, таким как IDE, выявлять проблемы. Они довольно ограничены в своей эффективности.
Проверьте, когда это имеет смысл
Не пишите 50% кода, проверяющего ноль, особенно если нет ничего разумного, что ваш код может сделать со
null
значением.С другой стороны, если это
null
можно использовать и что-то значить, обязательно используйте его.В конечном счете, вы, очевидно, не можете удалить
null
из Java. Я настоятельно рекомендую заменятьOptional
абстракцию всякий раз, когда это возможно, и проверять вnull
других случаях, что вы можете сделать что-то разумное с этим.источник
NullPointerException
? ANullPointerException
может происходить буквально каждый раз, когда вы вызываете метод экземпляра в Java. Вы бы имелиthrows NullPointerException
почти в каждом методе когда-либо.Есть несколько способов справиться с этим, перетаскивание вашего кода
if (obj != null) {}
не идеально, это грязно, это добавляет шум при чтении кода позже во время цикла обслуживания и подвержено ошибкам, так как это легко забыть сделать оберткой.Это зависит от того, хотите ли вы, чтобы код продолжал тихо выполняться или не работал. Это
null
ошибка или ожидаемое состояние.Что такое ноль
В каждом определении и случае Null представляет абсолютный недостаток данных. Нули в базах данных представляют отсутствие значения для этого столбца. null
String
- это не то же самое, что пустоеString
, nullint
- это не то же самое, что ZERO, в теории. На практике «это зависит». EmptyString
может сделать хорошуюNull Object
реализацию для класса String, посколькуInteger
это зависит от бизнес-логики.Альтернативы:
Null Object
Узор. Создайте экземпляр вашего объекта, который представляетnull
состояние, и инициализируйте все ссылки на этот тип со ссылкой наNull
реализацию. Это полезно для простых объектов типа значения, которые не имеют большого количества ссылок на другие объекты, которые также могут бытьnull
и, как ожидается, будутnull
в качестве допустимого состояния.Используйте ориентированные на аспект инструменты, чтобы связать методы с
Null Checker
аспектом, который предотвращает нулевые параметры. Это для случаев, когдаnull
есть ошибка.Используйте
assert()
не намного лучше,if (obj != null){}
но меньше шума.Используйте инструмент исполнения контрактов, такой как Contracts For Java . Тот же сценарий использования, что и в AspectJ, но более новый и использует аннотации вместо внешних файлов конфигурации. Лучшие из работ Аспектов и Актеров.
1 является идеальным решением, когда известно, что входящие данные
null
должны быть заменены на какое-то значение по умолчанию, чтобы потребителям, работающим в восходящем потоке, не приходилось иметь дело со всем стандартным кодом проверки нуля. Проверка на известные значения по умолчанию также будет более выразительной.2, 3 и 4 - просто удобные альтернативные генераторы исключений, которые можно заменить
NullPointerException
на что-то более информативное, что всегда и является улучшением.В конце
null
в Java почти во всех случаях логическая ошибка. Вы должны всегда стремиться устранить первопричинуNullPointerExceptions
. Вы должны стремиться не использоватьnull
условия в качестве бизнес-логики.if (x == null) { i = someDefault; }
просто сделайте начальное присвоение этому экземпляру объекта по умолчанию.источник
null
не неожиданно, то это истинная ошибка, тогда все должно полностью остановиться.null == null
(даже в PHP), но в базах данных,null != null
поскольку в базах данных он представляет собой неизвестное значение, а не «ничто». Два неизвестных не обязательно равны, а два ничто не равны.Добавление нулевых проверок может сделать тестирование проблематичным. Посмотрите эту прекрасную лекцию ...
Ознакомьтесь с лекцией Google Tech: «Чистые переговоры по коду - не ищите!» он говорит об этом около минуты 24
http://www.youtube.com/watch?v=RlfLCWKxHJ0&list=PL693EFD059797C21E
Параноидальное программирование включает в себя добавление нулевых проверок везде. Поначалу это кажется хорошей идеей, однако, с точки зрения тестирования, это затрудняет работу с типом проверки нулевой проверки.
Кроме того, когда вы создаете предварительное условие для существования некоторого объекта, такого как
это мешает вам создать Дом, так как вы будете выдавать исключение. Предположим, что ваши тестовые сценарии создают фиктивные объекты для тестирования чего-то другого, кроме Door, ну, вы не можете сделать это, потому что door требуется
Те, кто пострадал от ада создания Насмешек, хорошо знают об этих типах раздражения.
Таким образом, ваш набор тестов должен быть достаточно надежным, чтобы тестировать двери, дома, крыши или что-то еще, не будучи параноиком по этому поводу. Seroiusly, как трудно добавить тест нулевой проверки для конкретных объектов в вашем тестировании :)
Вы всегда должны отдавать предпочтение приложениям, которые работают, потому что у вас есть несколько тестов, которые ДОКАЗЫВАЮТ, что они работают, а не НАДЕЖДА, что это работает просто потому, что у вас есть целая куча предварительных проверок нуля повсюду
источник
tl; dr - ХОРОШО проверять наличие неожиданностей,
null
но ПЛОХО для приложения, чтобы попытаться сделать их хорошими.Детали
Ясно, что существуют ситуации, когда
null
допустимый ввод или вывод метода, и другие, где это не так.Правило № 1:
Правило № 2:
Учитывая четкую спецификацию метода "контракта" по отношению к
null
s, это ошибка программирования для передачи или возврата туда,null
где вы не должны.Правило № 3:
Если метод обнаруживает
null
что этого не должно быть, он не должен пытаться решить проблему, превращая его во что-то другое. Это просто скрывает проблему от программиста. Вместо этого он должен позволить NPE произойти и вызвать сбой, чтобы программист мог выяснить, что является основной причиной, и устранить ее. Надеемся, что сбой будет замечен во время тестирования. Если нет, то это говорит о вашей методологии тестирования.Правило № 4:
Если в вашем коде есть ошибки, которые приводят к большому количеству NPE, самое сложное - выяснить, откуда взялись
null
значения. Один из способов облегчить диагностику - это написать свой код, чтобыnull
он был обнаружен как можно скорее. Часто вы можете сделать это в сочетании с другими проверками; например(Очевидно, что есть случаи, когда правила 3 и 4 следует измерить с реальностью. Например (правило 3), некоторые виды приложений должны пытаться продолжить работу после обнаружения, вероятно, программных ошибок. И (правило 4) может иметь слишком большую проверку на плохие параметры влияние на производительность.)
источник
Я бы порекомендовал исправить метод для защиты. Например:
Должно быть больше в соответствии с этим:
Я понимаю, что это абсолютно тривиально, но если вызывающий ожидает, что объект даст им объект по умолчанию, который не приведет к передаче нулевого значения.
источник
new String()
вообще.null
s - худший из возможных вариантов, хуже, чем бросание NPE.Следующие общие правила о NULL очень помогли мне до сих пор:
Если данные поступают извне, систематически проверяйте их на наличие нулей и действуйте соответствующим образом. Это означает, что вы можете сгенерировать исключение, которое имеет смысл для функции (проверено или не отмечено, просто убедитесь, что имя исключения точно говорит вам, что происходит.). Но НИКОГДА не теряйте ценность в вашей системе, которая потенциально может принести сюрпризы.
Если значение Null находится в области соответствующих значений для вашей модели данных, действуйте соответствующим образом.
При возврате значений старайтесь по возможности не возвращать нули. Всегда предпочитайте пустые списки, пустые строки, шаблоны нулевых объектов. Сохраняйте пустые значения в качестве возвращаемых значений, когда это наилучшее возможное представление данных для данного варианта использования.
Наверное, самый важный из всех ... Тесты, тесты и тестирование снова. При тестировании своего кода не проверяйте его как кодировщика, тестируйте его как доминантного нацистского психопата и пытайтесь придумать всевозможные способы измучить этот код.
Это имеет тенденцию немного параноидально относиться к нулям, часто приводящим к фасадам и прокси, которые соединяют системы с внешним миром и строго контролируют значения внутри с избыточной избыточностью. Внешний мир здесь означает почти все, что я сам не кодировал. Это требует затрат времени выполнения, но до сих пор мне редко приходилось оптимизировать это, создавая «нулевые безопасные разделы» кода. Я должен сказать, однако, что я в основном создаю долго работающие системы для здравоохранения, и последнее, что мне нужно, это интерфейсная подсистема, переносящая аллергию на йод на сканер КТ из-за неожиданного нулевого указателя, потому что кто-то в другой системе никогда не осознавал, что имена могут содержать апострофы или символы, такие как 但 耒耨。
в любом случае .... мои 2 цента
источник
Я бы предложил использовать шаблон Option / Some / None из функциональных языков. Я не специалист по Java, но я интенсивно использую собственную реализацию этого шаблона в своем проекте C #, и я уверен, что он может быть преобразован в мир Java.
Идея этого шаблона заключается в следующем: если логически возникает ситуация, когда существует вероятность отсутствия значения (например, при получении из базы данных по идентификатору), вы предоставляете объект типа Option [T], где T - возможное значение. , Я возвращал случай отсутствия объекта-значения класса None [T], если возвращалось существование объекта-объекта Some [T], содержащего значение.
В этом случае вы должны обрабатывать возможность отсутствия значения, и если вы делаете обзор кода, вы легко можете найти место неправильной обработки. Чтобы получить вдохновение от реализации языка C #, обратитесь к моему репозиторию bitbucket. https://bitbucket.org/mikegirkin/optionsomenone
Если вы возвращаете нулевое значение, и оно логически эквивалентно ошибке (например, файл не существует или не может подключиться), вы должны сгенерировать исключение или использовать другой шаблон обработки ошибок. Идея, лежащая в основе этого, опять-таки заключается в том, что вы получаете решение, когда вам нужно справиться с ситуацией отсутствия значения и легко найти места неправильной обработки в коде.
источник
Хорошо, если один из возможных результатов вашего метода - нулевое значение, вы должны защищаться для этого, но если метод должен возвращать ненулевое значение, но это не так, я бы наверняка это исправил.
Как обычно, это зависит от случая, как и с большинством вещей в жизни :)
источник
В lang- библиотеках Apache Commons есть способ обработки нулевых значений.
метод defaultIfNull в классе ObjectUtils позволяет вам возвращать значение по умолчанию, если переданный объект является нулевым
источник
Не используйте тип Optional, если он действительно не является обязательным, часто выход лучше обрабатывать как исключение, если вы действительно не ожидали null в качестве опции, а не потому, что вы регулярно пишете глючный код.
Как указывает статья Google, проблема не в нулевом типе, который он использует. Проблема в том, что значения NULL должны проверяться и обрабатываться, часто их можно корректно завершить.
Существует ряд нулевых случаев, которые представляют недопустимые условия в областях, выходящих за рамки обычной работы программы (недопустимый ввод данных пользователем, проблемы с базой данных, сбой сети, отсутствующие файлы, поврежденные данные), для чего предназначены проверенные исключения, их обработка, даже если это просто для регистрации.
Обработка исключений допускает различные операционные приоритеты и привилегии в JVM, в отличие от типа, такого как Optional, который имеет смысл для исключительного характера их возникновения, включая раннюю поддержку приоритетной отложенной загрузки обработчика в память, поскольку нужно, чтобы оно болталось все время.
Вам не нужно писать нулевые обработчики везде, только там, где они могут возникнуть, где бы вы ни обращались к ненадежной службе данных, и, поскольку большинство из них делятся на несколько общих шаблонов, которые можно легко абстрагировать, вам действительно нужно только вызов обработчика, за исключением редких случаев.
Поэтому я предполагаю, что мой ответ будет заключен в проверенное исключение и обработать его или исправит ненадежный код, если он в пределах ваших возможностей.
источник