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
Використовуйте, якщо (drawable == null) Виклик будь-якого методу для NULL-об'єкта є NullPointerException.
diciu

3
Чому б вам не написати звичайну відповідь замість коментаря, diciu?
Дімон

@JaredBurrows Не редагуйте код у питанні таким чином, щоб переконати мету питання!
Жиль 'ТАК - перестань бути злим'

@Gilles Прочитайте мій редакторський коментар, я зробив код більш читабельним.
Джаред Берроуз,

@JaredBurrows Ні, ваша редакція не змінила "форматування". Ви змінили неробочий код, який був об’єктом питання, на робочий код, який змусив питання спірним.
Жиль 'ТАК - перестань бути злим'

Відповіді:


35

Відредаговане рішення Java 8:

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

Ви можете заявити drawable finalв цьому випадку.

Як зазначив Часмо, Android наразі не підтримує Java 8. Отже, це рішення можливе лише в інших контекстах.


7
Можливо, це не гарна ідея - ви повертаєтесь до Fortran 60, де оцінюються обидві сторони умовного, тоді звикає лише одна. Це погано, якщо невикористана гілка має будь-які обчислення, що є справжнім у більшості випадків, тому це, як правило, не корисний метод. Я б перемістив умову до Commonкласу і дозволив би вам вказати резервну URL-адресу, а також взяти на себе обов'язки.
Піт Кіркхем,

1
Тепер приклад повністю переписаний в Java 8, тому моє рішення вже не страждає від марних оцінок (як @PeteKirkham зазначив у моєму оригінальному рішенні).
Дімон

1
Android не підтримує Java 8. Він підтримує лише до Java 7 (якщо у вас є kitkat), і все-таки він не має викликаної динаміки, лише новий синтаксисний цукор. Крім цього, Optional.ofмається на увазі, що значення не є нульовим, а отже, orElseGetє непотрібним. Ви повинні використовувати Optional.ofNullableв цьому випадку.
Мартін Сілер

179
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 може бути нульовим і видаватиме NPE, тоді як у першому випадку це не робить Не має значення, якщо myDogString має значення null.
Торстен С.

20
Відомий як стан йоди: "якщо койот, собака ..."
Томас

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)

У наведеному вище рядку викликається метод "дорівнює (...)" для об'єкта, що малюється.

Отже, коли drawable не має значення null і є реальним об’єктом, тоді все йде добре, оскільки виклик методу «equals (null)» поверне «false»

Але коли "drawable" має значення null, це означає виклик методу "equals (...)" для нульового об'єкта, означає виклик методу для об'єкта, який не існує, тому він видає "NullPointerException"

Щоб перевірити, чи існує об’єкт і чи не є він нульовим, використовуйте наступне

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

У вищевказаному стані ми перевіряємо, що посилальна змінна "drawable" є нульовою або містить якесь значення (посилання на її об'єкт), тому вона не буде видавати виняток, якщо drawable є нульовим як перевірка

null == null

є дійсним.



0

Можливо, трохи ефективніше ловити NullPointerException. Вищезазначені методи означають, що час виконання двічі перевіряє наявність нульових покажчиків.


1
Де рішення для подвійної реєстрації if x == null?
Дімон

Після оператора if середовище виконання знову перевірить наявність нульового покажчика, коли використовується об'єкт. Однак я не знаю, оптимізовано це компілятором чи ні.
Tom R

4
Це суперечить загальноприйнятій думці, використовуючи винятки як контрольний потік.
Джеймс,

1
Винятки дуже дорогі, оскільки їм потрібно створити цілий стек.
Дімон

0

Використовуйте google guava libs для обробки is-null-check (оновлення deamon)

Drawable drawable = Optional.of(Common.getDrawableFromUrl(this, product.getMapPath())).or(getRandomDrawable());

Краще використовувати Java 8 Optionalсьогодні.
Дімон

-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

Використання додаткового в 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 ... а вам?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.