Я часто использую object != null, чтобы избежать NullPointerException.
Какая альтернатива:
if (someobject != null) {
someobject.doCalc();
}
Отказ от использования null превосходит большинство других предложений здесь. Выбрасывать исключения, не возвращать и не разрешать нули. Кстати, ключевое слово assert бесполезно, потому что по умолчанию оно отключено. Используйте всегда активный механизм отказа
Вы можете создать класс, который будет проверять нулевые значения или нулевой объект. Это поможет вам улучшить возможность повторного использования. stackoverflow.com/a/16833309/1490962
используйте Ломбок, у вас есть @Ненулевой
Разве нет шаблона дизайна, который говорит о создании нулевого объекта? Поэтому при создании экземпляра нового объекта вы всегда используете этот нулевой объект (тот же суперкласс, те же [но пустые] методы), а позже вы устанавливаете объект как полный объект, когда он вам нужен. Возможно, вы захотите проверить аналогичный вопрос: stackoverflow.com/questions/9162371/… и эту информацию о шаблоне нулевого объекта: en.wikipedia.org/wiki/Null_Object_pattern
В коде высокого уровня следует избегать нулевых значений. Тони Хоар, который изобрел нулевые ссылки, назвал их «ошибкой на миллиард долларов». Взгляните на здесь для некоторых идей.
Кажется, в Java 8: static Objects.isNull (Object o) docs.oracle.com/javase/8/docs/api/java/util/Objects.html
Как насчет обертывания объекта с помощью Optional. Используйте optional везде, где вы видите возможность нулевых значений




Вместо шаблона нулевого объекта, который имеет свое применение, вы можете рассмотреть ситуации, когда нулевой объект является ошибкой.
При возникновении исключения изучите трассировку стека и исправьте ошибку.
Проблема в том, что обычно вы теряете контекст, поскольку исключение NullPointerException не указывает, какая переменная была нулевой, и у вас может быть несколько операций с «.» - в строке. Использование «if (foo == null) throw new RuntimeException (« foo == null »)» позволяет вам явно указать, ЧТО было не так, что дает вашей трассировке стека гораздо большую ценность для тех, кто должен это исправить.
С Андерсеном - мне бы хотелось, чтобы система исключений Java могла включать имя переменной, над которой работает, чтобы NullPointerExceptions не только указывал строку, в которой произошло исключение, но и имя переменной. Это должно работать нормально в незафусцированном программном обеспечении.
У меня был профессор, который проповедовал против цепочки вызовов методов. Его теория заключалась в том, что следует опасаться цепочек вызовов, длина которых превышает 2 метода. Не знаю, жесткое ли это правило, но оно определенно устраняет большинство проблем с трассировкой стека NPE.
Вы должны проверить объект! = Null, только если вы хотите обработать случай, когда объект может быть нулевым ...
Есть предложение добавить новые аннотации в Java7, чтобы помочь с параметрами null / notnull: http://tech.puredanger.com/java7/#jsr308
Нет, не используйте утверждения в производственном коде.
Иногда у вас есть методы, которые работают с его параметрами, которые определяют симметричную операцию:
a.f(b); <-> b.f(a);
Если вы знаете, что b никогда не может быть нулевым, вы можете просто поменять его местами. Это наиболее полезно для равных:
Вместо foo.equals("bar"); лучше сделать "bar".equals(foo);.
Но тогда вы должны предположить, что equals (может быть любым методом) будет правильно обрабатывать null. На самом деле все, что это делает, - это передача ответственности кому-то другому (или другому методу).
@Supericy В основном да, но equals (или любой другой метод) в любом случае должен проверять наличие null. Или прямо заявите, что это не так.
В зависимости от того, какие объекты вы проверяете, вы можете использовать некоторые классы из общего числа apache, например: apache commons lang и коллекции Apache Commons
Пример:
String foo;
...
if ( StringUtils.isBlank( foo ) ) {
///do something
}
или (в зависимости от того, что вам нужно проверить):
String foo;
...
if ( StringUtils.isEmpty( foo ) ) {
///do something
}
Класс StringUtils - только один из многих; В общем, довольно много хороших классов, которые выполняют нулевые безопасные манипуляции.
Вот пример того, как вы можете использовать нулевую валидацию в JAVA, когда вы включаете библиотеку apache (commons-lang-2.4.jar).
public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
return read(new StringReader(xml), true, validationEventHandler);
}
И если вы используете Spring, Spring также имеет ту же функциональность в своем пакете, см. Библиотеку (spring-2.4.6.jar)
Пример использования этого статического classf из spring (org.springframework.util.Assert)
Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
Также вы можете использовать более общую версию Apache Commons, весьма полезную при запуске методов для проверки найденных мной параметров. Validate.notNull (object, «объект не должен быть нулевым»); commons.apache.org/lang/apidocs/org/apache/commons/lang/…
@monojohnny использует ли Validate операторы Assert в ?. Я прошу это, потому что Assert может быть активирован / деактивирован на JVM, и его рекомендуется не использовать в производстве.
Не думаю - я считаю, что он просто выдает исключение RuntimeException, если проверка не удалась.
Если ваш метод вызывается извне, начните с чего-то вроде этого:
public void method(Object object) {
if (object == null) {
throw new IllegalArgumentException("...");
}
Затем в остальной части этого метода вы узнаете, что object не равен нулю.
Если это внутренний метод (не часть API), просто задокументируйте, что он не может быть нулевым, и все.
Пример:
public String getFirst3Chars(String text) {
return text.subString(0, 3);
}
Однако, если ваш метод просто передает значение, а следующий метод передает его и т. д., Это может вызвать проблемы. В этом случае вы можете проверить аргумент, как указано выше.
Это действительно зависит. Если обнаружу, что я часто делаю что-то вроде этого:
if (object == null) {
// something
} else {
// something else
}
Итак, я разветвляюсь и делаю две совершенно разные вещи. Нет уродливого фрагмента кода, потому что мне действительно нужно делать две разные вещи в зависимости от данных. Например, следует ли мне работать с вводом или рассчитать хорошее значение по умолчанию?
На самом деле я редко использую идиому «if (object != null && ...».
Может быть, будет проще привести примеры, если вы покажете примеры того, где вы обычно используете идиому.
Какой смысл выбрасывать исключение IllegalArgumentException? Я думаю, что исключение NullPointerException было бы более ясным, и оно также будет выброшено, если вы сами не выполните нулевую проверку. Я бы либо использовал assert, либо вообще ничего.
Маловероятно, что любое другое значение, кроме нуля, будет приемлемым. У вас может быть IllegalArgumentException, OutOfRageException и т. д. И т. Д. Иногда это имеет смысл. В других случаях вы создаете множество классов исключений, которые не добавляют никакой ценности, тогда вы просто используете IllegalArgumentException. Нет смысла иметь одно исключение для нулевого ввода и другое для всего остального.
Да, я согласен с принципом быстрого сбоя, но в приведенном выше примере значение не передается, а является объектом, для которого должен быть вызван метод. Таким образом, он терпит неудачу одинаково быстро, и добавление нулевой проверки только для того, чтобы выбросить исключение, которое все равно было бы сгенерировано в одно и то же время и в одном месте, похоже, не упрощает отладку.
Я согласен с @Axel в том, что IllegalArgumentException подразумевает (поскольку я все равно использую его), что предварительное условие для аргумента не выполняется, поскольку оно относится к ограничение в параметре. Нулевой параметр обычно является просто «общей ошибкой программирования», а не ограничением приложения / API. Чтобы поддерживать стратегию защиты и быстрого сбоя, ничто не мешает никому проверять наличие нуля и генерировать исключение NullPointerException ... которое точно передает то, что произошло, а именно: «вы неправильно запрограммировали» :)
«Нулевой параметр обычно является просто« общей ошибкой программирования », а не ограничением приложения / API». Наивный. Вы можете использовать это как дыру в безопасности для DoS или попытаться получить информацию трассировки стека (если такая информация не подавляется). osvdb.org/show/osvdb/67379 Если ваш API является общедоступным и вы явно не определяете принимаемые вами границы - как через документацию API, так и через любые инструменты, которые вы можете использовать для обеспечения действительности контракта, - вызывающий может делать все, что хочет. Ты - это тот, кто тогда не программировал, а не звонивший.
Дыра в безопасности? JDK полон такого кода. Если вы не хотите, чтобы пользователь видел трассировки стека, просто отключите их. Никто не подразумевал, что поведение не задокументировано. MySQL написан на C, где разыменование нулевых указателей - это неопределенное поведение, не что иное, как выброс исключения.
throw new IllegalArgumentException("object==null")@myplacedk Я думаю, что имеет смысл иметь другое исключение для нулевых значений, передаваемых в том случае, когда передаются неправильные значения. Эти два обычно являются результатом разных типов ошибок программирования. Нулевые значения обычно возникают из-за того, что некоторые требуемые вычисления не выполняются, в то время как другие проблемы обычно возникают из-за неправильных вычислений.
@Axel весь смысл использования чего-либо, кроме RuntimeException, заключается в информативности исключения. Почему IllegalArgumentException вместо NullPointerException? Потому что, когда вы отлаживаете вызванное этим исключение, исключение IllegalArgumentException намного более очевидно, особенно когда вы помещаете в него сообщение. Это особенно относится к корпоративным приложениям, когда появляются исключения NullPointerExceptions (да, это происходит в корпоративных приложениях). В этом же примере программист может не контролировать, обрабатываются ли утверждения JVM.
1/2 Я должен согласиться с тем, что IllegalArgumentException лучше, чем обычный NPE для таких ситуаций. Я рассматриваю NPE как указание на то, что где-то в коде что-то небезопасно разорвало ссылку на выражение, которое оказалось нулевым (при условии, что все известные и объявленные предварительные условия и инварианты были соблюдены). Исключение недопустимого аргумента. OTH сообщает мне, что известное предусловие или инвариант не соблюдены.
2/2 - То есть NPE сообщает мне, что в методе (или в методах, которые он вызывает) есть еще недокументированная нулевая ошибка или что есть пустое предварительное условие, для которого мы не закодировали. Исключение недопустимого аргумента указывает на наличие ошибки вне этого метода, лежащей где-то в цепочке вызовов, которая ведет к текущему методу. Придерживаясь этого шаблона (очевидно, в разумных пределах), он действительно приводит к более быстрому анализу первопричин ошибок (особенно неприятных, взаимосвязанных).
Выбрасывание NullPointerException - это соглашение Java. См., Например, Objects.requireNonNull, который является "в первую очередь для проверки параметров в методах и конструкторах" и бросает NullPointerException. Также есть просто документ для NullPointerException, в котором говорится, что «приложения должны генерировать экземпляры этого класса, чтобы указать на другое незаконное использование объекта null».
Ответ на этот вопрос указывает на то, что вас могут заинтересовать стратегии обработки ошибок. Как и где обрабатывать ошибки - это широко распространенный архитектурный вопрос. Есть несколько способов сделать это.
Мое любимое: позвольте Исключениям распространяться - ловите их в «основном цикле» или в какой-либо другой функции с соответствующими обязанностями. Проверка условий ошибок и их надлежащая обработка могут рассматриваться как особая ответственность.
Обязательно посмотрите и на аспектно-ориентированное программирование - у них есть изящные способы вставить if ( o == null ) handleNull() в ваш байт-код.
Где бы вы ни передавали массив или вектор, инициализируйте их пустыми, а не нулевыми. - Таким образом можно избежать частых проверок на null, и все в порядке :)
public class NonNullThing {
Vector vectorField = new Vector();
int[] arrayField = new int[0];
public NonNullThing() {
// etc
}
}
Для меня это звучит как довольно распространенная проблема, с которой в какой-то момент сталкиваются разработчики младшего и среднего уровня: они либо не знают, либо не доверяют контрактам, в которых участвуют, и в целях защиты перепроверяют нули. Кроме того, при написании собственного кода они, как правило, полагаются на возвращение нулей, чтобы указать что-то, что требует от вызывающей стороны проверки наличия нулей.
Другими словами, есть два случая, когда возникает нулевая проверка:
Где null - действительный ответ с точки зрения контракта; и
Где это неверный ответ.
(2) легко. Либо используйте операторы assert (утверждения), либо разрешите сбой (например, Исключение нулевого указателя). Утверждения - это редко используемая функция Java, которая была добавлена в версии 1.4. Синтаксис:
assert <condition>
или же
assert <condition> : <object>
где <condition> - это логическое выражение, а <object> - это объект, выходные данные метода toString() которого будут включены в ошибку.
Оператор assert выдает Error (AssertionError), если условие не выполняется. По умолчанию Java игнорирует утверждения. Вы можете включить утверждения, передав параметр -ea в JVM. Вы можете включать и отключать утверждения для отдельных классов и пакетов. Это означает, что вы можете проверять код с утверждениями при разработке и тестировании и отключать их в производственной среде, хотя мое тестирование практически не показало влияния утверждений на производительность.
Не использовать утверждения в этом случае - нормально, потому что код просто выйдет из строя, что и произойдет, если вы используете утверждения. Единственная разница в том, что с утверждениями это может произойти раньше, более значимым образом и, возможно, с дополнительной информацией, которая может помочь вам выяснить, почему это произошло, если вы этого не ожидали.
(1) немного сложнее. Если у вас нет контроля над кодом, который вы вызываете, вы застряли. Если null является допустимым ответом, вы должны его проверить.
Однако, если это код, который вы контролируете (а это часто бывает), то это совсем другая история. Избегайте использования нулей в качестве ответа. С методами, возвращающими коллекции, это просто: почти все время возвращать пустые коллекции (или массивы) вместо нулей.
С не коллекциями может быть сложнее. Рассмотрим это как пример: если у вас есть эти интерфейсы:
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}
где Parser принимает необработанный пользовательский ввод и находит, чем заняться, возможно, если вы для чего-то реализуете интерфейс командной строки. Теперь вы можете сделать контракт, чтобы он возвращал значение null, если нет соответствующих действий. Это приводит к нулевой проверке, о которой вы говорите.
Альтернативное решение - никогда не возвращать null и вместо этого использовать Шаблон "Нулевой объект":
public class MyParser implements Parser {
private static Action DO_NOTHING = new Action() {
public void doSomething() { /* do nothing */ }
};
public Action findAction(String userInput) {
// ...
if ( /* we can't find any actions */ ) {
return DO_NOTHING;
}
}
}
Сравнивать:
Parser parser = ParserFactory.getParser();
if (parser == null) {
// now what?
// this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
// do nothing
} else {
action.doSomething();
}
к
ParserFactory.getParser().findAction(someInput).doSomething();
это намного лучший дизайн, потому что он приводит к более лаконичному коду.
Тем не менее, возможно, для метода findAction () вполне уместно генерировать исключение со значимым сообщением об ошибке - особенно в этом случае, когда вы полагаетесь на ввод пользователя. Было бы намного лучше, если бы метод findAction выдал исключение, чем вызывающий метод выдал простое исключение NullPointerException без каких-либо объяснений.
try {
ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
userConsole.err(anfe.getMessage());
}
Или, если вы считаете, что механизм try / catch слишком уродлив, вместо «Ничего не делать» ваше действие по умолчанию должно обеспечивать обратную связь с пользователем.
public Action findAction(final String userInput) {
/* Code to return requested Action if found */
return new Action() {
public void doSomething() {
userConsole.err("Action not found: " + userInput);
}
}
}
Я не согласен с вашими утверждениями о действии DO_NOTHING. Если метод действия find не может найти действие, то правильным решением будет возврат null. Вы «нашли» в своем коде действие, которое на самом деле не найдено, что нарушает принцип метода поиска полезного действия.
Я согласен с тем, что null слишком часто используется в Java, особенно со списками. Так много API было бы лучше, если бы они возвращали пустой список / массив / коллекцию вместо null. Часто значение null используется там, где вместо этого должно быть сгенерировано исключение. Если синтаксический анализатор не может выполнить синтаксический анализ, должно быть создано исключение.
Я думаю, что в исходном коде должно быть возможно указать, что null никогда не возвращается из метода X и что данный параметр НЕ должен быть нулевым, и передача одного из них является ошибкой.
Последний пример - IIRC, шаблон проектирования Null Object.
Утверждение подходит для ТЕСТИРОВАНИЯ. Опасно использовать на PROD.
Я не согласен с DO_NOTHING, потому что, хотя он устраняет эту нулевую проверку, результирующее поведение является неожиданным. Если значение null является неожиданным вводом для вашего метода, тогда уместно, чтобы ваш метод генерировал NPE, чтобы вызывающий был осведомлен и все записывались в журнал (быстрое сбойное поведение). При использовании DO_NOTHING все проходит так же, как и все, но результирующее действие не выполняется, и пользователи повторяют действие (повторная отправка формы). Я согласен возвращать пустые списки, объекты, но не нули, в качестве возвращаемых значений, но не согласен с DO_NOTHING, показанным выше. Но NPE не должен отображать трассировку стека в пользовательском интерфейсе
@Cshah (и MetroidFan2002). Просто поместите это в контракт, и тогда станет ясно, что ненайденное возвращенное действие ничего не даст. Если это важная информация для вызывающего абонента, предоставьте способ обнаружить, что это было ненайденное действие (т.е. предоставьте метод, чтобы проверить, был ли результатом объект DO_NOTHING). В качестве альтернативы, если действие обычно должно быть найдено, вы все равно не должны возвращать null, а вместо этого генерировать исключение, конкретно указывающее на это условие - это все равно приводит к лучшему коду. При желании предоставьте отдельный метод, возвращающий логическое значение, чтобы проверить, существует ли действие.
Я защищаюсь в своем коде и выполняю нулевые проверки. Особенно в среде J2EE. Я считаю, что все, что может быть нулевым ... потенциально может быть нулевым в какой-то момент. По контракту в большинстве случаев я не хочу генерировать исключение с незаконным аргументом или нулевой указатель, потому что в Java вообще не должно быть нулевых ссылок. В большинстве случаев я пытаюсь найти возвращаемое значение по умолчанию и быстро терпит неудачу со значением по умолчанию / ожидаемым возвращаемым значением.
Лаконичность не означает качественный код. Мне жаль, что ты так думаешь. Ваш код скрывает ситуации, когда ошибка была бы полезной.
@MetroidFan, если вы вернете действительное действие, которое ничего не делает, у вас будет более простой вызывающий объект без ветки. Ветви создают дополнительную сложность, и их минимальное количество упрощает тестирование.
@ Thorbjørn Ravn Andersen Скрывая возможность того, что метод findAction может нет найти действие, вы теперь выполнили логику, которая, хотя и не нарушает работу программы, может привести к нежелательным эффектам, которые не будут обнаружены до гораздо более поздней стадии. (возможно, в производстве). В зависимости от того, действительно ли можно ожидать, что findAction ничего не найдет, это крайне нежелательно - возвращение null или выдача исключения, как предлагает воображаемый мальчик, являются лучшими подходами, так что их можно явно проверить, а пути принять во внимание отсутствие поиска действие.
Какой смысл использовать утверждения, когда они только для вас не подходят? Да, вы можете ловить вещи, пока работаете над этим, но как они помогут на производстве, если вы никогда не услышите об этом в странных ситуациях?
Нет ничего плохого в проверке нулевых значений, и я видел много старших разработчиков / разработчиков Rockstar, которые везде проверяли нулевые значения. Кроме того, проверка нуля - одна из самых дешевых операций в языке программирования.
Согласен с Дартом Вейдером. Я бы сказал, что недостаточно защищаться - это еще не все. Существует очень мало библиотек, и очень мало программистов, по моему опыту, у которых есть дисциплина, чтобы полностью описать свои контракты (включая то, могут ли возвращаться нули / являются ли приемлемые значения для аргументов), поэтому часто не стоит доверять .
@Saj: Почему утверждения подходят только для тестирования и опасны для продуктивных систем? Если есть условие, которое приводит к ошибке, оно должно также выйти из строя в производственной среде. Тем не менее важно иметь какой-нибудь тест JUnit или интеграционный тест, который проверяет это утверждение. Кроме того, разрешите утверждения с помощью "-ea"
В коде «сравнения» раскрывается ваша точка зрения на тот факт, что если вам нечего делать, когда NULL возвращается для action, тогда зачем проверять наличие NULL? Вы заставляете код выглядеть уродливее, чем просто проверка на значение, отличное от NULL. Избегая стилей кодирования, я предпочитаю способ, который я видел в некотором коде API Android, когда запрашивал NULL. Они просто возвращаются, если задействованный метод не может продолжать работать, даже если профиль метода возвращает void. И если вам нужно, сделайте все до заявления о возврате. Конечно, вы возвращаетесь и нарушаете нормальный поток языка высокого уровня.
assert для меня непригоден, потому что он должен быть явно включен - я хочу, чтобы мои утверждения всегда были включены. Кто-то сказал: «Но в производстве, как они помогут, если вы никогда не услышите об этом в странных ситуациях?» Легко - вы получаете точный и кристально чистый сбой, максимально приближенный к первопричине проблемы, и можете легко исправить его с гораздо меньшими усилиями, чем обратное проектирование всей системы, пытаясь выяснить, где произошел сбой. Вот почему проектирование по контракту, безотказное проектирование без нулевого значения - единственный способ пойти .... и никогда не использовать "assert", используйте механизм, который всегда включен ....
Вместо действия DO_NOTHING я бы, вероятно, создал метод hasAction (userInput), возвращающий истину или ложь, если для этого userInput есть допустимое действие. Затем findAction вернет действие или выдаст исключение ActionNotFoundException
«хотя мое тестирование не показало почти никакого влияния утверждений на производительность». Ваше предположение не основано на документации Oracle. Это может сильно повлиять на производительность в типах систем, которые включают вычисления в реальном времени.
Я согласен с MetroidFan2002. он на месте. Иногда может произойти возврат null, и проверка на нули совсем не грязная. во что бы то ни стало, если вы можете избежать нулей и всегда инициализировать свои контракты, вам не нужно будет проверять нули
@SnOrfus +1 за упоминание шаблона проектирования Null Object. Я кое-что узнал здесь. См. en.wikipedia.org/wiki/Null_Object_pattern
Я никогда не возвращаю null, поэтому я никогда не проверяю возвращаемые значения на null. Мне никогда не нужно думать о том, какие переменные допустимы. Все они. Я никогда не передаю null методу, поэтому мне никогда не нужна проверка ввода в моих методах. Если было бы логично иметь метод, который позволяет передавать нулевой параметр, я вместо этого создаю два метода. Тогда важно свести к минимуму дублирование кода за счет исключения общих черт.
Я против раздувания кода и согласен с этим решением. Явная проверка на NULL - это антипаттерн ИМХО. Способ Java состоит в том, чтобы генерировать исключения * NotFound / InvalidAccess и т. д., Что избавляет вызывающего абонента от необходимости явно обрабатывать нестандартные ситуации. Я даже иду дальше: используйте arg.equals ("foo") вместо "foo" .equals (arg) или используйте собственные типы (long вместо Long), чтобы неявно ПРИНУДИТЬ NPE. К счастью, при возврате нулевого объекта вызывающая сторона все еще может попытаться вызвать метод для этого нулевого значения и принудительно выполнить NPE. :-)))))
Часто поведение, которое вы хотите реализовать, если объект имеет значение NULL, будет одинаковым независимо от того, где вы получаете объект NULL. Как отмечали другие, ответное действие DO_NOTHING на самом деле является шаблоном нулевого объекта (en.wikipedia.org/wiki/Null_Object_pattern), который собирает это «что нам делать, если он нулевой?» логика в одном месте, что сокращает дублирование. Однако шаблон нулевого объекта на самом деле является просто более ограниченной версией шаблона особого случая Мартина Фаулера: (martinfowler.com/eaaCatalog/specialCase.html), который отлично подходит для устранения проверок для значений, отличных от нуля.
Я бы выбрал Optional / Option или исключение. Возвращение null - это просто яд для вызывающего абонента; они забудут с этим справиться и увидят проблему далеко от места звонка.
@ MetroidFan2002: согласен по поводу DO_NOTHING, но не совсем. Если метод действия find не может найти действие, значит, метод не сделал то, что обещал. В этом случае он не должен возвращаться. Его следует бросить.
@TravisWilson. Если метод собирался что-то выбросить, он должен генерировать исключение IllegalArgumentException, а не NPE, потому что он явно проверяет значение null и что-то с ним делает. IAE также обрабатывает получение ненулевого ввода и не может ничего для него найти. Но в настоящее время с Java 5+ я бы выбрал NPE IFF, метод принимал константу перечисления в качестве параметра, поскольку у вас было бы что-то (по одному для каждой константы перечисления) или ничего, если бы соблюдались правильные методы работы с перечислениями.
@ user1050755 То, что вы делаете со строками, опасно и наивно. Когда вы проверяете литерал, вы хотите знать, совпадает ли этот литерал, а не является ли строка нулевой. Наивный способ сделать это, как вы предложили, с бесполезной нулевой проверкой: if (stringVar! = Null && stringVar.equals ("literal")) Но это заставляет вас напрямую отправлять нулевой ввод для тестирования покрытия, в результате появляются ненужные ветви. "" .equals (stringVar) всегда будет работать независимо. Если вы знаете буквальное значение, которое нужно проверить, вы всегда должны это делать - он самый безопасный, легкий для чтения и не требует дополнительных условий.
Я не понимаю, почему все ненавидят DO_NOTHING. Конечно, в этом примере это минималистично, но это язык программирования ... добавьте в класс метод isEmptyAction () ... суть в том, чтобы КОДИРОВАТЬ состояние объектов, а не возвращать какой-то загадочный недостаток. -of-a-value, которое вам нужно просто знать, чтобы проверить ... isEmptyAction () - это реальный API, кодирующий тот факт, что действие может быть пустым / ничего не делать. Намного намного чище, imo (и многие другие, отсюда тот факт, что это собственный определенный шаблон проектирования ...)
@ MetroidFan2002: абсолютно. NPE обычно не подходит. Невозможность найти метод - это вполне законный результат, поэтому это должно быть что-то конкретное, что потребитель должен уловить. Возможно, это результат неправильного ввода, и в этом случае мне нравится IllegalArgumentException (но я не в восторге от того, что это исключение RuntimeException). Также по этому правилу: если метод говорит, что он может вернуть действие, которое ничего не делает (скажем, для удобства потребителя), то возврат DO_NOTHING - это нормально.
Выбрасывать NPE очень разумно, когда что-то имеет значение NULL этого не должно быть. Между прочим, вы должны быть осторожны, если имеете дело с параллелизмом, потому что то, что не равно нулю, когда вы проверяете его, может быть нулевым, когда вы его используете.
Я просто добавил к ответу два последних предложения - try / catch и более значимое действие по умолчанию. @dfeuer Я не думаю, что NPE имеет смысл, если someInput не имеет значения null. Я согласен с Трэвисом Уилсоном в том, что IllegalArgumentException также не идеален, хотя и не является неуместным. Мое предложение - это настраиваемое исключение со значимым сообщением, которое может быть показано пользователю, предоставившему неверный ввод.
@Ziggy Это не значит, что я не согласен с шаблоном нулевого объекта, и я использую его все время. Дело в том, что в данном конкретном случае сигнатура метода - findAction Действие DO_NOTHING по определению НЕ НАЙДЕНО! Это ложь вашему пользователю. И если пользователь должен проверить, что DO_NOTHING нарушает полиморфизм - теперь не все, ваши экземпляры могут использоваться взаимозаменяемо. Чтобы представить это в перспективе, предположим, что это был метод BigDecimal findBigDecimal (String any) - шаблон Null Object здесь работает нет. Обнаружение чего-то лжет вам, если возвращается ноль.
Шаблон «Нулевой объект» более полезен, чем null, потому что иногда результат не используется сразу - например, он может быть сохранен в поле. Затем вы можете отличить null, вызванный неинициализированным полем (возможно, программной ошибкой), и null в результате какого-либо действия.
ВНИМАНИЕ! Утверждения можно отключить, но в производственных средах они отключены.
Шаблон нулевого объекта полезен только для простых случаев из-за отсутствия множественного наследования в Java. К сожалению, null - единственное значение, которое может обозначать произвольный объект, и поэтому оно так широко используется.
Я обнаружил, что использую DP Null Object, когда актуален «всегда доступный» API (например, с шаблоном стратегии), но обычно я просто выбрасываю подробные и значимые исключения. Я не могу вспомнить, когда я в последний раз явно проверял значение null в Java (или любом другом реальном объектно-ориентированном языке); опять же, я не так часто пишу на Java. Я просто хочу сказать: это был эпический разговор и очень поучительное чтение. Вот почему я приехал в SO. Спасибо всем за участие в этом.
В Java8 для этого есть гораздо лучшее решение: используйте Optional в качестве возвращаемого значения для представления значения, допускающего значение NULL. Таким образом, вызывающий знает, что это необязательное значение, и может использовать все методы, которые предоставляет Optional для обработки значения.
Мне нравится идея действия DO_NOTHING, но, похоже, никто не упоминает о выбросе исключения IllegalArgumentException. Если аргумент неверен, это кажется хорошим ответом. В любом случае для метода потребуется соответствующая документация. Также @sprinter, возвращающий действие DO_NOTHING, очень похож на Optional. Оба имеют цель не возвращать null. Я не уверен, что Optional - это «гораздо лучшее решение».
По большому счету проблема не в том, что разработчики не знают контрактов или не доверяют им; проблема в том, что там являются нет контрактов. По моему опыту работы с Android SDK, опубликованными несколькими поставщиками оборудования, документации либо нет, либо нет полезной документации. Кодовые фабрики в Гонконге и Бангалоре даже не слышали о Javadoc.
Как электронный англ. превратился в программиста, эта тема кружит мне голову, пока я пытаюсь узнать больше XD
выдача ошибки только из-за того, что кто-то передал пустой путь к вашему открывателю файлов, является чрезвычайно излишним. Представьте, если бы кто-то использовал это внутри сервера приложений.
Настоящий вопрос в том, КОГДА нулевой ответ является допустимым, а когда - нет. И каков был бы тот самый договор о том, чтобы программное обеспечение было наименее загромождено шаблонным кодом.
Начиная с Java 8, я всегда использую Optional для подобных случаев. С точки зрения готовности это не большая разница, IMO, но выглядит немного эстетичнее. Так что вместо if (obj != null) я пишу if (objOpt.isPresent())
@ MetroidFan2002 Добавлено в ваше заявление - Критика NullObjectPattern
Я видел слишком много глупых исключений NullPointer в производственной среде, чтобы думать, что защитная проверка на пустые значения - это «проблема разработчиков от младшего до среднего уровня». На мой взгляд, всегда, всегда выполняйте проверку на null.
@ MetroidFan2002 «Если метод действия find не может найти действие, то правильным решением будет возврат null» Это полностью зависит от разработчика программы, который решает, соответствует ли действие, которое ничего не делает, его варианту использования. вполне допустимо вернуть действие, которое ничего не делает, если оно соответствует вашему дизайну. Вы подразумеваете, что различие реальных / поддельных действий важно для вызывающего, но оба подхода действительны в соответствии с вашим вариантом использования. Случай, когда не найденное действие важно для вызывающего, также допустим, но может быть передан другими способами, кроме возврата null
Как человек, плохо знакомый с java, мне интересно, что люди сочтут это полезным. Почему бы программисту вместо этого не всегда писать оператор try / catch и использовать его для предотвращения и устранения ошибок?
Во второй половине этого примера в основном говорится, что Java нельзя использовать. Хотя это может быть хорошей идеей, иногда у вас нет выбора. А в java значение null является допустимым.
Метод find открывает возможность того, что он не нашел то, что мы искали. У меня хорошо работает привычка использовать 2 разных глагола для функций, которые, очевидно, могут дать сбой: findXXX может потерпеть неудачу и, как таковой, может вернуть значение null или лучше вариант, getXXX может потерпеть неудачу только путем выброса исключения. Я также видел такие варианты, как find vs find_exn или find vs find_opt. Так или иначе, пока вы используете его регулярно, это нормально.
На мой взгляд, подход NOP почти никогда не бывает хорошим. Как уже говорили другие, это может скрыть более глубокие недостатки в вашей программе, так что они будут обнаружены в производственной среде только после нескольких недель устранения неполадок. Очевидно, это не всегда так, но я бы очень осторожно использовал его. Строгий и, возможно, правильный ответ на «найди меня X», когда вы его не нашли, - это вернуть null, если вы ожидаете, что он, возможно, не будет найден, или выбросить исключение, если это не ожидаемый результат. (например, я ожидал бы, что метод findByName сможет вернуть значение null, но getById никогда не должен.)
Как насчет использования Optional<T>?
Как насчет использования Котлина?
Не существует единого хорошего шаблона, подходы должны диктовать здравый смысл. Контракты, нулевые проверки, шаблоны нулевых объектов, пустые строки, утверждения, блоки try-catch - все они действительны для их конкретного варианта использования. Стремление программистов найти настоящий золотой молоток для всех гвоздей - это для меня просто повод отказаться от «согласованного подхода» и не думать и проектировать код должным образом. Иногда вам нужен NOP, иногда вам нужно быстро выйти из строя, иногда вам нужно упростить и установить пустые значения по умолчанию. Просто делайте то, что делает систему наиболее устойчивой, надежной, удобной в обслуживании и безошибочной.
Я считаю, что отключение утверждений по умолчанию было неправильным решением. Значение по умолчанию должно быть самым безопасным, после чего вы можете добавить флаги настройки в свое производственное развертывание.
Только для этой ситуации -
Не проверять, является ли переменная нулевой перед вызовом метода equals (пример сравнения строк ниже):
if ( foo.equals("bar") ) {
// ...
}
приведет к NullPointerException, если foo не существует.
Этого можно избежать, если сравнить свои String следующим образом:
if ( "bar".equals(foo) ) {
// ...
}
Согласен - только в такой ситуации. Я терпеть не могу программистов, которые подняли это на следующий ненужный уровень и пишут if (null! = MyVar) ... мне просто уродливо и бесполезно!
Это частный пример, вероятно, наиболее часто используемый, из общей хорошей практики: если вы это знаете, всегда делайте <object that you know that is not null>.equals(<object that might be null>);. Он работает для других методов, кроме equals, если вы знаете контракт и эти методы могут обрабатывать параметры null.
Это первый пример Йода Условия, который действительно имеет смысл.
Исключения NullPointerExceptions выбрасываются не просто так. Они выбрасываются, потому что объект имеет значение NULL там, где его не должно быть. Задача программистов - ИСПРАВИТЬ это, а не СКРЫТЬ проблему.
Это только скрывает проблему. Что, если вы будете использовать foo позже? Если переменная не должна иметь значение null, но ... ваше приложение должно получить NPE, чтобы вы, как разработчик, могли исправить основную причину.
Я пробовал NullObjectPattern, но для меня это не всегда лучший способ. Бывают случаи, когда «бездействие» неуместно.
NullPointerException - это Исключение времени выполнения, что означает, что это ошибка разработчиков, и при достаточном опыте он сообщает вам, где именно ошибка.
Теперь к ответу:
Постарайтесь сделать все свои атрибуты и их аксессоры как можно более приватными или вообще не открывайте их клиентам. Конечно, вы можете иметь значения аргументов в конструкторе, но, уменьшая область видимости, вы не позволяете клиентскому классу передавать недопустимое значение. Если вам нужно изменить значения, вы всегда можете создать новый object. Вы проверяете значения в конструкторе только однажды, а в остальных методах вы можете быть почти уверены, что значения не равны нулю.
Конечно, опыт - лучший способ понять и применить это предложение.
Байт!
Фреймворк коллекций Google предлагает хороший и элегантный способ достижения нулевой проверки.
В классе библиотеки есть такой метод:
static <T> T checkNotNull(T e) {
if (e == null) {
throw new NullPointerException();
}
return e;
}
И использование (с import static):
...
void foo(int a, Person p) {
if (checkNotNull(p).getAge() > a) {
...
}
else {
...
}
}
...
Или в вашем примере:
checkNotNull(someobject).doCalc();
ммм, в чем разница? p.getAge () будет генерировать тот же NPE с меньшими накладными расходами и более четкой трассировкой стека. Что мне не хватает?
Лучше создать исключение IllegalArgumentException ("e == null") в вашем примере, поскольку оно ясно указывает на то, что это исключение, предназначенное программистом (вместе с достаточной информацией, чтобы фактически позволить разработчику идентифицировать проблему). Исключения NullPointerExceptions следует зарезервировать для JVM, так как это ясно указывает на то, что это было непреднамеренно (и обычно происходит в труднодоступных местах).
Теперь это часть Google Guava.
Для меня это пахнет чрезмерной инженерией. Просто позвольте JVM генерировать NPE и не загромождать код этим мусором.
Мне это нравится, и я открываю большинство методов и конструкторов с явной проверкой аргументов; если есть ошибка, методы всегда терпят неудачу на первых нескольких строках, и я знаю оскорбительную ссылку, но не нашел что-то вроде getThing().getItsThing().getOtherThing().wowEncapsulationIsBroken().setLol("hi");
В Java 1.7 добавлен метод java.util.Objects.requireNonNull (среди прочего), который делает именно это. Это настолько распространенная идиома, что я удивлен, что это заняло столько времени!
просто для интереса ... в чем разница между checkNotNull (bla) .foo () и bla.foo (), если оба могут генерировать NPE в случае нуля? нулевая выгода, правда?
@gorefest checkNotNull возвращает значение, поэтому вы можете присвоить ему свои поля в конструкторе. Например. this.foo = checkNotNull(foo), также более читаемый (он показывает, что вы хотите принудительно использовать ненулевые значения, а не какой-либо случайный вызов метода), а также что, если у параметра нет методов для вызова или для методов требуется много аргументов. Наконец, checkNotNull поддерживает пользовательское сообщение об ошибке.
Вау, мне почти не нравится добавлять еще один ответ, когда у нас есть 57 различных способов порекомендовать NullObject pattern, но я думаю, что некоторые люди, интересующиеся этим вопросом, могут захотеть узнать, что есть предложение для Java 7 добавить "нулевое безопасное обращение" - a оптимизированный синтаксис для логики «если не равно нулю».
Пример, приведенный Алексом Миллером, выглядит так:
public String getPostcode(Person person) {
return person?.getAddress()?.getPostcode();
}
?. означает отмену ссылки на левый идентификатор только в том случае, если он не равен нулю, в противном случае оцените остаток выражения как null. Некоторым людям, таким как член Java Posse Дик Уолл и избиратели в Devoxx, действительно нравится это предложение, но есть и возражения на том основании, что оно фактически будет способствовать более широкому использованию null в качестве контрольного значения.
Обновлять:официальное предложение для нулевого безопасного оператора в Java 7 был отправлен в Монета проекта.. Синтаксис немного отличается от приведенного выше примера, но это то же самое понятие.
Обновлять: Предложение нулевого оператора не вошло в Project Coin. Таким образом, вы не увидите этого синтаксиса в Java 7.
Я считаю это неправильным. Должен быть способ указать, что данная переменная ВСЕГДА не равна нулю.
Обновление: предложение не будет делать Java7. См. blogs.sun.com/darcy/entry/project_coin_final_five.
Но на той же странице см. Ссылку на types.cs.washington.edu/jsr308 для получения информации об использовании среды Checker для добавления аннотаций типа @Nullable и @NonNull в Java 7.
Интересная идея, но выбор синтаксиса абсурден; Я не хочу, чтобы кодовая база была заполнена вопросительными знаками, прикрепленными к каждому стыку.
Этот оператор существует в Groovy, поэтому у тех, кто хочет его использовать, он все еще есть в качестве опции.
Необязательно был добавлен в Java8
Это самая гениальная идея, которую я когда-либо видел. Его следует добавить на каждый разумный язык синтаксиса C. Я бы предпочел повсюду «заколачивать вопросительные знаки», чем пролистывать экран, полный строк или уклоняться от «охранных оговорок» весь день.
Тони Хоар извинился за изобретение null. Но еще большая ошибка - это выбрать стратегию, придерживаться ее более 20 лет, пока не будут написаны миллиарды строк кода, а затем окончательно передумать. Этот .? был как последний шанс сохранить "чистоту" Java. Это очень простое синтаксическое решение. Но вместо этого они предпочитают добавлять несколько разных классов @Nullable и Option, пустые коллекции, пустые объекты. Цель заключалась в том, чтобы упростить использование значений NULL. Но вместо этого они добавили много уровней сложности. В конце концов, это разделит Java-сообщество и приведет его к разрушению.
В Kotlin также есть операторы нулевого безопасного вызова. kotlinlang.org/docs/reference/null-safety.html#safe-calls
В конечном счете, единственный способ полностью решить эту проблему - использовать другой язык программирования:
nil, и абсолютно ничего не произойдет. Это делает ненужными большинство нулевых проверок, но может значительно усложнить диагностику ошибок.Я не знаком с Nice, но Kotlin реализует ту же идею, в систему типов языка встроены типы, допускающие значение NULL, и типы, отличные от NULL. Намного более лаконично, чем Optionals или шаблон нулевого объекта.
Вы можете настроить свою IDE так, чтобы она предупреждала вас о потенциальном разыменовании null. Например. в Eclipse см. Настройки> Java> Компилятор> Ошибки / предупреждения / анализ нулевого значения.
Если вы хотите определить новый API, в котором неопределенные значения имеют смысл, используйте Вариант шаблона (может быть знаком по функциональным языкам). Он имеет следующие преимущества:
Java 8 имеет встроенный класс Optional (рекомендуется); для более ранних версий существуют альтернативные библиотеки, например OptionalГуава или OptionФункциональная Java. Но, как и многие шаблоны функционального стиля, использование Option в Java (даже 8) приводит к довольно некоторому шаблону, который вы можете уменьшить, используя менее подробный язык JVM, например Scala или Xtend.
Если вам нужно иметь дело с API, который может возвращать нули, вы не можете много сделать на Java. Xtend и Groovy имеют Оператор Элвиса?: и нулевой безопасный оператор разыменования?., но обратите внимание, что это возвращает null в случае нулевой ссылки, поэтому он просто «откладывает» правильную обработку null.
Действительно, паттерн Option великолепен. Существуют некоторые эквиваленты Java. Guava содержит ограниченную версию этого под названием Optional, в которой отсутствует большая часть функционального материала. В Haskell этот шаблон называется Maybe.
@Luca Molteni: Вы абсолютно правы, я уже прокомментировал сообщение с просьбой расширить его. :)
Необязательный класс будет доступен в Java 8
... и у него (пока) нет карты или flatMap: download.java.net/jdk8/docs/api/java/util/Optional.html
Необязательный шаблон ничего не решает; вместо одного потенциально нулевого объекта теперь у вас их два.
Также посмотрите функциональные расширения Guava (фуга). У этой библиотеки также есть своя опция.
Optional Guava в этом случае не подходит, поскольку transform выдает NPE, когда функция возвращает null.
Если вы используете (или планируете использовать) Java IDE, например JetBrains IntelliJ IDEA, Затмение или Netbeans, или инструмент, например findbugs, вы можете использовать аннотации для решения этой проблемы.
По сути, у вас есть @Nullable и @NotNull.
Вы можете использовать в методе и параметрах, например:
@NotNull public static String helloWorld() {
return "Hello World";
}
или же
@Nullable public static String helloWorld() {
return "Hello World";
}
Второй пример не компилируется (в IntelliJ IDEA).
Когда вы используете первую функцию helloWorld() в другом фрагменте кода:
public static void main(String[] args)
{
String result = helloWorld();
if (result != null) {
System.out.println(result);
}
}
Теперь компилятор IntelliJ IDEA сообщит вам, что проверка бесполезна, поскольку функция helloWorld() никогда не вернет null.
Использование параметра
void someMethod(@NotNull someParameter) { }
если вы напишете что-то вроде:
someMethod(null);
Это не скомпилируется.
Последний пример с использованием @Nullable
@Nullable iWantToDestroyEverything() { return null; }
Делая это
iWantToDestroyEverything().something();
И можете быть уверены, что этого не произойдет. :)
Это хороший способ позволить компилятору проверить что-то большее, чем обычно, и заставить ваши контракты быть сильнее. К сожалению, это поддерживается не всеми компиляторами.
В IntelliJ IDEA 10.5 и более поздних версиях они добавили поддержку любых других реализаций @Nullable@NotNull.
См. Сообщение в блоге Более гибкие и настраиваемые аннотации @ Nullable / @ NotNull.
@NotNull, @Nullable и другие аннотации аннулирования являются частью JSR 305. Вы также можете использовать их для обнаружения потенциальных проблем с такими инструментами, как FindBugs.
Меня странно раздражает то, что интерфейсы @NotNull и @Nullable находятся в пакете com.sun.istack.internal. (Думаю, я связываю com.sun с предупреждениями об использовании проприетарного API.)
переносимость кода становится нулевой с помощью jetbrains. Я бы дважды подумал (квадрат), прежде чем привязать к уровню ide. Как Jacek S сказал, что они являются частью JSR в любом случае, который, кстати, я думал, был JSR303.
Почему второй не компилируется?
Я действительно не думаю, что использование специального компилятора является жизнеспособным решением этой проблемы.
Хорошая вещь об аннотациях, которыми являются @NotNull и @Nullable, заключается в том, что они хорошо ухудшаются, когда исходный код создается системой, которая их не понимает. Таким образом, аргумент о том, что код не переносится, может быть недействительным - если вы используете систему, которая поддерживает и понимает эти аннотации, вы получаете дополнительное преимущество более строгой проверки ошибок, в противном случае вы получите меньше, но ваш код все равно должен сборка выполняется нормально, и качество вашей запущенной программы ОДИНАКОВО, потому что эти аннотации в любом случае не применялись во время выполнения. К тому же все компиляторы кастомные ;-)
в вашем примере вы дважды вызываете helloWorld. Это ужасно. Вы не представляете, какие могут быть последствия!
@Mechanicalsnail, потому что он всегда возвращает только "hello world" и никогда не может вернуть null.
@JacekS Для информации - для разработки под Android, начиная с версии 19.1 библиотеки поддержки Android, добавлена поддержка аннотаций @NotNull и @Nullable. Таким образом, практически любой разработчик Android может воспользоваться им. Это больше не будет зависеть от IDE. Более подробная информация об аннотациях поддержки здесь - tools.android.com/tech-docs/support-annotations
Аргументы против @Nullable / @NotNull за «совместимость» не имеют смысла. Они нужны только для того, чтобы помочь инструментам (из статического анализа) гарантировать выполнение этих основных контрактов - они заменяют нет правильной обработкой null, когда это уместно для контракта (или возможно для входного источника). Хотя это было бы потрясающе, если бы Java и C# (и среда выполнения) действительно поддерживали ненулевые ссылочные типы в системе типов, использование более совершенных инструментов статического анализа (и явных аннотированных контрактов) имеет большое значение для уменьшения ошибки в 100 триллионов долларов. то есть Algo, это Java, это C# ..
Netbeans также поддерживает @NotNull и @Nullable.
Стоит отметить, что аннотации TYPE_USE (начиная с Java 8) позволяют рассматривать пустые аннотации как неотъемлемую часть системы типов, включая, в частности, обобщенные типы. Это означает, что концептуально все нарушения контракта могут быть обнаружены компилятором. Eclipse поддерживает это с момента выпуска Java 8, см. help.eclipse.org/topic/org.eclipse.jdt.doc.user/tasks/…
Какое сообщение об ошибке дает второй пример (в IntelliJ IDEA)?
Теперь это должен быть основной ответ, я считаю, что принятый ответ был принят до того, как эти аннотации стали доступны. Интересно, есть ли способ хотя бы вывести его на вершину ...
@mwfearnley Я считаю, что комментарий ко второму ответу был неправильным, Nullable - это скорее предупреждение для разработчика, и я не думаю, что компилятор доказывает, что он может быть нулевым (поскольку переопределенный метод может возвращать null). Что это ДЕЙСТВИТЕЛЬНО означает, так это то, что он не может быть передан в NotNull без защиты нулевой проверки.
Между прочим, не все реализации шашек согласованы! Средство проверки Eclipse намного лучше, чем средство проверки IntelliJ (хотя я использовал IntelliJ, это определенно лучше, чем ничего). Eclipses намного лучше обрабатывает неаннотированные переменные. stackoverflow.com/questions/48349393/…
Для служебных классов вы можете проверить, что параметры не равны нулю.
Во всех остальных случаях вам, возможно, не придется. По возможности используйте инкапсуляцию, уменьшая количество мест, в которых вы чувствуете соблазн проверить на null.
В дополнение к использованию assert вы можете использовать следующее:
if (someobject == null) {
// Handle null here then move on.
}
Это немного лучше, чем:
if (someobject != null) {
.....
.....
.....
}
Ммм, почему это? Пожалуйста, не защищайтесь, я просто хотел бы узнать больше о Java :)
@Mudu Как правило, я предпочитаю, чтобы выражение в операторе if было более «положительным», а не «отрицательным». Так что, если бы я увидел if (!something) { x(); } else { y(); }, я был бы склонен реорганизовать его как if (something) { y(); } else { x(); } (хотя можно было бы поспорить, что != null - более положительный вариант ...). Но что еще более важно, важная часть кода не заключена внутри {}, и у вас на один уровень меньше отступа для большей части метода. Я не знаю, было ли это рассуждением fastcodejava, но это было бы моим.
Я тоже так делаю ... На мой взгляд, сохраняет код в чистоте.
@MatrixFrog Да, это делает код более чистым и легко читаемым, поскольку вы сначала видите важный код (когда все работает без ошибок).
public static <T> T ifNull(T toCheck, T ifNull) {
if (toCheck == null) {
return ifNull;
}
return toCheck;
}
Что не так с этим методом, я думаю, что @tltester просто хочет указать значение по умолчанию, если оно равно нулю, что имеет смысл.
В Apache commons-lang есть такой метод: ObjectUtils.defaultIfNull(). Есть еще одно общее: ObjectUtils.firstNonNull(), которое можно использовать для реализации стратегии деградации: firstNonNull(bestChoice, secondBest, thirdBest, fallBack);
Другое предложение - программировать защитно - где ваши классы / функции предоставляют значения по умолчанию, которые известны и безопасны, а где null зарезервирован для истинных ошибок / исключений.
Например, вместо функций, которые возвращают строки, возвращающие ноль при возникновении проблемы (например, преобразование числа в строку), пусть они возвращают пустую строку (""). Вам все равно нужно проверить возвращаемое значение, прежде чем продолжить, но особых случаев для исключений не будет. Дополнительным преимуществом этого стиля программирования является то, что ваша программа сможет различать обычные операции и исключения и соответственно реагировать на них.
-1. Это еще хуже. Теперь вместо сбоя, если вы забудете протестировать, ваша программа незаметно передает неверное значение.
Вы можете использовать FindBugs. У них также есть плагин Затмение), который помогает вам находить повторяющиеся нулевые проверки (среди прочего), но имейте в виду, что иногда вам следует выбирать защитное программирование. Также может оказаться полезным Контракты для Java.
Действительно, обычная «проблема» в Java.
Во-первых, мои мысли по этому поводу:
Я считаю, что плохо что-то «есть», когда было передано NULL, когда NULL не является допустимым значением. Если вы не выходите из метода с какой-либо ошибкой, это означает, что в вашем методе ничего не произошло, что не соответствует действительности. Тогда вы, вероятно, вернете null в этом случае, и в методе получения вы снова проверяете null, и он никогда не заканчивается, и вы получаете «if! = Null» и т. д.
Итак, IMHO, null должно быть критической ошибкой, которая предотвращает дальнейшее выполнение (то есть, где null не является допустимым значением).
Я решаю эту проблему следующим образом:
Во-первых, я следую этому соглашению:
И, наконец, в коде первая строка общедоступного метода выглядит так:
ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();
Обратите внимание, что addParam () возвращает self, поэтому вы можете добавить дополнительные параметры для проверки.
Метод validate() выбрасывает проверенный ValidationException, если какой-либо из параметров равен нулю (установлен или не отмечен - это скорее проблема дизайна / вкуса, но мой ValidationException проверен).
void validate() throws ValidationException;
Сообщение будет содержать следующий текст, если, например, «планы» не заданы:
«Обнаружено недопустимое значение аргумента null для параметра [планы]»
Как видите, второе значение в методе addParam () (строка) необходимо для пользовательского сообщения, потому что вы не можете легко определить переданное имя переменной, даже с отражением (в любом случае, это не тема этого сообщения ...).
И да, мы знаем, что за пределами этой строки мы больше не встретим нулевое значение, поэтому мы просто безопасно вызываем методы для этих объектов.
Таким образом, код будет чистым, легко обслуживаемым и читаемым.
Абсолютно. Приложения, которые просто выдают ошибку и сбой, имеют более высокое качество, потому что нет никаких сомнений в том, что они не работают. Приложения, которые проглатывают ошибки, в лучшем случае постепенно деградируют, но обычно не работают так, что их трудно заметить и не исправить. А когда проблема обнаруживается, их гораздо труднее отлаживать.
Я фанат кода, работающего без ошибок. Спросите себя, делаете ли вы что-нибудь полезное в случае, если параметр равен нулю? Если у вас нет четкого ответа на вопрос, что ваш код должен делать в таком случае ... оно никогда не должно быть нулевым, а затем игнорировать его и разрешить выброс исключения NullPointerException. Вызывающий код будет иметь такое же значение для NPE, как и для исключения IllegalArgumentException, но разработчику будет легче отладить и понять, что пошло не так, если возникнет NPE, а не ваш код, пытающийся выполнить какое-либо другое непредвиденное обстоятельство. логика - что в конечном итоге приводит к сбою приложения.
лучше использовать утверждения, например Contract.notNull (abc, «abc не должно быть равным нулю, не удалось ли загрузить во время xyz?»); - это более компактный способ, чем выполнение if (abc! = null) {выбросить новое исключение RuntimeException ...}
Мне нравятся статьи Ната Прайса. Вот ссылки:
В статьях также есть ссылка на репозиторий Git для Java Maybe Type, который мне интересен, но я не думаю, что это само по себе могло бы уменьшить проверка раздувания кода. Проведя некоторое исследование в Интернете, я думаю, что раздувание кода ! = ноль можно уменьшить в основном за счет тщательного проектирования.
Майкл Фезерс написал короткий и интересный текст о подходах, подобных упомянутому вами: manuelp.newsblur.com/site/424
Если есть что-то, что мне больше всего понравилось в этом ответе, так это совет о «тщательном проектировании». Независимо от того, сводится ли это к написанию кода, исправлению ошибок или проверке на недействительность, чертовски важно сделать в целом хороший дизайн и организацию кода, чтобы избежать множества избыточностей, с которыми нам все еще приходится иметь дело сегодня из-за плохого выбора дизайна, сделанного долгое время тому назад...
Еще одна альтернатива:
Следующая простая функция помогает скрыть нулевую проверку (я не знаю почему, но я не нашел ее как часть той же библиотеки общий):
public static <T> boolean isNull(T argument) {
return (argument == null);
}
Теперь вы можете написать
if (!isNull(someobject)) {
someobject.doCalc();
}
что, по ИМО, лучший способ выразить != null.
Если вы постоянно собираетесь отрицать возвращаемое значение, не лучше ли просто написать функцию isNotNull? Разве это не более четко указывает на ваши намерения?
@TMN: вы правы, в идеале я хотел бы иметь как метод isNull, так и метод isNotNull.
Я не понимаю, насколько это более кратко, чем «someobject! = Null».
Инструментам разработки времени компиляции и времени выполнения, таким как findbugs, будет сложнее идентифицировать повторяющиеся нулевые проверки. Кроме того, вам лучше надеяться, что Java встроена в функцию Null,
Guava, очень полезная основная библиотека от Google, имеет приятный и полезный API, позволяющий избежать нулей. Я считаю UsingAndAvoidingNullExplained очень полезным.
Как объяснено в вики:
Optional<T>is a way of replacing a nullable T reference with a non-null value. An Optional may either contain a non-null T reference (in which case we say the reference is "present"), or it may contain nothing (in which case we say the reference is "absent"). It is never said to "contain null."
Использование:
Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5
@CodyGuldner Верно, Коди. Я привел соответствующую цитату из ссылки, чтобы дать больше контекста.
Вы также можете использовать Checker Framework (с JDK 7 и выше) для статической проверки нулевых значений. Это может решить множество проблем, но требует запуска дополнительного инструмента, который в настоящее время работает только с OpenJDK AFAIK. https://checkerframework.org/
Хорошо, теперь я получил технический ответ миллион раз, но я должен сказать это, потому что это нескончаемая дискуссия с Java-программистами.
Извините, но я не согласен почти со всем вышеперечисленным. Причина, по которой мы должны тестировать на null в Java, состоит в том, что Java-программисты не знают, как обращаться с памятью.
Я говорю это, потому что у меня большой опыт программирования на C++, а мы этим не занимаемся. Другими словами, в этом нет необходимости. И обратите внимание, что в Java, если вы нажмете на висящий указатель, вы получите обычное исключение; в C++ это исключение обычно не перехватывается и завершает программу.
Не хочешь этого делать? Тогда следуйте некоторым простым правилам аля C / C++.
Не создавайте экземпляры вещей так легко, считать, что каждый «новый» может доставить вам массу неприятностей, и СОБЛЮДАЙТЕ эти простые правила.
Класс должен обращаться к памяти только тремя способами ->
Он может «ИМЕТЬ» учеников класса, и они будут соблюдать следующие правила:
Это означает, что вам нужно иметь в виду (как это делает Java), кто является владельцем или родителем каждого ресурса, и уважать это право собственности. Объект удаляется только тем классом, который его создал. Также ->
Некоторые участники будут «ИСПОЛЬЗУЮТСЯ», но не будут собственными или «ИМЕЮТ». Это «СОБСТВЕННЫЕ» в другом классе и передаются конструктору в качестве аргументов. Поскольку они принадлежат другому классу, мы НИКОГДА не удалим или закроем его, только родительский элемент может.
Метод в классе также может создавать экземпляры локальных объектов для внутреннего использования, которые НИКОГДА не будут выходить за пределы класса, или они должны были быть обычными "имеющими" объектами.
Наконец, чтобы все это работало, вам необходимо иметь дисциплинированный дизайн с классами в иерархической форме и без циклов.
В этом дизайне И, следуя приведенным выше правилам, дочерний класс в иерархическом дизайне никогда не сможет получить доступ к указателю, который был уничтожен, потому что это означает, что родительский элемент был уничтожен раньше дочернего, чего не будет в иерархической ациклической структуре. разрешить это.
Наконец, также помните, что при запуске вашей системы вы должны строить иерархию сверху вниз и разрушать снизу вверх. У вас никогда нигде не будет нулевого указателя или кто-то нарушает правила.
Согласованы, хотя и концептуально. Ага, надо иметь план. Но тогда вам нужны программисты, которые МОГУТ СОЗДАТЬ ПЛАНЫ и обладают способностью мыслить логически, а также разрабатывать и поддерживать согласованные шаблоны. А еще есть работодатели, которые в первую очередь уделяют внимание деньгам и заработной плате ;-). А затем начните смотреть на спецификацию JPA, чтобы получить представление о том, что составляет последовательный шаблон / план и что требуется для его разработки и / или документирования.
Этот ответ актуален для C++, но не для языка со сборкой мусора, такого как Java.
Я с уважением не согласен. Хорошая обработка памяти в JAVA (или почти на любом другом языке) даст вам много преимуществ. От лучшей стабильности при уменьшении нулевых указателей, лучшей производительности за счет меньшего объема памяти, до лучшего дизайна, поскольку отношения лучше контролируются. Я предполагаю, что неаккуратное управление памятью многих приложений JAVA приводит к частым NPE и утечкам памяти.
Я полностью согласен с тем, что вы написали, и считаю очень прискорбным, что Java не делает различий между ссылками, которые инкапсулируют право собственности, и ссылками, которые этого не делают. Те, кто будет утверждать, что «это то, для чего нужен сборщик мусора», упускают важный момент: сборщик мусора исключает необходимость наличия у объектов неизменный владельцев, а также устраняет - возможность того, что висячая ссылка на удаленный объект превращается в ссылку на какой-либо другой произвольный объект. (что и может случиться в C++). Однако трудно написать правильный код, если несколько объектов инкапсулируют состояние изменяемого объекта как часть своего собственного.
Я предпочитаю думать о вещах, говоря, что ссылки могут инкапсулировать идентичность, изменяемое состояние, и то, и другое, или ни то, ни другое. Кроме того, ссылки могут инкапсулировать изменяемое состояние либо потому, что они идентифицируют неизменяемый объект, либо потому, что идентифицируемый ими объект никогда не будет подвергаться воздействию чего-либо, что могло бы его изменить. Жаль, что Java не имеет понятия о таких различиях, поскольку такие вещи, как проверка равенства и клонирование, могли бы обрабатываться на 99% автоматически, если бы это было так.
Я считаю, что то, что вы предлагаете, решит только небольшое подмножество проблем с нулевым указателем в Java и не решит исходную проблему, описанную здесь.
Возможно, это более актуально, чем вы думаете. Подробнее: ibm.com/developerworks/library/j-jtp06243 :)
Конечно, чужой код нельзя контролировать. Но правила по-прежнему действуют и полезны. В противном случае это все равно что сказать, что RUST (cmr.github.io/blog/2013/08/13/rust-by-concept) никогда не будет работать, если ему потребуется доступ к какой-либо библиотеке. Так что это действительно проблема, но следование владению указателем может значительно снизить риск.
В Java 7 есть новый служебный класс java.util.Objects, в котором есть метод requireNonNull(). Все это вызывает NullPointerException, если его аргумент равен нулю, но это немного очищает код. Пример:
Objects.requireNonNull(someObject);
someObject.doCalc();
Этот метод наиболее полезен для проверка непосредственно перед назначением в конструкторе, где при каждом его использовании можно сохранить три строки кода:
Parent(Child child) {
if (child == null) {
throw new NullPointerException("child");
}
this.child = child;
}
становится
Parent(Child child) {
this.child = Objects.requireNonNull(child, "child");
}
Фактически, ваш пример представляет собой раздувание кода: первая строка лишняя, потому что NPE будет брошен во второй строке. ;-)
Правда. Лучшим примером было бы, если бы вторая строка была doCalc(someObject).
Зависит. Если вы являетесь автором doCalc (), я бы предложил поместить проверку в тело этого метода (если возможно). И тогда вы, скорее всего, вызовете someObject.someMethod (), где снова нет необходимости проверять значение null. :-)
Что ж, если вы не являетесь автором doCalc(), и он не сразу бросает NPE, когда ему задано значение null, вам нужно будет проверить значение null и самостоятельно запустить NPE. Для этого и нужен Objects.requireNonNull().
Это не просто раздувание кода. Лучше проверить заранее, чем на полпути к методу, который вызывает побочные эффекты или использует время / пространство.
Я бы, вероятно, не бросил NPE, когда я проверяю аргумент на нули, я обычно бросаю IllegalArgumentException, и это неплохо, если вы предполагаете, что this.child = child "поймает" его , вы не указываете явно в своем коде, рефакторинг может сильно затруднить определение источника нуля. Раздутие кода в любой день намного лучше, чем волшебство.
Версия Objects.requireNonNull(object, string) (где вы можете передать сообщение об ошибке в качестве второго аргумента) более полезна, чем версия с одним аргументом (последняя, вероятно, просто добавлена для полноты), особенно когда вы используете ее для проверки значений нескольких аргументов. Скажем, вам нужно было проверить 3 аргумента на null, это уменьшит ваш код с 3 блоков if / then-throw (разделенных пустыми строками) до 3 отдельных строк, которым не нужны пустые строки.
Я предпочитаю это
public void simpleFunc(SomeObject someObject){
someObject = someObject != null ? someObject : new SomeObject(null);
someObject.doSomething();
}
Конечно, в моем примере SomeObject корректно обрабатывает нулевой параметр. Например, записывать такое событие и больше ничего не делать.
Просто никогда не используйте null. Не позволяй этого.
В моих классах большинство полей и локальных переменных имеют ненулевые значения по умолчанию, и я добавляю операторы контракта (всегда включенные утверждения) повсюду в коде, чтобы убедиться, что это выполняется (поскольку это более сжато и выразительно, чем позволяя ему появляются как NPE, а затем необходимо разрешить номер строки и т. д.).
Как только я применил эту практику, я заметил, что проблемы, казалось, исчезли сами собой. Вы поймаете вещи намного раньше в процессе разработки просто случайно и поймете, что у вас есть слабое место ... и, что более важно ... это помогает инкапсулировать проблемы различных модулей, разные модули могут `` доверять '' друг другу и больше не засорять код с конструкциями if = null else!
Это защитное программирование, которое в конечном итоге приводит к гораздо более чистому коду. Всегда дезинфицируйте данные, например здесь путем соблюдения жестких стандартов, и проблемы исчезнут.
class C {
private final MyType mustBeSet;
public C(MyType mything) {
mustBeSet=Contract.notNull(mything);
}
private String name = "<unknown>";
public void setName(String s) {
name = Contract.notNull(s);
}
}
class Contract {
public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}
Контракты похожи на мини-модульные тесты, которые всегда выполняются, даже в производственной среде, и когда что-то выходит из строя, вы знаете, почему, а не случайный NPE, который вам нужно как-то выяснить.
почему это было бы отвергнуто? по моему опыту, это намного превосходит другие подходы, хотелось бы знать, почему бы и нет
Я согласен, этот подход предотвращает проблемы, связанные с нулевыми значениями, вместо того, чтобы исправлять их, повсюду проверяя нулевые значения кода.
Проблема с этим подходом заключается в том, что если имя никогда не задано, оно имеет значение «<неизвестно>», которое ведет себя как заданное значение. Теперь предположим, что мне нужно проверить, не было ли имя никогда не задано (неизвестно), я должен провести сравнение строки со специальным значением «<неизвестно>».
Истинно хороший аргумент, Стив. Я часто использую это значение как константу, например общедоступная статическая конечная строка UNSET = "__ unset" ... частное поле строки = UNSET ... затем частное логическое значение isSet () {return UNSET.equals (field); }
IMHO, это реализация шаблона Null Object с собственной реализацией Optional (Contract). Как он ведет себя по классу настойчивости? Я не вижу применимого в этом случае.
@Kurapika - согласен. Я думаю, что «никогда не использовать null» не совсем практично в Java. Но в 99% случаев это так, и имо следует поощрять это. Мне нравится то, что я вижу с такими языками, как Kotlin, которые решают эту проблему.
Вы можете использовать перехватчик перед вызовом метода. Это то, на чем фокусируется аспектно-ориентированное программирование.
Предположим, что M1 (объектный тест) - это метод, а M2 - это метод, в котором мы применяем аспект перед вызовом метода, M2(Object test2). Если test2 != null, то вызовите M1, в противном случае сделайте другое. Он работает для всех методов, к которым вы хотите применить аспект. Если вы хотите применить аспект для поля экземпляра и конструктора, вы можете использовать AspectJ. Spring также может быть лучшим выбором для аспекта метода.
вы предлагаете перехватить каждый метод всего приложения?
Во-первых, мы не можем удалить все нулевые условия. Мы можем уменьшить их, используя аннотации @NotNull и @Nullable (как уже упоминалось). Но это должно быть подкреплено какой-то структурой. Здесь может помочь Овал.
Основная идея заключается в том, что объект / параметры / конструктор всегда должны удовлетворять предварительным условиям. У вас может быть множество предварительных условий, таких как Nullable, NotNull и OVal, которые позаботятся о том, чтобы объект был в согласованном состоянии при вызове.
Я предполагаю, что OVal внутренне использует AspectJ для проверки предварительных условий.
@Guarded
public class BusinessObject
{
public BusinessObject(@NotNull String name)
{
this.name = name;
}
...
}
Например,
// Throws a ConstraintsViolatedException because parameter name is null
BusinessObject bo = new BusinessObject(null);
В Java 8 появился новый класс java.util.Optional, который, возможно, решает некоторые проблемы. По крайней мере, можно сказать, что это улучшает читаемость кода, а в случае общедоступных API делает контракт API более понятным для разработчика клиента.
Они так работают:
Необязательный объект для данного типа (Fruit) создается как возвращаемый тип метода. Он может быть пустым или содержать объект Fruit:
public static Optional<Fruit> find(String name, List<Fruit> fruits) {
for (Fruit fruit : fruits) {
if (fruit.getName().equals(name)) {
return Optional.of(fruit);
}
}
return Optional.empty();
}
Теперь посмотрите на этот код, в котором мы ищем в списке Fruit (fruits) данный экземпляр Fruit:
Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
Fruit fruit = found.get();
String name = fruit.getName();
}
Вы можете использовать оператор map() для выполнения вычислений или извлечения значения из необязательного объекта. orElse() позволяет резервировать пропущенные значения.
String nameOrNull = find("lemon", fruits)
.map(f -> f.getName())
.orElse("empty-name");
Конечно, проверка нулевого / пустого значения по-прежнему необходима, но, по крайней мере, разработчик осознает, что значение может быть пустым, и риск забыть о проверке ограничен.
В API, созданном с нуля с использованием Optional, всякий раз, когда возвращаемое значение может быть пустым, и возвращать простой объект только тогда, когда он не может быть null (соглашение), клиентский код может отказаться от нулевых проверок для возвращаемых значений простого объекта ...
Конечно, Optional можно также использовать в качестве аргумента метода, возможно, это лучший способ указать необязательные аргументы, чем в некоторых случаях 5 или 10 методов перегрузки.
Optional предлагает другие удобные методы, такие как orElse, который позволяет использовать значение по умолчанию, и ifPresent, который работает с лямбда-выражения.
Я предлагаю вам прочитать эту статью (мой основной источник для написания этого ответа), в которой хорошо объяснены проблема NullPointerException (и вообще нулевой указатель), а также (частичное) решение, предложенное Optional: Необязательные объекты Java.
Guava от Google имеет необязательное значение для Java 6+.
очень важно подчеркнуть, что использование Optional только с ifPresent () добавляет нет намного больше, чем обычная проверка нуля. Его основная ценность заключается в том, что это монада, которую можно использовать в цепочках функций map / flapMap, которая дает результаты, аналогичные оператору Элвиса в Groovy, упомянутому в другом месте. Тем не менее, даже без этого использования синтаксис orElse / orElseThrow также очень полезен.
В этом блоге есть хорошая запись о Optional winterbe.com/posts/2015/03/15/avoid-null-checks-in-java
Я действительно никогда не понимал, почему людям так нравится этот шаблонный код dzone.com/articles/java-8-elvis-operator
Почему люди склонны делать именно этот if (optional.isPresent()){ optional.get(); } вместо optional.ifPresent(o -> { ...})
Таким образом, помимо договорных намеков API, это действительно просто обслуживание функциональных программистов, которым нравится бесконечно связывать методы.
Делая это в своем собственном коде, вы можете избежать проверок! = Null.
В большинстве случаев нулевые проверки, кажется, охраняют циклы над коллекциями или массивами, поэтому просто инициализируйте их пустыми, вам не понадобятся нулевые проверки.
// Bad
ArrayList<String> lemmings;
String[] names;
void checkLemmings() {
if (lemmings != null) for(lemming: lemmings) {
// do something
}
}
// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};
void checkLemmings() {
for(lemming: lemmings) {
// do something
}
}
В этом есть крошечные накладные расходы, но они того стоят для более чистого кода и меньшего количества исключений NullPointerExceptions.
+1 С этим я согласен. Вы никогда не должны возвращать половину инициализированных объектов. Код, связанный с Jaxb, и код bean-компонента не подходят для этого. Это плохая практика. Все коллекции должны быть инициализированы, и все объекты должны существовать (в идеале) без нулевых ссылок. Рассмотрим объект, в котором есть коллекция. Проверка того, что объект не является нулевым, что коллекция не является нулевой и что коллекция не содержит нулевых объектов, неразумно и глупо.
Мы использовали библиотеки Apache (Apache Commons) для решения этой проблемы.
ObjectUtils.equals(object, null)
или же
CollectionUtils.isEmpty(myCollection);
или же
StringUtils.isEmpty("string");
Мне нравится предыдущий ответ перед, как практика, предоставлением начальных значений по умолчанию или пустых наборов для коллекций, чтобы свести к минимуму необходимость.
Это могут быть простые способы использования, которые не позволяют вам иметь исключение NullPointerException или использовать пустую коллекцию. Это не отвечает на вопрос, что делать с нулевым объектом, но они обеспечивают некоторые проверки для основных проверок объекта или коллекции.
Надеюсь это поможет.
Мне не нравятся CollectionUtils.isEmpty и StringUtils.isEmpty, поскольку они также выполняют нулевую проверку, что не подразумевается именем метода.
Способ избежать ненужного null-checks прост:
You need to know which variables can be null, and which cannot, and you need to be confident about which category a given variable fall into.
Но, хотя об этом можно сказать достаточно просто, добиться этого труднее. Ключ находится в части confident, потому что как вы можете быть уверены, что переменная не может быть нулевой?
На этот вопрос нет простых и быстрых ответов, но вот несколько советов:
Чистый код. Самая важная вещь для рассуждений о поведении фрагмента кода - это то, что он написан в легком для понимания материале. Назовите свои переменные на основе того, что они представляют, назовите свои методы в соответствии с тем, что они делают, примените Single responsibility principle (S в SOLID: http://en.wikipedia.org/wiki/SOLID_(object-oriated_design), это означает, что каждый фрагмент кода должен иметь единственную ответственность и делать это, и ничего больше). После того, как ваш код станет чистым, его будет намного проще рассуждать, в том числе на нескольких уровнях / уровнях кода. В запутанном коде попытка понять, что делает метод, может заставить вас забыть, почему вы вообще читаете этот метод. (Совет: прочтите «Чистый код» Роберта К. Мартина)
Избегайте возврата значений null. Если значение null мешает вашей программе работать правильно, вместо этого бросьте exception (обязательно добавьте соответствующую обработку ошибок). Случаи, когда возврат значения null может быть приемлемым, - это, например, попытка получить объект из базы данных. В этих случаях напишите код, который обрабатывает значения null, и отметьте за ухом, что здесь у нас есть что-то, что может вернуть null. Обработайте возвращенные значения null как можно ближе к вызывающему методу, возвращающему null (не просто слепо передавать его обратно в цепочку вызовов).
НИКОГДА не передавайте явные значения null в качестве параметров (по крайней мере, не для разных классов). Если вы когда-либо оказывались в ситуации, когда передача параметра null является единственным вариантом, создание нового метода без этого параметра - лучший вариант.
Подтвердите свой вклад! Определите «точки входа» в ваше приложение. Они могут все, от веб-сервисов, REST-сервисов, удаленных классов EJB, контроллеров и т. д. Для каждого метода в этих точках входа спросите себя: «Будет ли этот метод выполняться правильно, если этот параметр равен нулю?» Если ответ отрицательный, добавьте Validate.notNull(someParam, "Can't function when someParam is null!");. Это вызовет ошибку IllegalArgumentException, если требуемый параметр отсутствует. Хорошая вещь в этом типе проверки в точках входа заключается в том, что вы можете легко предположить в коде, выполняемом из точки входа, что эта переменная никогда не будет нулевой! Кроме того, если это не удается, находясь в точке входа, отладка становится намного проще, чем если бы вы только что получили NullPointerException глубоко в своем коде, поскольку такой сбой может означать только одно: клиент не отправим вам всю необходимую информацию. В большинстве случаев вы хотите проверить все входные параметры, если вы окажетесь в положении, когда вам нужно разрешить много значений null, это может быть признаком плохо спроектированного интерфейса, который требует рефакторинга / дополнений для удовлетворения потребностей. клиентов.
При работе с Collections возвращайте пустой, а не нуль!
При работе с базой данных используйте ограничения not null. Таким образом вы узнаете, что значение, считанное из базы данных, не может быть нулевым, и вам не придется его проверять.
Структурируйте свой код и придерживайтесь его. Это позволяет вам делать предположения о поведении кода, например, если все входные данные вашего приложения проверены, вы можете предположить, что эти значения никогда не будут нулевыми.
Если вы еще этого не сделали, напишите автоматизированные тесты вашего кода. Написав тесты, вы будете рассуждать о своем коде, а также станете более уверенными в том, что он делает то, что должен. Кроме того, автоматические тесты защищают вас от грубых ошибок во время рефакторинга, сразу сообщая вам, что этот фрагмент кода не выполняет то, что раньше.
Конечно, вам все равно придется выполнять нулевую проверку, но ее можно сократить до минимума (то есть ситуация, когда знать вы можете получать нулевое значение, а не везде, чтобы быть уверенным.) Когда дело доходит до нулевых проверок. , я на самом деле предпочитаю использовать тернарный оператор (но используйте осторожно, когда вы начинаете их вкладывать, они становятся действительно беспорядочными.)
public String nullSafeToString(final Object o) {
return o != null ? o.toString() : "null";
}
Могу я ответить на него более широко!
Мы, как правило, сталкиваемся с этой проблемой, когда методы получают параметры не так, как мы ожидали (неправильный вызов метода - это ошибка программиста). Например: вы ожидаете получить объект, вместо этого вы получаете ноль. Вы ожидаете получить строку, содержащую хотя бы один символ, вместо этого вы получите пустую строку ...
Итак, нет никакой разницы между:
if (object == null){
//you called my method badly!
}
или же
if (str.length() == 0){
//you called my method badly again!
}
Они оба хотят убедиться, что мы получили допустимые параметры, прежде чем выполнять какие-либо другие функции.
Как упоминалось в некоторых других ответах, чтобы избежать вышеуказанных проблем, вы можете следовать шаблону Дизайн по контракту. См. http://en.wikipedia.org/wiki/Design_by_contract.
Чтобы реализовать этот шаблон в Java, вы можете использовать аннотации ядра Java, такие как javax.annotation.NotNull, или использовать более сложные библиотеки, такие как Валидатор гибернации.
Просто образец:
getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)
Теперь вы можете безопасно разработать основную функцию вашего метода без необходимости проверять входные параметры, они защищают ваши методы от неожиданных параметров.
Вы можете пойти дальше и убедиться, что в вашем приложении могут быть созданы только действительные pojos. (образец с сайта валидатора спящего режима)
public class Car {
@NotNull
private String manufacturer;
@NotNull
@Size(min = 2, max = 14)
private String licensePlate;
@Min(2)
private int seatCount;
// ...
}
javax по определению является нет "ядром Java".
Я считаю, что в этом случае очень полезны предварительные условия Guava. Мне не нравится оставлять нули для исключения нулевого указателя, поскольку единственный способ понять NPE - найти номер строки. Номера строк в производственной и разрабатываемой версиях могут быть разными.
Используя предварительные условия Guava, я могу проверить нулевые параметры и определить значимое сообщение об исключении в одной строке.
Например,
Preconditions.checkNotNull(paramVal, "Method foo received null paramVal");
Это самая частая ошибка, возникающая у большинства разработчиков.
У нас есть несколько способов справиться с этим.
Подход 1:
org.apache.commons.lang.Validate //using apache framework
notNull (объект объекта, строковое сообщение)
Подход 2:
if (someObject!=null){ // simply checking against null
}
Подход 3:
@isNull @Nullable // using annotation based validation
Подход 4:
// by writing static method and calling it across whereever we needed to check the validation
static <T> T isNull(someObject e){
if (e == null){
throw new NullPointerException();
}
return e;
}
Объявление. 4. Это не очень полезно - когда вы проверяете, является ли указатель нулевым, вы, вероятно, захотите вызвать для него метод. Вызов метода с нулевым значением дает то же поведение - NullPointerException.
Я крайне игнорирую ответы, предлагающие использовать нулевые объекты в любой ситуации. Этот шаблон может разорвать договор и похоронить проблемы все глубже и глубже, вместо того, чтобы решать их, не говоря уже о том, что неправильное использование приведет к созданию еще одной кучи шаблонного кода, который потребует дальнейшего обслуживания.
В действительности, если что-то, возвращаемое из метода, может иметь значение NULL, и вызывающий код должен принять решение по этому поводу, должен быть более ранний вызов, который обеспечивает состояние.
Также имейте в виду, что этот шаблон нулевого объекта будет потреблять память, если его использовать без осторожности. Для этого - экземпляр NullObject должен совместно использоваться владельцами, а не быть уникальным экземпляром для каждого из них.
Также я бы не рекомендовал использовать этот шаблон, когда тип предназначен для представления примитивного типа - например, математические объекты, которые не являются скалярами: векторы, матрицы, комплексные числа и объекты POD (простые старые данные), которые предназначены для хранения состояния. в виде встроенных типов Java. В последнем случае вы закончите вызовом методов получения с произвольными результатами. Например, что должен вернуть метод NullPerson.getName ()?
Такие случаи стоит рассмотреть, чтобы избежать абсурдных результатов.
Решение с hasBackground () имеет один недостаток - оно не является потокобезопасным. Если вам нужно вызвать два метода вместо одного, вам нужно синхронизировать всю последовательность в многопоточной среде.
@pkalinow Вы сделали надуманный пример только для того, чтобы указать на недостаток этого решения. Если код не предназначен для работы в многопоточном приложении, недостатка нет. Я мог бы поставить вам, вероятно, 90% вашего кода, который не является потокобезопасным. Мы не говорим здесь об этом аспекте кода, мы говорим о шаблоне проектирования. А многопоточность - это отдельная тема.
Конечно, в однопоточном приложении это не проблема. Я дал этот комментарий, потому что иногда это проблема.
@pkalinow Если вы изучите эту тему поближе, то обнаружите, что шаблон проектирования Null Object не решит проблемы многопоточности. Так что это не имеет значения. И, честно говоря, я нашел места, где этот шаблон хорошо подошел бы, поэтому мой первоначальный ответ на самом деле немного неверен.
Вот мой подход ..
class MyObjectHandler
{
public static final int EXCEPTION = (-3);
public static final int INACCESSIBLE = (-2);
public static int doSomething (MyObject obj, MyObjectParameter [] input)
{
int returnValue= 0;
try
{
if (obj != null)
{
returnValue = obj.doSomething(input);
}
else
{
returnValue = MyObjectHandler.INACCESSIBLE;
}
}
catch (Exception e)
{
e.printStack();
returnValue = MyObjectHandler.EXCEPTION;
}
finally
{
return returnValue;
}
}
..
}
Тогда ваш код будет таким:
import xx.xx.xx.MyObjectHandler;
import xx.xx.xx.MyObjectParameter;
class Test
{
public static void main ()
{
MyObject obj = null;
MyObjectHandler.doSomething(obj, null);
}
..
}
Это очень распространенная проблема для каждого разработчика Java. Таким образом, в Java 8 есть официальная поддержка для решения этих проблем без загромождения кода.
В Java 8 появился java.util.Optional<T>. Это контейнер, который может содержать или не содержать ненулевое значение. Java 8 предоставила более безопасный способ обработки объекта, значение которого в некоторых случаях может быть нулевым. Он вдохновлен идеями Haskell и Scala.
Вкратце, необязательный класс включает методы для явной обработки случаев, когда значение присутствует или отсутствует. Однако преимущество по сравнению с нулевыми ссылками состоит в том, что класс Optional <T> заставляет задуматься о случае, когда значение отсутствует. Как следствие, вы можете предотвратить непреднамеренные исключения нулевого указателя.
В приведенном выше примере у нас есть фабрика домашнего обслуживания, которая возвращает дескриптор для нескольких устройств, доступных в доме. Но эти услуги могут быть доступны / функциональны, а могут и не быть; это означает, что это может привести к исключению NullPointerException. Вместо добавления нулевого условия if перед использованием какой-либо службы давайте заключим его в Optional <Service>.
ПЕРЕДАЧА К ВАРИАНТУ <T>
Давайте рассмотрим способ получения ссылки на услугу с завода. Вместо того, чтобы возвращать ссылку на службу, оберните ее с помощью Optional. Он позволяет пользователю API знать, что возвращенная услуга может быть доступна, а может и не работать, использовать в целях защиты.
public Optional<Service> getRefrigertorControl() {
Service s = new RefrigeratorService();
//...
return Optional.ofNullable(s);
}
Как видите, Optional.ofNullable() предоставляет простой способ обернуть ссылку. Есть еще один способ получить ссылку на Optional: Optional.empty() и Optional.of(). Один для возврата пустого объекта вместо перенастройки null, а другой для обертывания объекта, не допускающего значения NULL, соответственно.
ТАК КАК ТОЧНО ЭТО ПОМОГАЕТ ИЗБЕЖАТЬ НУЛЕВОЙ ПРОВЕРКИ?
После того, как вы обернули ссылочный объект, Optional предоставляет множество полезных методов для вызова методов для обернутой ссылки без NPE.
Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);
Optional.ifPresent вызывает данного Consumer со ссылкой, если это ненулевое значение. В противном случае ничего не делает.
@FunctionalInterface
public interface Consumer<T>
Представляет операцию, которая принимает один входной аргумент и не возвращает результата. Ожидается, что в отличие от большинства других функциональных интерфейсов, Consumer будет работать с побочными эффектами.
Это так чисто и легко для понимания. В приведенном выше примере кода вызывается HomeService.switchOn(Service), если необязательная удерживающая ссылка не равна нулю.
Мы очень часто используем тернарный оператор для проверки нулевого условия и возврата альтернативного значения или значения по умолчанию. Необязательно предоставляет другой способ обработки того же условия без проверки null. Optional.orElse (defaultObj) возвращает defaultObj, если Optional имеет нулевое значение. Давайте использовать это в нашем примере кода:
public static Optional<HomeServices> get() {
service = Optional.of(service.orElse(new HomeServices()));
return service;
}
Теперь HomeServices.get () делает то же самое, но лучше. Он проверяет, инициализирована ли служба или нет. Если это так, то верните то же самое или создайте новую Новую службу. Необязательный <T> .orElse (T) помогает вернуть значение по умолчанию.
Наконец, вот наш NPE, а также нулевой код без проверки:
import java.util.Optional;
public class HomeServices {
private static final int NOW = 0;
private static Optional<HomeServices> service;
public static Optional<HomeServices> get() {
service = Optional.of(service.orElse(new HomeServices()));
return service;
}
public Optional<Service> getRefrigertorControl() {
Service s = new RefrigeratorService();
//...
return Optional.ofNullable(s);
}
public static void main(String[] args) {
/* Get Home Services handle */
Optional<HomeServices> homeServices = HomeServices.get();
if (homeServices != null) {
Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
refrigertorControl.ifPresent(HomeServices::switchItOn);
}
}
public static void switchItOn(Service s){
//...
}
}
Полный пост - NPE, а также код без проверки Null… Правда?.
В приведенном выше коде есть проверка на null - if (homeServices != null) {, который можно заменить на homeServices.ifPresent(h -> //action);
Вы можете связать свой класс с модульным тестированием, используя фреймворк, например JUnit. Таким образом, ваш код будет чистым (без бесполезных проверок), и вы будете уверены, что ваши экземпляры не будут нулевыми.
Это одна из многих хороших причин для использования модульного тестирования.
С помощью лямбда-выражений Java 8 можно определить служебные методы, которые обрабатывают вложенные проверки на null почти красивым образом.
void example() {
Entry entry = new Entry();
// This is the same as H-MANs solution
Person person = getNullsafe(entry, e -> e.getPerson());
// Get object in several steps
String givenName = getNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.getGivenName());
// Call void methods
doNullsafe(entry, e -> e.getPerson(), p -> p.getName(), n -> n.nameIt());
}
/** Return result of call to f1 with o1 if it is non-null, otherwise return null. */
public static <R, T1> R getNullsafe(T1 o1, Function<T1, R> f1) {
if (o1 != null) return f1.apply(o1);
return null;
}
public static <R, T0, T1> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, R> f2) {
return getNullsafe(getNullsafe(o0, f1), f2);
}
public static <R, T0, T1, T2> R getNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Function<T2, R> f3) {
return getNullsafe(getNullsafe(o0, f1, f2), f3);
}
/** Call consumer f1 with o1 if it is non-null, otherwise do nothing. */
public static <T1> void doNullsafe(T1 o1, Consumer<T1> f1) {
if (o1 != null) f1.accept(o1);
}
public static <T0, T1> void doNullsafe(T0 o0, Function<T0, T1> f1, Consumer<T1> f2) {
doNullsafe(getNullsafe(o0, f1), f2);
}
public static <T0, T1, T2> void doNullsafe(T0 o0, Function<T0, T1> f1, Function<T1, T2> f2, Consumer<T2> f3) {
doNullsafe(getNullsafe(o0, f1, f2), f3);
}
class Entry {
Person getPerson() { return null; }
}
class Person {
Name getName() { return null; }
}
class Name {
void nameIt() {}
String getGivenName() { return null; }
}
(This answer was first posted here.)
В Java 8 теперь есть необязательный класс, который обертывает рассматриваемый объект, и если значение присутствует, isPresent () вернет true, а get () вернет значение.
http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
Я следую приведенным ниже инструкциям, чтобы избежать нулевых проверок.
По возможности избегайте ленивая инициализация переменных-членов. Инициализируйте переменные в самом объявлении. Это обработает исключения NullPointerExceptions.
Определите изменчивость переменных-членов в начале цикла. Эффективно используйте языковые конструкции, такие как ключевое слово final.
Если вы знаете, что дополнения для метода не будут изменены, объявите их как final.
Максимально ограничьте мутация данных. Некоторые переменные могут быть созданы в конструкторе и никогда не могут быть изменены. Удалите общедоступные методы установки, если они действительно не требуются.
Например. Предположим, что один класс в вашем приложении (A.java) поддерживает коллекцию наподобие HashMap. Не предоставляйте метод получения public в A.java и разрешайте B.java напрямую добавлять элемент в Map. Вместо этого предоставьте API в A.java, который добавляет элемент в коллекцию.
// Avoid
a.getMap().put(key,value)
//recommended
public void addElement(Object key, Object value){
// Have null checks for both key and value here : single place
map.put(key,value);
}
И, наконец, эффективно используйте блоки try{} catch{} finally{} в нужных местах.
Вероятно, лучшей альтернативой для Java 8 или новее является использование класса Optional.
Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);
Это особенно удобно для длинных цепочек возможных нулевых значений. Пример:
Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
.map(f -> f.getBar())
.map(b -> b.getBaz())
.map(b -> b.getInt());
Пример того, как генерировать исключение для null:
Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);
В Java 7 появился метод Objects.requireNonNull, который может быть полезен, когда что-то нужно проверить на ненулевое значение. Пример:
String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();
В Java 8 вы можете использовать тип T для локальной переменной / поля / аргумента-метода / типа-возврата, если он никогда не назначал null (и не проверял наличие null), или введите Optional<T>, если он может быть null. Затем используйте метод map для обработки T -> и метод flatMap для обработки T -> Optional<R>:
class SomeService {
@Inject
private CompanyDao companyDao;
// return Optional<String>
public Optional<String> selectCeoCityByCompanyId0(int companyId) {
return companyDao.selectById(companyId)
.map(Company::getCeo)
.flatMap(Person::getHomeAddress)
.flatMap(Address::getCity);
}
// return String + default value
public String selectCeoCityByCompanyId1(int companyId) {
return companyDao.selectById(companyId)
.map(Company::getCeo)
.flatMap(Person::getHomeAddress)
.flatMap(Address::getCity)
.orElse("UNKNOWN");
}
// return String + exception
public String selectCeoCityByCompanyId2(int companyId) throws NoSuchElementException {
return companyDao.selectById(companyId)
.map(Company::getCeo)
.flatMap(Person::getHomeAddress)
.flatMap(Address::getCity)
.orElseThrow(NoSuchElementException::new);
}
}
interface CompanyDao {
// real situation: no company for such id -> use Optional<Company>
Optional<Company> selectById(int id);
}
class Company {
// company always has ceo -> use Person
Person ceo;
public Person getCeo() {return ceo;}
}
class Person {
// person always has name -> use String
String firstName;
// person can be without address -> use Optional<Address>
Optional<Address> homeAddress = Optional.empty();
public String getFirstName() {return firstName;}
public Optional<Address> getHomeAddress() {return homeAddress;}
}
class Address {
// address always contains country -> use String
String country;
// city field is optional -> use Optional<String>
Optional<String> city = Optional.empty();
String getCountry() {return country;}
Optional<String> getCity() {return city;}
}
Шаблон нулевого объекта можно использовать в качестве решения этой проблемы. Для этого следует изменить класс someObject.
public abstract class SomeObject {
public abstract boolean isNil();
}
public class NullObject extends SomeObject {
@Override
public boolean isNil() {
return true;
}
}
public class RealObject extends SomeObject {
@Override
public boolean isNil() {
return false;
}
}
Теперь вместо проверки,
if (someobject != null) {
someobject.doCalc();
}
Мы можем использовать,
if (!someObject.isNil()) {
someobject.doCalc();
}
Ссылка: https://www.tutorialspoint.com/design_pattern/null_object_pattern.htm
Вы просто модифицируете чек. Никакой реальной выгоды не получено. Несмотря на то, что мы приложили дополнительные усилия для реализации предложенного шаблона, код все равно не чистый.
Если вы реализуете шаблон объекта Null, вместо возврата null вы должны вернуть NullObject. Таким образом, вам не понадобится чек. Просто позвоните object.doCalc(). Если объект является экземпляром NullObject, doCalc() ничего не сделает. Это будет просто пустая реализация метода.
Вы знаете, вы в основном заменяете Null своей собственной версией Null, а затем говорите, что используйте эту версию Null, поэтому вам не нужно использовать другую, которая идет с языком :)
Начиная с Java 7 существует класс java.util.Objects.
Но начиная с Java 8, вы можете использовать методы Objects.isNull(var) и Objects.nonNull(var) класса Objects для проверки нулевого указателя.
Например,
String var1 = null;
Date var2 = null;
Long var3 = null;
if (Objects.isNull(var1) && Objects.isNull(var2) && Objects.isNull(var3))
System.out.println("All Null");
else if (Objects.nonNull(var1) && Objects.nonNull(var2) && Objects.nonNull(var3))
System.out.println("All Not Null");
Если вы используете java8 или более позднюю версию, выберите isNull(yourObject) от java.util.Objects.
Пример:-
String myObject = null;
Objects.isNull(myObject); //will return true
Использование: приведенный ниже код возвращает ненулевое значение (если имя не равно нулю, то это значение будет возвращено, иначе будет возвращено значение по умолчанию).
final String name = "Jobin";
String nonNullValue = Optional.ofNullable(name).filter(Objects::nonNull).orElse("DefaultName");
Это не сильно отличается от myObject == null и было введено в Java8 для Predicates в функции лямбда.
Objects.isNull () доступен с Java8 (не Java7)
@RealHowTo Спасибо, что указали на это, я обновил ответ, на самом деле Objects введен в java7, isNull добавлен к нему позже.
Java 8 представила новый класс Optional в пакете java.util.
Преимущества Java 8 Дополнительно:
1.) Нулевые проверки не требуются. 2.) Больше никаких исключений NullPointerException во время выполнения. 3.) Мы можем разрабатывать чистые и аккуратные API.
По желанию - объект-контейнер, который может содержать или не содержать ненулевое значение. Если значение присутствует, isPresent () вернет true, а get () вернет значение.
Для получения дополнительной информации найдите здесь документы оракула: - https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
В общем, чтобы избежать заявления
if (object != null) {
....
}
начиная с java 7 вы можете использовать методы Objects:
Objects.isNull (объект)
Objects.nonNull (объект)
Objects.requireNonNull (объект)
Objects.equals (объект1, объект2)
начиная с java 8 вы можете использовать необязательный класс (когда использовать)
object.ifPresent(obj -> ...); Java 8
object.ifPresentOrElse(obj -> ..., () -> ...); Java 9
полагаться на контракт метода (JSR 305) и использовать Найдите ошибки. Пометьте свой код аннотациями @javax.annotation.Nullable и @javax.annotation.Nonnnul. Также имеются предварительные условия.
Preconditions.checkNotNull (объект);
В особых случаях (например, для строк и коллекций) вы можете использовать служебные методы apache-commons (или Google guava):
public static boolean isEmpty(CharSequence cs) //apache CollectionUtils
public static boolean isEmpty(Collection coll) //apache StringUtils
public static boolean isEmpty(Map map) //apache MapUtils
public static boolean isNullOrEmpty(@Nullable String string) //Guava Strings
public static Object defaultIfNull(Object object, Object defaultValue)
объясните очень хорошо
Один вариант, который у вас есть
Используйте фреймворк для проверки @RequiresNonNull в методах. например, вы получите это, если вызовете метод, аннотированный как таковой, с нулевым аргументом. Он не сработает во время компиляции, даже до запуска вашего кода! поскольку во время выполнения это будет NullPointerException
@RequiresNonNull(value = { "#1" })
static void check( Boolean x) {
if (x) System.out.println("true");
else System.out.println("false");
}
public static void main(String[] args) {
check(null);
}
получает
[ERROR] found : null
[ERROR] required: @Initialized @NonNull Boolean
[ERROR] -> [Help 1]
Существуют и другие методы, такие как Use Java 8 Optional, Guava Annotations, Null Object pattern и т. д. Не имеет значения, если вы достигли своей цели избежать! = Null
В Java 8 вы можете передать поставщика вспомогательному методу, как показано ниже,
if (CommonUtil.resolve(()-> a.b().c()).isPresent()) {
}
Выше заменяет код котельной плиты, как показано ниже,
if (a!=null && a.b()!=null && a.b().c()!=null) {
}
//CommonUtil.java
public static <T> Optional<T> resolve(Supplier<T> resolver) {
try {
T result = resolver.get();
return Optional.ofNullable(result);
} catch (NullPointerException var2) {
return Optional.empty();
}
}
Вы можете избежать многого, чтобы избежать NullPointerException, просто следуя большинству других ответов на вопрос, я просто хочу добавить несколько больше способов, которые были введены в Java 9, чтобы изящно справиться с этим сценарием, а также продемонстрировать, что некоторые из старых также можно использовать и, таким образом, уменьшить усилия.
public static boolean isNull(Object obj)
Возвращает истину, если предоставленная ссылка равна нулю, в противном случае возвращает ложный.
Начиная с Java 1.8
public static boolean nonNull(Object obj)
Возвращает истину, если предоставленная ссылка не равна нулю, в противном случае возвращает ложный.
Начиная с Java 1.8
public static <T> T requireNonNullElse(T obj, T defaultObj)
Возвращает первый аргумент, если он не равен нулю, и в противном случае возвращает ненулевой второй аргумент.
Начиная с Java 9
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)
Возвращает первый аргумент, если он не равен нулю, и в противном случае возвращает ненулевое значение supplier.get ().
Начиная с Java 9
public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier)
Проверяет, что указанная ссылка на объект не является нулевой, и в противном случае выдает настраиваемое исключение NullPointerException.
Начиная с Java 1.8
Более подробную информацию о вышеуказанных функциях можно найти в здесь.
вы можете видеть, что есть много ответов с большим количеством голосов, что особенного в вашем ответе?
Я просто хотел добавить еще несколько функций, доступных с Java 9.
затем выделите это жирным шрифтом в начале вашего сообщения
Котлин с нулевой безопасностью - элегантная альтернатива, но это означает большее изменение.
Функциональный подход может помочь обернуть повторяющиеся нулевые проверки и выполнить анонимный код, как в примере ниже.
BiConsumer<Object, Consumer<Object>> consumeIfPresent = (s,f) ->{
if (s!=null) {
f.accept(s);
}
};
consumeIfPresent.accept(null, (s)-> System.out.println(s) );
consumeIfPresent.accept("test", (s)-> System.out.println(s));
BiFunction<Object, Function<Object,Object>,Object> executeIfPresent = (a,b) ->{
if (a!=null) {
return b.apply(a);
}
return null;
};
executeIfPresent.apply(null, (s)-> {System.out.println(s);return s;} );
executeIfPresent.apply("test", (s)-> {System.out.println(s);return s;} );
Другой альтернативой проверке! = Null является (если вы не можете избавиться от нее с точки зрения дизайна):
Optional.ofNullable(someobject).ifPresent(someobject -> someobject.doCalc());
или же
Optional.ofNullable(someobject).ifPresent(SomeClass::doCalc);
SomeClass - это тип какого-то объекта.
Однако вы не можете получить возвращаемое значение из doCalc (), поэтому полезно только для методов void.
Вы можете получить значение, используя map в сочетании с get или любой другой метод получения значения в Optional вместо ifPresent.
Java 8 представила новый класс Optional в пакете java.util. Он используется для обозначения наличия или отсутствия значения. Основное преимущество этой новой конструкции заключается в том, что больше не требуется слишком много нулевых проверок и NullPointerException. Он избегает любой среды выполнения NullPointerExceptions и поддерживает нас в разработке чистых и аккуратных Java API или приложений. Подобно Collections и arrays, он также является Контейнером для хранения не более одного значения.
Ниже приведены полезные ссылки, по которым вы можете перейти
Вы можете создать один общий метод для объекта и строки, чтобы вы могли использовать его в своем приложении - Это может помочь вам и вашим коллегам: Создайте класс, например. StringUtilities и добавьте метод, например. getNullString
public static String getNullString(Object someobject)
{
if (null==someobject )
return null;
else if (someobject.getClass().isInstance("") &&
(((String)someobject).trim().equalsIgnoreCase("null")||
((String)someobject).trim().equalsIgnoreCase("")))
return null;
else if (someobject.getClass().isInstance(""))
return (String)someobject;
else
return someobject.toString().trim();
}
И просто назовите этот метод как,
if (StringUtilities.getNullString(someobject) != null)
{
//Do something
}
Лучший способ избежать нулевых проверок в Java - это правильно обрабатывать и использовать исключения. По моему опыту, проверки на NULL стали более распространенными и требующимися по мере того, как вы приближаетесь к интерфейсу, потому что он ближе к пользователю, который может предоставить неверную информацию через пользовательский интерфейс (например, отсутствие значения, отправляемое для поля).
Кто-то может возразить, что вы должны иметь возможность контролировать то, что делает пользовательский интерфейс, чтобы вы не забыли, что большая часть пользовательского интерфейса выполняется через какую-то стороннюю библиотеку, которая, например, может возвращать либо NULL, либо пустую строку для пустого текстового поля, в зависимости от ситуации или библиотеки.
Вы можете комбинировать их так:
try
{
myvar = get_user_supplied_value();
if (!myvar || myvar.length() == 0) { alert_the_user_somehow(); return; };
process_user_input(myvar);
} catch (Exception ex) {
handle_exception(ex);
}
Другой подход, который используют люди, - это сказать:
if (myvar && myvar.length() > 0) { };
Вы также можете создать исключение (что я предпочитаю)
if (!myvar || myvar.length() == 0) {
throw new Exception("You must supply a name!");
};
Но решать только вам.
Есть хороший способ проверить нулевое значение из JDK. Это Optional.java, в котором есть море методов для решения этих проблем. Такие как следующие: `
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
} `
`/
Вернуть {@code true}, если есть значение, иначе {@code false}. *
/ **
Очень-очень полезно помогать джаверу.
public class Null {
public static void main(String[] args) {
String str1 = null;
String str2 = "";
if (isNullOrEmpty(str1))
System.out.println("First string is null or empty.");
else
System.out.println("First string is not null or empty.");
if (isNullOrEmpty(str2))
System.out.println("Second string is null or empty.");
else
System.out.println("Second string is not null or empty.");
}
public static boolean isNullOrEmpty(String str) {
if (str != null && !str.isEmpty())
return false;
return true;
}
}
Выход
str1 is null or empty.
str2 is null or empty.
В приведенной выше программе у нас две строки str1 и str2. str1 содержит нулевое значение, а str2 - пустая строка.
Мы также создали функцию isNullOrEmpty (), которая проверяет, как следует из названия, является ли строка нулевой или пустой. Он проверяет его, используя нулевую проверку, используя метод строки! = Null и isEmpty ().
Проще говоря, если строка не является нулем, а isEmpty () возвращает false, она не является ни нулевым, ни пустым. В противном случае это так.
Однако указанная выше программа не возвращает пустое значение, если строка содержит только символы пробела (пробелы). Технически isEmpty () видит, что он содержит пробелы, и возвращает false. Для строки с пробелами мы используем строковый метод trim (), чтобы вырезать все начальные и конечные символы пробелов.
@Shervin Поощрение нулей делает код менее понятным и менее надежным.