Вопрос

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

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

Например:

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

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

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

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

Решение

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

Другими словами, есть два случая, когда возникает проверка null:

  1. Где null - допустимый ответ с точки зрения контракта;и

  2. Там, где это неверный ответ.

(2) это просто.Либо использовать assert утверждения) или допускают сбой (например, Исключение NullPointerException).Утверждения - это крайне недоиспользуемая функция 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);
        }
    }
}

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

Если вы используете (или планируете использовать) Java IDE, например ИДЕЯ JetBrains IntelliJ, Затмение или Netbeans - сетевые приложения или такой инструмент, как findbugs, тогда вы можете использовать аннотации для решения этой проблемы.

По сути, у вас есть @Nullable и @NotNull.

Вы можете использовать in метод и параметры, например, так:

@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.

Если нулевые значения недопустимы

Если ваш метод вызывается извне, начните с чего-то вроде этого:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

Затем, в остальной части этого метода, вы узнаете, что object не является нулевым.

Если это внутренний метод (не часть API), просто задокументируйте, что он не может быть нулевым, и все.

Пример:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

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

Если разрешено значение null

Это действительно зависит от обстоятельств.Если обнаружите, что я часто делаю что-то подобное:

if (object == null) {
  // something
} else {
  // something else
}

Итак, я разветвляюсь и делаю две совершенно разные вещи.Здесь нет уродливого фрагмента кода, потому что мне действительно нужно сделать две разные вещи в зависимости от данных.Например, должен ли я работать с входными данными или мне следует вычислить хорошее значение по умолчанию?


На самом деле я редко использую эту идиому " .if (object != null && ...".

Возможно, вам будет проще привести примеры, если вы покажете примеры того, где вы обычно используете эту идиому.

Ух, я почти не хочу добавлять другой ответ, когда у нас есть 57 различных способов рекомендовать NullObject pattern, но я думаю, что некоторым людям, интересующимся этим вопросом, может быть интересно узнать, что на столе есть предложение для Java 7 добавить " нулевую безопасную обработку " & # 8212; упрощенный синтаксис для логики if-not-equal-null.

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

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

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

<Ч>

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

<Ч>

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

Если не разрешены неопределенные значения:

Вы можете настроить свою IDE таким образом, чтобы она предупреждала вас о возможном разыменовании null.Например.в Eclipse смотрите Настройки > Java > Компилятор > Ошибки / Предупреждения / Анализ нулевых значений.

Если разрешены неопределенные значения:

Если вы хотите определить новый API, в котором неопределенные значения имеют смысл, используйте Шаблон опции (может быть знаком из функциональных языков).Он обладает следующими преимуществами:

  • В API явно указано, существует ли вход или вывод или нет.
  • Компилятор заставляет вас обрабатывать случай "undefined".
  • Опция - это монада, поэтому нет необходимости в подробной проверке нуля, просто используйте map /foreach /getOrElse или аналогичный комбинатор для безопасного использования значения (пример).

Java 8 имеет встроенный Optional класс (рекомендуемый);для более ранних версий существуют альтернативные библиотеки, например Гуава's Optional или Функциональная Джава's Option.Но, как и во многих шаблонах функционального стиля, использование Option в Java (даже 8) приводит к довольно большому шаблону, который вы можете уменьшить, используя менее подробный язык JVM, напримерScala или Xtend.

Если вам приходится иметь дело с API, который может возвращать нули, вы мало что можете сделать на Java.Xtend и Groovy обладают Оператор Элвиса ?: и тот оператор разыменования, защищенный от нуля ?., но обратите внимание, что это возвращает null в случае нулевой ссылки, поэтому это просто "откладывает" правильную обработку null .

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

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

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

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

Этого можно избежать, сравнив свои String с такими словами:

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

В Java 8 появился новый класс java.util.Optional, который, возможно, решает некоторые проблемы. Можно, по крайней мере, сказать, что это улучшает читабельность кода, а в случае открытых API-интерфейсов делает контракт API-интерфейса более понятным для разработчика клиента.

Они работают так:

Необязательный объект для данного типа (Fruit) создается как тип возврата метода. Он может быть пустым или содержать объект fruits:

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();
}

Теперь посмотрите на этот код, где мы ищем список map() (orElse()) для данного экземпляра Fruit:

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

Вы можете использовать оператор Optional для вычисления или извлечения значения из необязательного объекта. null позволяет предоставить запасной вариант для пропущенных значений.

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

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

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

Конечно, NullPointerException можно также использовать в качестве аргумента метода, возможно, лучший способ указать необязательные аргументы, чем 5 или 10 методов перегрузки в некоторых случаях.

<=> предлагает другие удобные методы, такие как <=>, которые позволяют использовать значение по умолчанию, и <=>, который работает с лямбда-выражения .

Я предлагаю вам прочитать эту статью (мой основной источник для написания этого ответа), в которой хорошо объяснены проблемная проблема <=> (и вообще нулевой указатель), а также (частичное) решение, приведенное <=>: Необязательные объекты Java .

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

Пример:

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)

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

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");
  • Если вы считаете, что объект не должен быть нулевым (или это ошибка), используйте assert.
  • Если ваш метод не принимает нулевые параметры, скажите это в javadoc и используйте assert.

Вы должны проверять наличие object != null только в том случае, если вы хотите обработать случай, когда объект может быть null...

Есть предложение добавить новые аннотации в Java7, чтобы помочь с параметрами null / notnull:http://tech.puredanger.com/java7/#jsr308

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

Каркас коллекций 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();

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

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

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

Вместо шаблона нулевого объекта - который имеет свои применения - вы можете рассмотреть ситуации, когда нулевой объект является ошибкой.

Когда выдается исключение, изучите трассировку стека и устраните ошибку.

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

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");
}

Null - это не "проблема".Это неотъемлемая часть полный набор инструментов для моделирования.Программное обеспечение нацелено на моделирование сложности мира, и null несет его бремя. Значение Null указывает на "Отсутствие данных" или "Неизвестно". на Java и тому подобном.Поэтому для этих целей целесообразно использовать значения null.Я не предпочитаю шаблон "Нулевой объект";Я думаю, что это поднимет 'кто будет охранять хранители- проблема.
Если вы спросите меня, как зовут мою девушку, я скажу вам, что у меня нет девушки.На языке Java я верну значение null.Альтернативой было бы создать значимое исключение, чтобы указать на какую-то проблему, которая не может быть (или не хочет быть) решена прямо там, и делегировать ее где-нибудь выше в стеке, чтобы повторить попытку или сообщить пользователю об ошибке доступа к данным.

  1. На "неизвестный вопрос" дайте "неизвестный ответ". (Будьте безопасны с нулевым значением, если это правильно с точки зрения бизнеса) Проверка аргументов на значение null один раз внутри метода перед использованием освобождает нескольких вызывающих пользователей от проверки их перед вызовом.

    public Photo getPhotoOfThePerson(Person person) {
        if (person == null)
            return null;
        // Grabbing some resources or intensive calculation
        // using person object anyhow.
    }
    

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

    getPhotoOfThePerson(me.getGirlfriend())
    

    И это соответствует новому Java API (с нетерпением жду).

    getPhotoByName(me.getGirlfriend()?.getName())
    

    Хотя это довольно "нормальный бизнес-процесс" - не находить фотографию, сохраненную в базе данных для какого-то человека, я использовал пары, подобные приведенным ниже, для некоторых других случаев

    public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException
    public static MyEnum parseMyEnumOrNull(String value);
    

    И не испытывайте отвращения к печатанию <alt> + <shift> + <j> (сгенерируйте javadoc в Eclipse) и напишите три дополнительных слова для вашего публичного API.Этого будет более чем достаточно для всех, кроме тех, кто не читает документацию.

    /**
     * @return photo or null
     */
    

    или

    /**
     * @return photo, never null
     */
    
  2. Это скорее теоретический случай, и в большинстве случаев вам следует предпочесть java null safe API (на случай, если он будет выпущен еще через 10 лет), но NullPointerException является подклассом Exception. Таким образом, это форма Throwable это указывает на условия, которые разумное приложение, возможно, захочет выполнить (Javadoc)!Использовать первое по преимуществу преимущество исключений и отделить код обработки ошибок от "обычного" кода (по словам создателей Java) уместно, как по мне, уловить NullPointerException.

    public Photo getGirlfriendPhoto() {
        try {
            return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
        } catch (NullPointerException e) {
            return null;
        }
    }
    

    Могут возникнуть вопросы:

    Q.Что , если getPhotoDataSource() возвращает значение null?
    A.Это зависит от бизнес-логики.Если мне не удастся найти фотоальбом, я не покажу вам никаких фотографий.Что делать, если AppContext не инициализирован?Бизнес-логика этого метода допускает это.Если та же логика должна быть более строгой, то создание исключения является частью бизнес-логики, и следует использовать явную проверку на null (случай 3).Тот Самый новый Java Null-safe API лучше подходит здесь, чтобы выборочно указывать, что подразумевает, а что не подразумевает инициализацию быстро отказывать в случае ошибок программиста.

    Q.Может быть выполнен избыточный код и захвачены ненужные ресурсы.
    A.Это могло бы произойти, если бы getPhotoByName() попытался бы открыть соединение с базой данных, создать PreparedStatement и, наконец, используйте имя пользователя в качестве параметра SQL.Подход на неизвестный вопрос дается неизвестный ответ (случай 1) работает здесь.Перед захватом ресурсов метод должен проверить параметры и при необходимости вернуть "неизвестный" результат.

    Q.Такой подход приводит к снижению производительности из-за открытия try closure.
    A.Во-первых, программное обеспечение должно быть простым для понимания и модификации.Только после этого можно было думать о производительности, и только при необходимости!и там, где нужно!(Источник), и многие другие).

    PS.Этот подход будет столь же разумным в использовании, как и отделите код обработки ошибок от "обычного" кода принцип разумен для использования в каком-то месте.Рассмотрим следующий пример:

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }
    

    ППС.Для тех, кто быстро отклоняет запрос (и не так быстро читает документацию) Я хотел бы сказать, что я никогда в жизни не ловил исключение с нулевым указателем (NPE).Но такая возможность была намеренно спроектированный создателями Java, потому что NPE является подклассом Exception.У нас есть прецедент в истории Java, когда ThreadDeath является Error не потому, что это на самом деле ошибка приложения, а исключительно потому, что она не предназначалась для обнаружения!Насколько NPE подходит для того, чтобы быть Error чем ThreadDeath!Но это не так.

  3. Проверяйте наличие "Нет данных" только в том случае, если это подразумевает бизнес-логика.

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }
    

    и

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }
    

    Если AppContext или DataSource не инициализированы, необработанное исключение NullPointerException во время выполнения завершит текущий поток и будет обработано Поток.defaultUncaughtExceptionHandler (чтобы вы могли определить и использовать свой любимый регистратор или другой механизм уведомления).Если не установлено, ThreadGroup#Неперехваченное исключение выведет stacktrace на системную ошибку.Следует отслеживать журнал ошибок приложения и открывать Jira issue для каждого необработанного исключения, которое на самом деле является ошибкой приложения.Программист должен исправить ошибку где-то в процессе инициализации.

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

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

Общее " проблема " действительно в Java.

Сначала мои мысли по этому поводу:

Я считаю, что "!" есть "!" что-то, когда NULL был передан, где NULL не является допустимым значением. Если вы не выходите из метода с какой-либо ошибкой, это означает, что в вашем методе ничего не пошло не так, что неверно. Тогда вы, вероятно, вернете нуль в этом случае, а в методе получения вы снова проверяете на ноль, и он никогда не заканчивается, и в итоге вы получаете & Quot; if! = Null & Quot ;, и т.д ..

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

Я решил эту проблему следующим образом:

Во-первых, я следую этому соглашению:

<Ол>
  • Все открытые методы / API всегда проверяют свои аргументы на нулевое значение
  • Все приватные методы не проверяют наличие null, поскольку они являются контролируемыми методами (просто дайте умереть с исключением nullpointer, если это не было обработано выше)
  • Единственные другие методы, которые не проверяют на нулевое значение, - это служебные методы. Они общедоступны, но если вы по каким-то причинам вызываете их, вы знаете, какие параметры вы передаете. Это все равно что пытаться кипятить воду в чайнике без подачи воды ...
  • И, наконец, в коде первая строка открытого метода выглядит следующим образом:

    ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();
    

    Обратите внимание, что addParam () возвращает self, так что вы можете добавить больше параметров для проверки.

    Метод validate() выбрасывает проверенный ValidationException, если какой-либо из параметров имеет значение null (проверено или не выбрано, это скорее проблема дизайна / вкуса, но мой <=> отмечен).

    void validate() throws ValidationException;
    

    Сообщение будет содержать следующий текст, если, например, " plan " является нулевым:

    " Недопустимое значение недопустимого аргумента для параметра [планы] "

    Как вы можете видеть, второе значение в методе (строке) addParam () необходимо для пользовательского сообщения, потому что вы не можете легко определить переданное имя переменной, даже с отражением (в любом случае это не тема этого сообщения). .).

    И да, мы знаем, что за этой строкой мы больше не встретим нулевое значение, поэтому мы просто безопасно вызываем методы для этих объектов.

    Таким образом, код является чистым, простым в обслуживании и читаемым.

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

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

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

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

    В дополнение к использованию assert вы можете использовать следующее:

    if (someobject == null) {
        // Handle null here then move on.
    }
    

    Это немного лучше, чем:

    if (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, вы должны каким-то образом выяснить.

    Guava, очень полезная базовая библиотека Google, имеет приятный и полезный API, позволяющий избежать нулевых значений.Я нахожу Использование и отказ от завершения объяснены очень полезно.

    Как объяснено в вики:

    Optional<T> является способом замены обнуляемой ссылки T на ненулевое значение.Необязательный элемент может либо содержать ненулевую ссылку на T (в этом случае мы говорим, что ссылка "присутствует"), либо он может не содержать ничего (в этом случае мы говорим, что ссылка "отсутствует").Он никогда не сказал, чтобы "содержать нулевые".

    Использование:

    Optional<Integer> possible = Optional.of(5);
    possible.isPresent(); // returns true
    possible.get(); // returns 5
    

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

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

    В двух словах, в классе Optional есть методы для явного обращения со случаями, когда значение присутствует или отсутствует. Однако преимущество по сравнению с нулевыми ссылками заключается в том, что Optional & Lt; T & Gt; Класс заставляет задуматься о случае, когда значение отсутствует. Как следствие, вы можете предотвратить непреднамеренные исключения нулевого указателя.

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

    ОБРАЩЕНИЕ К ВАРИАНТУ < T >

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

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

    Как видите, Optional.ofNullable() предоставляет простой способ обернуть ссылку. Есть и другие способы получить ссылку на Optional: Optional.empty() & Amp; Optional.of(). Один для возврата пустого объекта вместо перенастройки null, а другой для переноса ненулевого объекта соответственно.

    ТАК КАК ТОЛЬКО ЭТО ПОМОГАЕТ ИЗБЕЖАТЬ ПУСТОЙ ПРОВЕРКИ?

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

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

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

    @FunctionalInterface
    public interface Consumer<T>
    

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

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

    public static Optional<HomeServices> get() {
        service = Optional.of(service.orElse(new HomeServices()));
        return service;
    }
    

    Теперь HomeServices.get () делает то же самое, но лучше. Проверяет, инициализирован ли сервис или нет. Если это так, верните то же самое или создайте новый новый сервис. Необязательный & Lt; T & Gt; .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, а также нулевой код без проверки & # 8230; В самом деле? .

    Мне нравятся статьи от Нэта Прайса.Вот ссылки:

    В статьях также ссылка на репозиторий Git для Java может быть тип, который я нахожу интересным, но я не думаю, что он в одиночку может снизить проверка раздувания кода.Проведя некоторые исследования в Интернете, я думаю != null объем кода можно было бы уменьшить в основном за счет тщательного проектирования.

    Я уже пробовал NullObjectPattern но для меня это не всегда лучший путь.Иногда бывают ситуации, когда "никаких действий" неуместно.

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

    Теперь перейдем к ответу:

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

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

    Байт!

    Вероятно, лучшая альтернатива для Java 8 или новее - использовать Optional class.

    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());
    

    Пример того, как вывести исключение на нуль:

    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();
    

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

    Мы обычно столкнитесь с этой проблемой, когда методы получают параметры не так, как мы ожидали (неправильный вызов метода - ошибка программиста).Например:вы ожидаете получить объект, вместо этого вы получаете значение 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.аннотация.NotNull или используйте более сложные библиотеки, такие как Валидатор перехода в спящий режим.

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

    getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)
    

    Теперь вы можете безопасно разрабатывать основную функцию вашего метода без необходимости проверять входные параметры, они защищают ваши методы от неожиданных параметров.

    Вы можете пойти еще дальше и убедиться, что в вашем приложении могут быть созданы только действительные pojo.(пример с сайта hibernate validator)

    public class Car {
    
       @NotNull
       private String manufacturer;
    
       @NotNull
       @Size(min = 2, max = 14)
       private String licensePlate;
    
       @Min(2)
       private int seatCount;
    
       // ...
    }
    

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

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

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

    Кроме того, я бы не рекомендовал использовать этот шаблон, когда тип предназначен для представления примитивного типа - как математические объекты, которые не являются скалярами: векторы, матрицы, комплексные числа и объекты POD (Plain Old Data), которые подразумеваются держать состояние в форме встроенных типов Java. В последнем случае вы должны вызывать методы-получатели с произвольными результатами. Например, что должен возвращать метод NullPerson.getName ()?

    Стоит рассмотреть такие случаи, чтобы избежать абсурдных результатов.

    <Ол>
  • Никогда не инициализируйте переменные нулем.
  • Если (1) невозможно, инициализируйте все коллекции и массивы пустыми коллекциями / массивами.
  • Делая это в своем собственном коде, вы можете избежать! = пустых проверок.

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

    // 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:

    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;
    }
    
    public static <T> T ifNull(T toCheck, T ifNull) {
        if (toCheck == null) {
               return ifNull;
        }
        return toCheck;
    }
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top