объект == null или null == объект?

97

Я слышал от кого-то, что null == objectлучше, чем object == null проверить

например:

void m1(Object obj ) {
   if(null == obj)  // Is this better than object == null ? Why ?
       return ;
   // Else blah blah
}

Есть ли причины или это очередной миф? Спасибо за помощь.

Джиджой
источник
Dupe от 271561 и 1957836 (за исключением того, что здесь написано «на Яве»)
Гишу,
20
Java отличается от C #
Jijoy 03
5
Если бы было значительное преимущество в производительности, то компилятор наверняка его оптимизировал бы ...
Андреас Долк
Для nullсправок курс действий по умолчанию должен заключаться в выдаче NPE. В некоторых хороших библиотеках (например, в Java-библиотеке JDK7) есть метод вроде public static <T> T notNull(T obj) { if (obj == null) { throw new NullPointerException(); } else { return obj; } }. Также есть @NonNull(или @Nonnull?), Но это «стирается».
Том Хотин - tackline
2
null == objectизвестен как состояние Йоды .
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

Ответы:

140

Вероятно, это привычка, полученная от C, чтобы избежать такой опечатки (одиночной =вместо двойной ==):

if (object = null) {

Соглашение о помещении константы в левой части ==не очень полезно в Java, поскольку Java требует, чтобы выражение в ifоценке оценивалось как booleanзначение, поэтому, если константа не является a boolean, вы получите ошибку компиляции в любом случае, если вы поместите аргументы. (и если это логическое значение, вам ==все равно не следует использовать ...)

Лоуренс Гонсалвес
источник
4
что не очень полезно для java, поскольку опечатка приведет к ошибке компиляции на java
radai
11
За исключением особых случаев. stackoverflow.com/questions/2369226/null-check-in-java/…
Chandra Sekar
3
@Chandru для логического значения, вы можете использовать x.booleanValue()или !x.booleanValue(). x == trueили x == falseв выражении состояния - это неприятный запах, ИМХО.
Лоуренс Гонсалвес,
2
Здесь он проверяет наличие null. И бывают случаи, когда ему действительно нужно проверить логическое значение на null, поскольку null не является ни истинным, ни ложным.
Чандра Секар,
1
Привыкание использовать null == objectтолько для того, чтобы убедиться, что мы случайно не перезаписываем объект с опечаткой, вообще не должно быть прецедентом. Это означает, что мы обучаем себя тому, что теперь, когда я сначала использую «null», все в порядке, даже если я сделаю ошибку. Это не означает, что код работает должным образом. Даже если null = objectуказано вместо null == object, программа не будет работать должным образом! Тогда нет смысла следовать этому условию!
VanagaS
33

Как говорили другие, это привычка, которую выучили у C, избегать опечаток - хотя даже в C я ожидал бы, что достойные компиляторы при достаточно высоких уровнях предупреждений выдадут предупреждение. Как говорит Чандру, сравнение с null в Java таким способом вызовет проблемы только в том случае, если вы используете переменную типа Boolean(которой нет в примере кода). Я бы сказал, что это довольно редкая ситуация, и не та, для которой стоит менять способ написания кода в любом другом месте. (Я бы не стал обращать внимание на операнды даже в этом случае; если я достаточно ясно мыслю, чтобы рассмотреть возможность их изменения, я уверен, что могу посчитать знаки равенства.)

Что не было упомянуто, так это то, что многие люди (в том числе и я, конечно) находят if (variable == constant)форму более читаемой - это более естественный способ самовыражения. Это причина не копировать слепо соглашение из C. Вы всегда должны подвергать сомнению практики (как вы делаете здесь :), прежде чем предполагать, что то, что может быть полезно в одной среде, полезно в другой.

Джон Скит
источник
3
Я согласен с каждым вашим словом, особенно с частью "слепо копировать соглашение". Я читаю код прямо сейчас, и стиль null = object меня так раздражает, что я нашел его и пришел сюда. О чем думал кодер?
Adrian M
28

В Java (1.5+) это не имеет особого значения, за исключением случаев, когда объект имеет тип Boolean. В таком случае это все еще может пригодиться.

if (object = null)не вызовет сбоя компиляции в Java 1.5+, если объект есть, Booleanно вызовет ошибку во NullPointerExceptionвремя выполнения.

Чандра Секар
источник
Вы, вероятно, имели в виду, что это приведет к сбою компиляции :)
vava
7
Нет, это не вызовет ошибку компиляции, если объект является логическим.
Chandra Sekar
Разве это не одно и то же для всех типов объектов, кроме Boolean?
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
2
Для не-логических типов код не будет компилироваться, потому что тип выражения «объект = null» не будет логическим. Из-за автобокса он будет компилироваться для Boolean.
Чандра Секар
Но почему такое поведение для Boolean? Любое объяснение?
Рохит Банга
9

В Java нет веской причины.

В нескольких других ответах утверждалось, что это потому, что вы можете случайно назначить его вместо равенства. Но в Java у вас должно быть логическое значение в if, поэтому это:

if (o = null)

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

Единственный раз, когда это может иметь значение в Java, - это если переменная является логической:

int m1(boolean x)
{
    if (x = true)  // oops, assignment instead of equality
R Самуэль Клатчко
источник
4
Но зачем тебе вообще писать == trueили равно == true == true.
Том Хотин - tackline
7
Нет веской причины писать == true. Но за свою карьеру я видел столько плохого кода, что больше не спрашиваю, зачем кто-то что-то пишет, и просто принимаю тот факт, что некоторые люди написали ненужный / сомнительный код.
R Samuel Klatchko
1
В самом деле, вокруг много плохого кода, но, если рассматривать его x == trueкак плохой, потому что он может быть ошибочно написан x = true, не было бы большого смысла менять его на true == xвместо просто x.
Holger
9

Это также тесно связано с:

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

что удобно, если вы не хотите иметь дело с NPE:

if (bar!=null && bar.equals("foo")) {
херувим
источник
может быть удобно, но может быть опасно blue-walrus.com/2010/11/…
Оливер Уоткинс
@OliverWatkins: Я считаю эту статью слабой. Предположим, что переменная имеет тип int. Если оставить неинициализированным, значение будет 0, и обещание статьи не будет выполнено. Тот факт, что строки являются объектами, а целые числа являются примитивами, не имеет отношения к тому факту, что программист может забыть инициализировать переменную. В этом вопросе мы просто решаем проблему сравнения нулевых строк.
cherouvim
@cherouvim тот факт, что intэто примитивный тип, имеет значение, так как его невозможно вызвать equalsв int, следовательно, нет смысла обсуждать, использовать x.equals(constant)или constant.equals(x)для intзначений. А для Integerзначений значение по умолчанию - это, nullа не 0.
Holger
5

Этот трюк призван предотвратить v = nullопечатки.

Но Java допускает только логические выражения в качестве if()условий, так что этот трюк не имеет особого смысла, компилятор все равно обнаружит эти опечатки.

Тем не менее, это по-прежнему ценный трюк для кода C / C ++.

вава
источник
3

По той же причине, по которой вы делаете это в C; присваивание - это выражение, поэтому вы помещаете литерал слева, чтобы его нельзя было перезаписать, если вы случайно используете =вместо ==.

Игнасио Васкес-Абрамс
источник
Но это проблема Java только для логических типов, верно? Любой другой тип присваивания не будет иметь логического типа и должен вызвать ошибку компилятора.
Скотт Смит
1
нет, компилятор Java поймает такую ​​опечатку в любом порядке, который вы предпочитаете
vava
@Jijoy - Я не думаю, что это имеет какое-то отношение к производительности. Это звучит как старый трюк C, позволяющий избежать ужасной ошибки «присваивание в условном выражении». Идея заключалась в том, что если вы пытаетесь проверить, xравно ли 5при ошибочном вводе if (x = 5), он будет компилироваться незаметно (и всегда будет вычисляться true, независимо от значения x). Однако, если вы приобретете привычку всегда указывать сначала литерал: 'if (5 = x)', компилятор может перепроверить вашу работу и сэкономить ваше время в отладчике. Современные компиляторы избавляют от этой привычки.
Скотт Смит
6
-1: если вы случайно используете =, он не будет компилироваться в Java; поэтому причина из C не применима.
Джон Скит,
Технически, если он objбыл типа java.lang.Boolean(большой B), то это могло иметь значение (я думаю, на самом деле не пробовал или что-то в этом роде).
Том Хотин - tackline
3

Это для людей, которые предпочитают, чтобы константа была слева. В большинстве случаев наличие константы в левой части предотвратит выброс исключения NullPointerException (или другой нулевой контроль). Например, метод String также выполняет нулевую проверку. Наличие константы слева не даст вам выписать дополнительный чек. Что, по-другому, тоже выполняется позже. Наличие нулевого значения слева - это просто согласованность.

лайк:

 String b = null;
 "constant".equals(b);  // result to false
 b.equals("constant");  // NullPointerException
 b != null && b.equals("constant");  // result to false
SPee
источник
это сокрытие NPE только усложняет поиск ошибок ниже по течению
Оливер Уоткинс,
2

Это условие Йоды, написанное по-другому

В Java

String myString = null;
if (myString.equals("foobar")) { /* ... */ } //Will give u null pointer

состояние йода

String myString = null;
if ("foobar".equals(myString)) { /* ... */ } // will be false 
Танмай Найк
источник
1

Сравните со следующим кодом:

    String pingResult = "asd";
    long s = System.nanoTime ( );
    if ( null != pingResult )
    {
        System.out.println ( "null != pingResult" );
    }
    long e = System.nanoTime ( );
    System.out.println ( e - s );

    long s1 = System.nanoTime ( );
    if ( pingResult != null )
    {
        System.out.println ( "pingResult != null" );
    }
    long e1 = System.nanoTime ( );
    System.out.println ( e1 - s1 );

Вывод (после многократного выполнения):

null != pingResult
325737
pingResult != null
47027

Следовательно, pingResult != nullэто победитель.

Авинаш
источник
7
Запустите тест в дополнительном цикле! Или просто переключите операторы IF. Короче говоря: разницы нет! Первый цикл всегда медленнее.
Marcel Jaeschke
В этом тесте pingResult всегда не равен нулю. Что происходит со временем, когда pingResult равен нулю? Я уверен, что он независим от платформы, но в моем стеке Oracle Java 1.6 / Linux результаты в значительной степени равны (в цикле), за исключением случая, когда pingResult имеет значение null, обе проверки выполняются на несколько процентов быстрее.
Ogre Psalm33
1
если вы поместите блок «pingResult! = null перед блоком null! = pingResult, это приведет к чему-то вроде« pingResult! = null 325737 »
Сола Ян
Как говорит @Sola Yang, если вы поставите pingResult! = Null перед этим, вы увидите, что это займет больше времени, чем null! = PingResult. Если pingResult! = Null был быстрее, чем null! = PingResult, IDE (например, IntelliG, Eclipse, ...) выдаст предупреждение, чтобы заставить разработчиков использовать эту роль;)
adil.hilmi
1

Из-за его коммутативности единственное различие между object == nullи null == object( версия Йоды ) носит когнитивный характер : как код читается и усваивается читателем. Я не знаю окончательного ответа, но знаю, что лично предпочитаю сравнивать проверяемый мной объект с чем-то другим, а не сравнивать что-то еще с объектом, который я проверяю , если это имеет смысл. Начните с предмета, а затем значения, с которым его нужно сравнить.

В некоторых других языках этот стиль сравнения более полезен.

Однако, чтобы обезопасить себя от отсутствия знака «=» в целом, я считаю, что написание null == objectявляется ошибочным актом защитного программирования . Лучший способ обойти этот конкретный код - гарантировать поведение с помощью теста junit. Помните, что возможная ошибка отсутствия знака "=" не зависит от входных аргументов метода - вы не зависите от правильного использования этого API другими людьми - поэтому тест junit идеально подходит для защиты от этого. В любом случае вы захотите написать тесты junit для проверки поведения; отсутствующий знак "=" естественно попадает в область действия.

Бенни Боттема
источник