Вопрос: Избегание! = Null


я использую object != nullмного, чтобы избежать NullPointerException,

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

Например:

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

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

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


3507


источник


Ответы:


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

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

  1. Если null - действительный ответ в терминах контракта; а также

  2. Если это недействительный ответ.

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

assert <condition>

или

assert <condition> : <object>

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

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

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

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

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

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

public interface Action {
  void doSomething();
}

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

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

Альтернативное решение - никогда не возвращать null и вместо этого использовать Образец нулевого объекта :

public class MyParser implements Parser {
  private static Action DO_NOTHING = new Action() {
    public void doSomething() { /* do nothing */ }
  };

  public Action findAction(String userInput) {
    // ...
    if ( /* we can't find any actions */ ) {
      return DO_NOTHING;
    }
  }
}

Для сравнения:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}

в

ParserFactory.getParser().findAction(someInput).doSomething();

что намного лучше, потому что это приводит к более сжатому коду.

Тем не менее, возможно, вполне применимо, чтобы метод findAction () выдавал исключение со значимым сообщением об ошибке - особенно в этом случае, когда вы полагаетесь на ввод пользователя. Было бы намного лучше, если метод findAction выбрал исключение, чем для вызывающего метода, чтобы взорвать простое исключение NullPointerException без объяснения причин.

try {
    ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
    userConsole.err(anfe.getMessage());
}

Или, если вы считаете, что механизм try / catch слишком уродлив, а не Do Nothing, ваше действие по умолчанию должно обеспечивать обратную связь с пользователем.

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

2367



Если вы используете (или планируете использовать) 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 аннотации ,


508



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

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

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 && ...».

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


282



Wow, I almost hate to add another answer when we have 57 different ways to recommend the NullObject pattern, but I think that some people interested in this question may like to know that there is a proposal on the table for Java 7 to add "null-safe handling"—a streamlined syntax for if-not-equal-null logic.

The example given by Alex Miller looks like this:

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

The ?. means only de-reference the left identifier if it is not null, otherwise evaluate the remainder of the expression as null. Some people, like Java Posse member Dick Wall and the voters at Devoxx really love this proposal, but there is opposition too, on the grounds that it will actually encourage more use of null as a sentinel value.


Update: An official proposal for a null-safe operator in Java 7 has been submitted under Project Coin. The syntax is a little different than the example above, but it's the same notion.


Update: The null-safe operator proposal didn't make it into Project Coin. So, you won't be seeing this syntax in Java 7.


213



If undefined values are not permitted:

You might configure your IDE to warn you about potential null dereferencing. E.g. in Eclipse, see Preferences > Java > Compiler > Errors/Warnings/Null analysis.

If undefined values are permitted:

If you want to define a new API where undefined values make sense, use the Option Pattern (may be familiar from functional languages). It has the following advantages:

  • It is stated explicitly in the API whether an input or output exists or not.
  • The compiler forces you to handle the "undefined" case.
  • Option is a monad, so there is no need for verbose null checking, just use map/foreach/getOrElse or a similar combinator to safely use the value (example).

Java 8 has a built-in Optional class (recommended); for earlier versions, there are library alternatives, for example Guava's Optional or FunctionalJava's Option. But like many functional-style patterns, using Option in Java (even 8) results in quite some boilerplate, which you can reduce using a less verbose JVM language, e.g. Scala or Xtend.

If you have to deal with an API which might return nulls, you can't do much in Java. Xtend and Groovy have the Elvis operator ?: and the null-safe dereference operator ?., but note that this returns null in case of a null reference, so it just "defers" the proper handling of null.


176



Only for this situation -

Not checking if a variable is null before invoking an equals method (a string compare example below):

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

will result in a NullPointerException if foo doesn't exist.

You can avoid that if you compare your Strings like this:

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

157



With Java 8 comes the new java.util.Optional class that arguably solves some of the problem. One can at least say that it improves the readability of the code, and in the case of public APIs make the API's contract clearer to the client developer.

They work like that:

An optional object for a given type (Fruit) is created as the return type of a method. It can be empty or contain a Fruit object:

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

Now look at this code where we search a list of Fruit (fruits) for a given Fruit instance:

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

You can use the map() operator to perform a computation on--or extract a value from--an optional object. orElse() lets you provide a fallback for missing values.

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

Of course, the check for null/empty value is still necessary, but at least the developer is conscious that the value might be empty and the risk of forgetting to check is limited.

In an API built from scratch using Optional whenever a return value might be empty, and returning a plain object only when it cannot be null (convention), the client code might abandon null checks on simple object return values...

Of course Optional could also be used as a method argument, perhaps a better way to indicate optional arguments than 5 or 10 overloading methods in some cases.

Optional offers other convenient methods, such as orElse that allow the use of a default value, and ifPresent that works with lambda expressions.

I invite you to read this article (my main source for writing this answer) in which the NullPointerException (and in general null pointer) problematic as well as the (partial) solution brought by Optional are well explained: Java Optional Objects.


132



Depending on what kind of objects you are checking you may be able to use some of the classes in the apache commons such as: apache commons lang and apache commons collections

Example:

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

or (depending on what you need to check):

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

The StringUtils class is only one of many; there are quite a few good classes in the commons that do null safe manipulation.

Here follows an example of how you can use null vallidation in JAVA when you include apache library(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);
}

And if you are using Spring, Spring also has the same functionality in its package, see library(spring-2.4.6.jar)

Example on how to use this static classf from spring(org.springframework.util.Assert)

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

113



  • If you consider an object should not be null (or it is a bug) use an assert.
  • If your method doesn't accept null params say it in the javadoc and use an assert.

You have to check for object != null only if you want to handle the case where the object may be null...

There is a proposal to add new annotations in Java7 to help with null / notnull params: http://tech.puredanger.com/java7/#jsr308


87