Проверка Java null, почему использовать == вместо .equals ()

125

В Java мне говорят, что при проверке нуля следует использовать == вместо .equals (). В чем причины этого?

Джим Джеффрис
источник
12
Самый простой способ - попробовать проверить нулевое значение equals()и посмотреть. Когда вы попробуете, это сразу станет очевидно
Горан Йович
Между прочим, поиск в Google с ключевыми словами "java null check" (без кавычек) дал мне как одно из лучших совпадений в этой теме , которая содержит ту же информацию, что и ответы здесь.
Митч Шварц

Ответы:

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
TJ Crowder
источник
ты имеешь в виду public int data?
Jé Queue,
@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: дело не в том, включает ли метод equals проверку на null. Если ваша ссылка на объект имеет значение null, тогда вызов someObject.equals(null)вызовет a, NullPointerExceptionдаже не вводя метод equals.
Дэйв Коста
2
@ColinD Согласен, просто демонстрация здесь
Джигар Джоши
2
Всегда желательно любой ценой избегать нулевых значений, поэтому вам вообще не нужны нулевые проверки;).
fwielstra
2
Вы всегда можете использовать Objects.equals(a, b)Это не вызовет NullPointerException, но это все еще зависит от метода «равенства» для «a» и «b»
Доминик Минк
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 () не предназначен для простых типов. Простые типы могут быть сопоставлены с помощью ==.

user523859
источник
4
Проголосуйте за фактический ответ, который является наиболее полезным, в отличие от очевидного ответа «будет возвращено NullPointerException».
volk
4
foo.equals(null)

Что произойдет, если foo имеет значение null?

Вы получаете исключение NullPointerException.

Ник Ортон
источник
3

Если переменная Object имеет значение null, для нее нельзя вызвать метод equals (), поэтому проверка ссылки на объект на null является правильной.

Jé Queue
источник
2

Если вы попытаетесь вызвать equals для ссылки на нулевой объект, вы получите исключение с нулевым указателем.

A_M
источник
2

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

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

Но equalsв кастомном классе нельзя быть уверенным .

DixonD
источник
Это имеет значение, поскольку equalsможет только возвращать falseили вызывать NullPointerException(или что-то другое, если equalsметод переопределения не имеет смысла).
Том
2

Если мы используем метод => .equals

if(obj.equals(null))  

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

Когда ваш obj будет нулевым, он выдаст исключение нулевой точки.

поэтому мы должны использовать ==

if(obj == null)

он сравнит ссылки.

AKT
источник
2

Object.equals является нулевым безопасным, однако имейте в виду, что если два объекта имеют значение NULL, object.equals вернет true, поэтому обязательно проверьте, что сравниваемые объекты не являются нулевыми (или содержат нулевые значения), прежде чем использовать object.equals для сравнение.

String firstname = null;
String lastname = null;

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

Приведенный выше фрагмент примера вернет равенство!

chin90
источник
Как указано в JavaDoc (всегда разумно их читать): Consequently, if both arguments are null, true is returned. ...:)
Томас
1

Поскольку equal является функцией, производной от класса Object, эта функция сравнивает элементы класса. если вы используете его с null, он вернет false, потому что содержимое класса не равно null. Кроме того, == сравнивает ссылку на объект.

danny.lesnik
источник
Что ж, результат может быть только falseили NullPointerException(если equalsне переопределить что-то плохое).
Tom
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"), по крайней мере, с моей точки зрения. Не знаю, почему разработчики библиотеки подумали, что это было бы хорошо поддержать.
Tom
Кстати, в вашем первом предложении есть грамматическая проблема, и непонятно, что вы под ним имеете в виду. Вы имеете в виду «Вот пример, где str != nullи str.equals(null)вернуться trueпри использовании org.json .»?
Tom
Я думаю, это потому, что jsonObjectсодержит ключ "field", поэтому fieldон не равен null, у него есть ссылка, которая содержит json.org.JSONObject$Null объект
dina
Да, но я бы не стал относиться к Nullтакому же, nullи использовал бы "null"вместо этого. Но я думаю, они сделали это, чтобы не требовать строк. Но даже с этой Lib, field.equals(null)по - прежнему почти всегда вопрос: P.
Tom
0

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

if(str.trim().length() <=0 ) {
   // is null !
}
Матеус Маркес
источник
5
Если str имеет значение null, это будет NPE
typoerrpr 05
Кроме того, пустая строка ( ""имеющая длину 0) полностью отличается от nullссылки (т.е. без строки).
Томас
0

Я столкнулся с этим случаем вчера вечером.
Я определяю это просто так:

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

Нео_
источник
0

Ваш код нарушает закон Деметры. Поэтому лучше провести рефакторинг самой конструкции. В качестве обходного пути вы можете использовать Optional

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

выше - это проверить иерархию объекта, поэтому просто используйте

Optional.ofNullable(object1) 

если у вас есть только один объект для проверки

Надеюсь это поможет !!!!

Akitha_MJ
источник
-3

Вы всегда могли сделать

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

Это сначала проверит ссылку на объект, а затем проверит сам объект, если ссылка не равна нулю.

Кевин Оррисс
источник
if (str == null || str.equals (null) || str.equals (""))
Лу Морда
Я использовал ваш ответ и добавил проверку на пустую строку! если не ошибаюсь, null и "" - не одно и то же.
Лу Морда
4
Разве добавление второй проверки на ноль не является полностью избыточным?
Джастин Роу
2
@JustinRowe Это не только избыточно, но и очень неправильно. Пожалуйста, никогда не делай ничего подобного x.equals(null).
Том
@Tom, JustinRowe, пожалуйста, посмотрите мой ответ выше, почему это не избыточно и не полный мусор stackoverflow.com/questions/4501061/…
dina