== java Избегание! = Null




15 Answers

Если вы используете (или планируете использовать) Java IDE, например JetBrains IntelliJ IDEA , Eclipse или 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 аннотации .

object == null java

Я использую object != null чтобы избежать NullPointerException .

Есть ли хорошая альтернатива этому?

Например:

if (someobject != null) {
    someobject.doCalc();
}

Это позволяет избежать NullPointerException , когда неизвестно, является ли объект null или нет.

Обратите внимание, что принятый ответ может быть устаревшим, см. https://.com/a/2386013/12943 для более позднего подхода.




Вау, я почти не хочу добавлять еще один ответ, когда у нас есть 57 различных способов рекомендовать NullObject pattern , но я думаю, что некоторым людям, заинтересованным в этом вопросе, может понравиться знать, что в таблице для Java 7 есть предложение добавить «null -safe handling " - упрощенное синтаксис для логики if-not-equal-null.

Пример, данный Алексом Миллером, выглядит следующим образом:

public String getPostcode(Person person) {  
  return person?.getAddress()?.getPostcode();  
}  

?. означает только отмену ссылки на левый идентификатор, если он не является нулевым, иначе оценивайте остальную часть выражения как null . Некоторые люди, такие как член Джона Поссе Дик Уолл и избиратели из Devoxx, действительно любят это предложение, но есть и оппозиция, потому что это на самом деле будет способствовать более широкому использованию null в качестве дозорной ценности.

Обновление: proposed для оператора с нулевой безопасностью в Java 7 было представлено в Project Coin. Синтаксис немного отличается от приведенного выше примера, но это одно и то же понятие.

Обновление. Предложение с нулевым безопасным оператором не попало в проектную монету. Таким образом, вы не увидите этот синтаксис в Java 7.




Только для этой ситуации -

Не проверять, имеет ли переменная значение null перед вызовом метода equals (пример сравнения строк ниже):

if ( foo.equals("bar") ) {
 // ...
}

приведет к NullPointerException если foo не существует.

Вы можете избежать этого, если сравнить String s следующим образом:

if ( "bar".equals(foo) ) {
 // ...
}



В зависимости от того, какие объекты вы проверяете, вы можете использовать некоторые из классов в сообществах apache, таких как: apache commons lang и коллекции коллекций apache

Пример:

String foo;
...
if( StringUtils.isBlank( foo ) ) {
   ///do something
}

или (в зависимости от того, что вам нужно проверить):

String foo;
...
if( StringUtils.isEmpty( foo ) ) {
   ///do something
}

Класс StringUtils является лишь одним из многих; есть довольно много хороших классов в достояниях, которые делают нулевую безопасную манипуляцию.

Ниже приведен пример того, как вы можете использовать null vallidation в 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)

Пример использования этого static classf из Spring (org.springframework.util.Assert)

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");



Я поклонник кода «fail fast». Спросите себя: вы делаете что-то полезное в случае, когда параметр равен нулю? Если у вас нет четкого ответа на то, что должен делать ваш код в этом случае ... То есть он никогда не должен быть нулевым, а затем игнорировать его и разрешать бросать NullPointerException. Вызывающий код будет иметь такое же значение NPE, как и исключение IllegalArgumentException, но разработчику будет легче отлаживать и понимать, что пошло не так, если NPE выбрано, а не ваш код, пытающийся выполнить некоторые другие непредвиденные непредвиденные обстоятельства логики, что в конечном итоге приводит к тому, что приложение все равно не работает.




Иногда у вас есть методы, которые работают с параметрами, которые определяют симметричную операцию:

a.f(b); <-> b.f(a);

Если вы знаете, что b никогда не может быть нулевым, вы можете просто поменять его. Это наиболее полезно для равных: вместо foo.equals("bar"); лучше делать "bar".equals(foo); ,




Java 7 имеет новый класс утилиты java.util.Objects для которого существует метод requireNonNull() .Все это делает throw, NullPointerExceptionесли его аргумент равен null, но он немного очищает код. Пример:

Objects.requireNonNull(someObject);
someObject.doCalc();

Этот метод наиболее полезен для checking непосредственно перед назначением в конструкторе, где каждое его использование может сохранять три строки кода:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

становится

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}



В конечном счете, единственный способ полностью решить эту проблему - использовать другой язык программирования:

  • В Objective-C вы можете сделать эквивалент вызова метода nil, и абсолютно ничего не произойдет. Это делает ненужными проверки большинства нулей, но это может сделать ошибки намного сложнее диагностировать.
  • В Nice , языке Java, существует две версии всех типов: потенциально-нулевая версия и непустая версия. Вы можете использовать методы только для непустых типов. Потенциально-нулевые типы могут быть преобразованы в непустые типы через явную проверку для null. Это значительно облегчает понимание того, где нужны нулевые проверки, а где нет.



Задавая этот вопрос, вы можете быть заинтересованы в стратегиях обработки ошибок. Архитектор вашей команды должен решить, как работать с ошибками. Есть несколько способов сделать это:

  1. позволяют Исключениям пульсировать через - поймать их в «основном цикле» или в какой-то другой управляющей процедуре.

    • проверьте условия ошибок и соответствующим образом обработайте их

Конечно, посмотрите также на Aspect Oriented Programming, у них есть опрятные способы вставки if( o == null ) handleNull()в ваш байт-код.




Просто никогда не используйте 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, вам нужно как-то понять.




Это очень распространенная проблема для каждого разработчика Java. Таким образом, в Java 8 есть официальная поддержка для решения этих проблем без загроможденного кода.

Java 8 представила java.util.Optional<T>. Это контейнер, который может содержать или не содержать ненулевое значение. Java 8 предоставил более безопасный способ обработки объекта, значение которого может быть нулевым в некоторых случаях. Это вдохновлено идеями Haskell и Scala .

В двух словах класс Option включает методы для явного рассмотрения случаев, когда значение присутствует или отсутствует. Однако преимущество по сравнению с нулевыми ссылками заключается в том, что необязательный класс <T> заставляет вас думать о случае, когда значение отсутствует. Как следствие, вы можете предотвратить непреднамеренные исключения нулевого указателя.

В приведенном выше примере у нас есть фабрика домашних услуг, которая возвращает дескриптор нескольких устройств, доступных в доме. Но эти услуги могут быть или не быть доступными / функциональными; это означает, что это может привести к исключению NullPointerException. Вместо того, чтобы добавлять нулевое ifусловие перед использованием какой-либо службы, давайте обернем ее в Необязательный <Сервис>.

ОБРАЩЕНИЕ К ОПЦИИ <T>

Рассмотрим способ получения справки о сервисе с завода. Вместо того, чтобы возвращать служебную ссылку, оберните ее опцией. Он позволяет пользователю API знать, что возвращенная услуга может быть или не быть доступной / функциональной, использовать защитно

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

Как вы видите, Optional.ofNullable()это простой способ получить ссылку. Есть еще один способ получить ссылку Необязательный, либо Optional.empty()& Optional.of(). Один для возврата пустого объекта вместо того, чтобы перенастраивать нуль, а другой - для обертывания объекта, не подлежащего обнулению, соответственно.

ТАК КАК ЭТО ТОГО, ЧТОБЫ ИЗБЕЖАТЬ НУЛЬНОЙ ПРОВЕРКИ?

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

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

Необязательный.ifPresent вызывает данный потребитель со ссылкой, если он является ненулевым значением. В противном случае он ничего не делает.

@FunctionalInterface
public interface Consumer<T>

Представляет операцию, которая принимает один входной аргумент и не возвращает результат. В отличие от большинства других функциональных интерфейсов, потребитель, как ожидается, будет работать через побочные эффекты. Это так чисто и легко понять. В приведенном выше примере кода HomeService.switchOn(Service)вызывается, если ссылка необязательного удержания не равна нулю.

Мы используем тернарный оператор очень часто для проверки нулевого условия и возврата альтернативного значения или значения по умолчанию. Опция предоставляет другой способ обработки одного и того же условия без проверки нулевого значения. Необязательный.orElse (defaultObj) возвращает defaultObj, если опция имеет нулевое значение. Давайте используем это в нашем примере кода:

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 check-free code ... Действительно? ,




Я пробовал, NullObjectPatternно для меня не всегда лучший способ. Иногда бывает, когда «никакое действие» не подходит.

NullPointerExceptionэто исключение Runtime, которое означает, что это ошибки разработчиков и с достаточным опытом он сообщает вам, где именно ошибка.

Теперь ответ:

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

Конечно, опыт - лучший способ понять и применить это предложение.

Байт!




Могу ли я ответить на это в более общем плане!

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

Таким образом, нет никакой разницы между:

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 или использовать более сложные библиотеки, такие как Hibernate Validator .

Просто образец:

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;

   // ...
}



  1. Никогда не инициализируйте переменные равными нулю.
  2. Если (1) невозможно, инициализируйте все коллекции и массивы пустым коллекциям / массивам.

Выполняйте это в своем собственном коде, и вы можете избежать! = 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.




public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}



Related