Java: как проверить, является ли объект нулевым?

87

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

При попытке выполнить следующие строки:

Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
if (drawable.equals(null)) {
  drawable = getRandomDrawable();
}

Строка if (drawable.equals (null)) выдает исключение, если drawable равно null.

Кто-нибудь знает, как следует проверять значение drawable, чтобы не генерировать исключение, если оно равно нулю, и получить локальное изображение (выполнить drawable = getRandomDrawable ())?

Нико Гамулин
источник
23
Используйте if (drawable == null) Вызов любого метода для объекта NULL - это исключение NullPointerException.
diciu 09
3
Почему бы тебе не написать обычный ответ вместо комментария, diciu?
deamon
@JaredBurrows Не редактируйте код вопроса таким образом, чтобы это противоречило цели вопроса!
Жиль 'SO- перестань быть злом'
@Gilles Прочтите мой редакторский комментарий, я сделал код более читабельным.
Джаред Берроуз
@JaredBurrows Нет, ваше редактирование не было изменением «форматирования». Вы изменили нерабочий код, о котором шла речь, на рабочий код, что сделало вопрос спорным.
Жиль 'SO- перестань быть злым'

Ответы:

35

Отредактированное решение Java 8:

final Drawable drawable = 
    Optional.ofNullable(Common.getDrawableFromUrl(this, product.getMapPath()))
        .orElseGet(() -> getRandomDrawable());

Вы можете заявить drawable finalв этом случае.

Как отметил Часмо, Android на данный момент не поддерживает Java 8. Так что это решение возможно только в другом контексте.

Deamon
источник
7
Вероятно, это не лучшая идея - вы возвращаетесь к Fortran 60, где оцениваются обе стороны условного выражения, а затем используется только одна. Это плохо, если неиспользуемая ветвь имеет какое-либо вычисление, что в большинстве случаев верно, поэтому обычно это бесполезный метод. Я бы переместил условие в Commonкласс и позволил бы вам указать резервный URL-адрес, сохранив обязанности вместе.
Пит Киркхэм,
1
Пример теперь полностью переписан на Java 8, поэтому мое решение больше не страдает от бесполезных оценок (как указал @PeteKirkham в моем исходном решении).
deamon
1
Android не поддерживает Java 8. Он поддерживает только Java 7 (если у вас есть kitkat), и все же в нем нет invokedynamic, только новый синтаксический сахар. Кроме того, Optional.ofподразумевается, что значение не равно нулю, и поэтому в нем нет orElseGetнеобходимости. Вы должны использовать Optional.ofNullableв этом случае.
Мартин Зеелер
180
Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
if (drawable == null) {
    drawable = getRandomDrawable();
}

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

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

Томас
источник
56
Я хочу добавить очень ценный совет: если у вас есть строки или константы для сравнения, всегда помещайте их первыми в предложение equals. (if ("coyote" .equals (myDogString))) намного лучше, чем (if (myDogString.equals ("coyote"))), потому что во втором случае myDogString может иметь значение null и выдает NPE, а в первом случае - нет не имеет значения, если myDogString имеет значение null.
Thorsten S.
21
Известное как условие Йоды: «если койот, собака ...»
Томас
1
Я также хотел бы добавить, что начиная с Java 7 существует метод Objects.equals (), который позволяет вам не заботиться о синтаксисе Yoda
maryokhin
21

Я использую такой подход:

if (null == drawable) {
  //do stuff
} else {
  //other things
}

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

Что касается того, почему вы не можете вызвать .equals()объект, который может быть null; если ссылка на объект у вас есть (а именно «рисуем») является на самом деле null, это не указывает на объект в куче. Это означает, что в куче нет объекта, вызов которого мог бы equals()быть успешным.

Удачи!

вне кофе
источник
4
Я тоже предпочитаю конструкцию if (<constant> == <variable>) как способ защитить себя от случайного присвоения.
Скотт,
8

Сделай сам

private boolean isNull(Object obj) {
    return obj == null;
}

Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
if (isNull(drawable)) {
    drawable = getRandomDrawable();
}
Эдди Б.
источник
6
drawable.equals(null)

Вышеупомянутая строка вызывает метод «equals (...)» для рисованного объекта.

Итак, когда drawable не равно null и это реальный объект, тогда все идет хорошо, так как вызов метода equals (null) вернет false

Но когда «drawable» имеет значение null, это означает вызов метода «equals (...)» для нулевого объекта, означает вызов метода для объекта, который не существует, поэтому он вызывает «NullPointerException»

Чтобы проверить, существует ли объект и не является ли он нулевым, используйте следующее

if(drawable == null) {
    ...
    ...
}

В приведенном выше условии мы проверяем, что ссылочная переменная "drawable" имеет значение NULL или содержит некоторое значение (ссылку на ее объект), поэтому она не будет генерировать исключение в случае, если значение drawable равно NULL, как проверка

null == null

является действительным.

Ятендра Гоэль
источник
5

if (yourObject instanceof yourClassName)оценим, falseесли yourObjectесть null.

heapuser
источник
0

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

Мистеру
источник
1
Где решение двойной проверки if x == null?
deamon
После оператора if среда выполнения снова проверяет наличие нулевого указателя при использовании объекта. Однако я не знаю, оптимизировано ли это компилятором.
Tom R
4
Это противоречит общепринятому мнению, когда в качестве потока управления используются исключения.
Джеймс
1
Исключения очень дороги, так как они требуют создания всей трассировки стека.
deamon
0

Используйте библиотеки google guava для обработки is-null-check (обновление deamon)

Drawable drawable = Optional.of(Common.getDrawableFromUrl(this, product.getMapPath())).or(getRandomDrawable());
Бала
источник
Лучше используйте Java 8 Optionalсегодня.
deamon
-1

Просто чтобы дать некоторые идеи разработчику исходного кода Oracle Java :-)

Решение уже существует в .Net и более читабельно!

В Visual Basic .Net

Drawable drawable 
    = If(Common.getDrawableFromUrl(this, product.getMapPath())
        ,getRandomDrawable()
        )

В C #

Drawable drawable 
    = Common.getDrawableFromUrl(this, product.getMapPath() 
        ?? getRandomDrawable();

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

Чтобы быстро увидеть разницу с решением Java, я добавил 2 решения Java.

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

Drawable drawable = 
    Optional.ofNullable(Common.getDrawableFromUrl(this, product.getMapPath()))
        .orElseGet(() -> getRandomDrawable());

Использование {} в Java

Drawable drawable = Common.getDrawableFromUrl(this, product.getMapPath());
if (drawable != null)
    {
    drawable = getRandomDrawable();
    }

Лично мне нравится VB.Net, но я предпочитаю ?? C#или if {}решение на Java ... а вы?

Schlebe
источник