Перевірка нуля Java, навіщо використовувати == замість .equals ()


125

У Java мені кажуть, що при проведенні нульової перевірки слід використовувати == замість .equals (). Які причини цього?


12
Найпростіше - спробувати перевірити нуль equals()і побачити. Коли ви спробуєте, це миттєво стане очевидним
Горан Йович

До речі, пошук у Google із ключовими словами "ява нульова перевірка" (без лапок) дав мені один із найкращих звернень до цієї теми , який має ту саму інформацію, що й відповіді тут.
Мітч Шварц

Відповіді:


179

Це дві абсолютно різні речі. ==порівнює посилання на об'єкт, якщо він є, що міститься змінною. .equals()перевіряє, чи два об'єкти рівні відповідно до їх договору, що означає рівність. Цілком можливо, що два окремі екземпляри об'єкта будуть "рівними" відповідно до їх договору. І тут є незначна деталь, що оскільки equalsце метод, якщо ви спробуєте викликати його за nullпосиланням, ви отримаєте NullPointerException.

Наприклад:

class Foo {
    private int data;

    Foo(int d) {
        this.data = d;
    }

    @Override
    public boolean equals(Object other) {
        if (other == null || other.getClass() != this.getClass()) {
           return false;
        }
        return ((Foo)other).data == this.data;
    }

    /* In a real class, you'd override `hashCode` here as well */
}

Foo f1 = new Foo(5);
Foo f2 = new Foo(5);
System.out.println(f1 == f2);
// outputs false, they're distinct object instances

System.out.println(f1.equals(f2));
// outputs true, they're "equal" according to their definition

Foo f3 = null;
System.out.println(f3 == null);
// outputs true, `f3` doesn't have any object reference assigned to it

System.out.println(f3.equals(null));
// Throws a NullPointerException, you can't dereference `f3`, it doesn't refer to anything

System.out.println(f1.equals(f3));
// Outputs false, since `f1` is a valid instance but `f3` is null,
// so one of the first checks inside the `Foo#equals` method will
// disallow the equality because it sees that `other` == null

ти маєш на увазі public int data?
Черга Jé

@Xepoch: Ні, я взагалі не створюю публічні поля (хоча це не дуже важливо і для цього прикладу). Чому?
TJ Crowder

@TJ Crowder "Це дві абсолютно різні речі .." взагалі так. Однак реалізація обох за замовчуванням однакова, якщо я розумію правильно. Переглядаючи вихідний код, .equals () в основному робить перевірку ==. hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip/src/share/classes / ...
Ayush

1
@Ayush - це за замовчуванням Object, так. Однак це перекрито великою кількістю класів JDK. Але справа не в реалізації, а в семантиці. (Бічна примітка: JDK7 дуже застаріла.)
TJ Crowder

Правильно, це має сенс, просто хотілося уточнити.
Айюш

38

якщо ви викликаєте .equals()на nullви отримаєтеNullPointerException

Тому завжди бажано перевірити недійсність перед викликом методу там, де він застосовується

if(str!=null && str.equals("hi")){
 //str contains hi
}  

Також Див


34
Ваш приклад, як правило, краще писати як if ("hi".equals(str)).
ColinD

3
@ user368186: справа не в тому, що метод рівних включає нульову перевірку. Якщо ваша посилання на об'єкт є нульовою, тоді виклик someObject.equals(null)підніме a, NullPointerExceptionне вводячи метод рівних.
Дейв Коста

2
@ColinD Погоджуюсь лише демонструвати тут
Jigar Joshi

2
Завжди доцільно уникати нулів за будь-яку ціну, тому нульові перевірки вам взагалі не потрібні;).
fwielstra

2
Ви завжди можете використовувати Objects.equals(a, b)це не підвищить NullPointerException, але це все ще залежить від методу "рівності" "а" та "б"
Домінік Мінк

29

Окрім прийнятої відповіді ( https://stackoverflow.com/a/4501084/6276704 ):

Оскільки Java 1.7, якщо ви хочете порівняти два об'єкти, які можуть бути нульовими, я рекомендую цю функцію:

Objects.equals(onePossibleNull, twoPossibleNull)

java.util.Objects

Цей клас складається з статичних корисних методів для роботи з об'єктами. Ці утиліти включають безпечні або нулестійкі методи обчислення хеш-коду об'єкта, повернення рядка для об'єкта та порівняння двох об'єктів.

З моменту: 1.7


2
Просто, щоб зробити його більш помітним для інших (див. Відповідь chin90 або JavaDoc ): Objects.equals(null, null)повернеться true- майте це на увазі.
Томас

20

У Java 0 або null - це прості типи, а не об'єкти.

Метод equals () не побудований для простих типів. Прості типи можна зіставити з ==.


4
піднести фактичну відповідь, яка є найбільш корисною на відміну від очевидної відповіді герпе дерп.
волк


3

Якщо змінна Object є null, не можна викликати на ній метод equals (), тому перевірка довідки об'єкта null є правильною.


2

Якщо ви спробуєте викликати рівний за нульовою посиланням на об'єкт, то ви отримаєте викинуте виключення нульового вказівника.


2

За джерелами, не має значення, що використовувати для впровадження методу за замовчуванням:

public boolean equals(Object object) {
    return this == object;
}

Але ви не можете бути впевнені equalsв користувацькому класі.


Це має значення, оскільки equalsможе повернути falseабо викликати NullPointerException(або щось інше, якщо equalsметод переосмислення - це нісенітниця).
Том

2

Якщо ми використовуємо метод => .equals

if(obj.equals(null))  

// Which mean null.equals(null) when obj will be null.

Коли ваш obj буде нульовим, він викине Null Point Exception.

тому ми повинні використовувати ==

if(obj == null)

вона порівняє посилання.


2

Object.equals є безпечним для нуля, проте майте на увазі, що якщо два об’єкти є null, object.equals поверне значення true, тому обов'язково переконайтеся, що об'єкти, які ви порівнюєте, не є null (або утримуйте null значення), перш ніж використовувати object.equals для порівняння.

String firstname = null;
String lastname = null;

if(Objects.equals(firstname, lastname)){
    System.out.println("equal!");
} else {
    System.out.println("not equal!");
}

Приклад фрагмента вище буде повернутись рівним!


Як зазначає JavaDoc (це завжди розумно читати): Consequently, if both arguments are null, true is returned. ...:)
Томас

1

Оскільки рівним є функція, похідна від класу Object, ця функція порівнює елементи класу. якщо ви використовуєте його з null, він поверне помилкову причину, оскільки вміст класу не є нульовим. Крім того, == порівнює посилання на об'єкт.


Ну, результат може бути тільки falseабо NullPointerException(якщо equalsНЕ перевизначений на що - то погане).
Том

1

ось приклад, де, str != nullале str.equals(null)при використанніorg.json

 JSONObject jsonObj = new JSONObject("{field :null}");
 Object field = jsonObj.get("field");
 System.out.println(field != null);        // => true
 System.out.println( field.equals(null)); //=> true
 System.out.println( field.getClass());  // => org.json.JSONObject$Null




EDIT: ось клас org.json.JSONObject $ Null :

/**
 * JSONObject.NULL is equivalent to the value that JavaScript calls null,
 * whilst Java's null is equivalent to the value that JavaScript calls
 * undefined.
 */
private static final class Null {

    /**
     * A Null object is equal to the null value and to itself.
     *
     * @param object
     *            An object to test for nullness.
     * @return true if the object parameter is the JSONObject.NULL object or
     *         null.
     */
    @Override
    public boolean equals(Object object) {
        return object == null || object == this;
    }  
}

Проблема тут полягає в тому, що field.equals(null)повертається правда. Це порушує звичайну поведінку Java і тому заплутано. Це повинно працювати лише field.equals("null")принаймні з моєї точки зору. Я не знаю, чому розробники бібліотек думали, що це було б добре підтримати.
Том

До речі, у вашому першому реченні є граматика, і незрозуміло, що ви маєте на увазі під цим. Ви маєте на увазі "Ось приклад, куди str != nullі str.equals(null)повернутися trueпри використанні org.json ."?
Том

Я думаю, що це тому, що jsonObjectмістить клавішу "поле", тому fieldвона не є нульовою, вона має посилання, яке містить json.org.JSONObject$Null об'єкт
Діна

Так, але я б не ставився Nullдо цього, nullа використовував би "null"натомість. Але я думаю, що вони зробили це, щоб уникнути необхідності струн. Але навіть з цією лібкою field.equals(null)все ще майже завжди виникає проблема: P.
Том

0

Тому я ніколи не плутаюсь і не уникаю проблем з цим рішенням:

if(str.trim().length() <=0 ) {
   // is null !
}

5
Якщо str є недійсним, це буде NPE
typoerrpr

Крім того, порожня рядок ( ""довжина 0) - це щось зовсім інше, ніж nullпосилання (тобто немає рядка).
Томас

0

Я зіткнувся з цим випадком минулої ночі.
Я визначаю, що просто це:

Не існує методу equals () для null
Отже, ви не можете використовувати неіснуючий метод, якщо у вас його немає
- >>> Ось чому ми використовуємо == для перевірки null


0

У вас код порушує закон Деметра. Ось чому краще переробляти саму конструкцію. Як вирішення, ви можете використовувати Необов’язково

   obj = Optional.ofNullable(object1)
    .map(o -> o.getIdObject11())
    .map(o -> o.getIdObject111())
    .map(o -> o.getDescription())
    .orElse("")

вище - це перевірити ієрархію об'єкта, щоб просто використовувати

Optional.ofNullable(object1) 

якщо у вас є лише один об’єкт для перевірки

Сподіваюся, це допомагає !!!!


-3

Ви завжди могли це зробити

if (str == null || str.equals(null))

Це спочатку перевірить посилання на об'єкт, а потім перевірить сам об’єкт, надаючи посилання isnt null.


if (str == null || str.equals (null) || str.equals (""))
Лу Морда

я використав вашу відповідь і додав чек на порожню рядок! якщо я не помиляюся, "null" та "" - це не те саме.
Лу Морда

4
Не зовсім зайвим є додавання 2-ої перевірки на null?
Джастін Роу

2
@JustinRowe Це не тільки надмірно, але й дуже помиляється. Будь ласка, ніколи не роби щось подібне x.equals(null).
Том

@Tom, JustinRowe, будь ласка, дивіться мою відповідь вище, чому це не є зайвим і не є повним сміттям stackoverflow.com/questions/4501061/…
dina
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.