Избегая!= null операторы

я использую object != null не NullPointerException.

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

например:

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

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

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

30 ответов


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

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

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

  2. где это недопустимый ответ.

(2) легко. Либо используйте assert утверждения (утверждения) или разрешить сбой (например, NullPointerException). Утверждения-это сильно недоиспользуемая функция Java, которая была добавлена в 1.4. Синтаксис:

assert <condition>

или

assert <condition> : <object>

где <condition> является логическим выражением и <object> является объектом,toString() вывод метода будет включен в ошибку.

An assert заявление, выдает Error (AssertionError) если условие неверно. По умолчанию Java игнорирует утверждения. Вы можете включить утверждения, передав опцию -ea к JVM. Можно включать и отключать утверждения для отдельных классов и пакетов. Это означает, что вы можете проверять код с помощью утверждений при разработке и тестирование и отключение их в рабочей среде, хотя мое тестирование показало, что утверждения практически не влияют на производительность.

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

(1) немного сложнее. Если у вас нет контроля над кодом, который вы вызываете, вы застряли. Если null является допустимым ответом,вы должны проверить его.

если это код, который вы контролируете, однако (и это часто бывает), то это другая история. Избегайте использования нулей в качестве ответа. С методами, которые возвращают коллекции, это легко: возвращайте пустые коллекции (или массивы) вместо нулей почти все время.

С non-коллекциями это может быть сложнее. Рассмотрим это в качестве примера: если у вас есть эти интерфейсы:

public interface Action {
  void doSomething();
}

public interface Parser {
  Action findAction(String userInput);
}

где парсер принимает ввод пользователя и находит что-то делать, возможно, если вы реализуете интерфейс командной строки для чего-то. Теперь вы можете сделать контракт, который он возвращает null, если нет соответствующего действия. Это приводит к нулевой проверке, о которой вы говорите.

альтернативным решением является никогда не возвращать 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();
}

to

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 идея, 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 скажет вам, что проверка бесполезна, так как


если null-значения не допускаются

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

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

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

если это внутренний метод (не часть 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 добавить "null-безопасная обработка"-оптимизированный синтаксис для логики if-not-equal-null.

пример, приведенный Алексом Миллером выглядит так:

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

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


обновление: An официальное предложение для оператора null-safe в Java 7 был отправлен под Проект Монету. синтаксис-это немного отличается от приведенного выше примера, но это то же самое понятие.


обновление: предложение оператора null-safe не вошло в проект Coin. Таким образом, вы не увидите этот синтаксис в Java 7.


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

вы можете настроить IDE, чтобы предупредить вас о потенциальном разыменовании null. Е. Г. в Eclipse, см. настройки > Java > компилятор > ошибки / предупреждения / нулевой анализ.

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

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

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

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

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


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

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

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

в результате NullPointerException Если foo не существует.

вы можете избежать этого, если вы сравните ваш StringS, как это:

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

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

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

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


в зависимости от того, какие объекты вы проверяете, Вы можете использовать некоторые классы в Apache commons, такие как: 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 также имеет ту же функциональность в своем пакете, см. library (spring-2.4.6.jar)

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

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

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

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

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


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


Google collections framework предлагает хороший и элегантный способ достижения нулевой проверки.

в классе библиотеки есть такой метод:

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 никогда не может быть null, вы можете просто поменять его. Это наиболее полезно для равных: Вместо foo.equals("bar"); лучше сделать "bar".equals(foo);.


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

при возникновении исключения проверьте трассировку стека и выполните работу с ошибкой.


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 object"; я думаю, что он поднимает "кто будет охранять стражи!-Проблемы -25-->'.
Если вы спросите меня, как зовут мою девушку Я скажу тебе, что у меня нет девушки. На языке Java я верну null. Альтернативой было бы создать значимое исключение, чтобы указать на некоторую проблему, которая не может быть (или не хочет быть) решена прямо там, и делегировать ее где-то выше в стеке, чтобы повторить попытку или сообщить об ошибке доступа к данным пользователю.

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

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

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

    getPhotoOfThePerson(me.getGirlfriend())
    

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

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

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

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

    и не люблю тип <alt> + <shift> + <j> (создайте javadoc в Eclipse) и напишите три дополнительных слова для вас public 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;
        }
    }
    

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

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

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

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

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

    PPS. Для тех, кто быстро downvote (и не так быстро читать документацию), я хотел бы сказать, что я никогда не ловил исключение нулевого указателя (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 не инициализирован необработанный runtime NullPointerException убьет текущий поток и будет обработан нить.defaultUncaughtExceptionHandler (для вас, чтобы определить и использовать ваш любимый регистратор или другой механизм оповещения). Если не установлено, ThreadGroup#uncaughtException будет печатать stacktrace в системе err. Следует отслеживать журнал ошибок приложений и открывать проблему Jira для каждого необработанного исключения, которое на самом деле является ошибкой приложения. Программист должен исправить ошибку где-то в материале инициализации.


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

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

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

во-первых, мои мысли на это:

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

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

как мне решить эту проблему так:

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

  1. все открытые методы / API всегда проверяют свои аргументы на null
  2. все частные методы не проверяют значение null, поскольку они являются управляемыми методами (просто позвольте умереть с исключением nullpointer в случае, если он не был обработан выше)
  3. единственными другими методами, которые не проверяют значение null, являются методы утилиты. Они общедоступны, но если вы по какой-то причине их называете, вы знаете, какие параметры вы проходите. Это как пытаться вскипятить воду в чайнике без воды...

и, наконец, в коде первая строка открытого метода выглядит так:

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

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

способ validate() будет бросать checked ValidationException если какой-либо из параметров равен null (checked или unchecked-это больше проблема дизайна / вкуса, но my ValidationException - Это проверено).

void validate() throws ValidationException;

сообщение будет содержать следующий текст, если, например, "plans" имеет значение null:

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

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

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

этот путь, код чист, легок ремонтопригоден и читаем.


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

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

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

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


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

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

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

if (someobject != null) {
    .....
    .....



    .....
}

просто никогда не используйте 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, чтобы избежать нулей. Я нахожу UsingAndAvoidingNullExplained очень полезная.

как описано в wiki:

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

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

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

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

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

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

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

ПЕРЕНОС В ОПЦИЮ

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

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

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

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

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

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

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

@FunctionalInterface
public interface Consumer<T>

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

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

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

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


Мне нравятся статьи от Nat Pryce. Вот ссылки:

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


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

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

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

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

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

байт!


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

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

это особенно удобно для длинных цепочек возможных значений null. Пример:

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

могу я ответить на него более широко!

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

пример:

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

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

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

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

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

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

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

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

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


  1. никогда не инициализируйте переменные в null.
  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.


Это самая распространенная ошибка большинства разработчиков.

у нас есть несколько способов справиться с этим.

подход 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;
}