object == null або null == object?


96

Я чув від когось, що null == objectкраще, ніж object == null чек

наприклад:

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

Є якісь причини чи це черговий міф? Дякуємо за допомогу.


Ошуканство 271561 та 1957836 (за винятком того, що в ньому написано "на Java")
— Гішу

20
Java відрізняється від C #
— Jijoy 03.03.10

5
Якби була суттєва перевага в продуктивності, то напевно компілятор її оптимізував би ...
— Андреас Долк

Щодо nullпосилань, за замовчуванням порядок дій повинен бути киданням NPE. Деякі приємні бібліотеки (наприклад, бібліотека JDK7 Java) мають щось на зразок методу public static <T> T notNull(T obj) { if (obj == null) { throw new NullPointerException(); } else { return obj; } }. Є також @NonNull(або @Nonnull?), Але це "стирається".
— Том Хоутін - таклін

Відповіді:


140

Це, мабуть, звичка, яку вивчив C, щоб уникнути такого типу друкарської помилки (одинарної =замість подвійної ==):

if (object = null) {

Домовленість про розміщення константи ліворуч від ==Java насправді не корисна в Java, оскільки Java вимагає, щоб вираз в ifоцінці отримав booleanзначення, тому, якщо константа не є a boolean, ви отримаєте помилку компіляції в будь-якому випадку аргументи. (а якщо це логічне значення, ви ==все одно не повинні використовувати ...)


4
що не є дуже корисною звичкою для Java, оскільки друкарська помилка призведе до помилки компіляції на Java
— radai 03.03.10

11
За винятком конкретного кутового випадку. stackoverflow.com/questions/2369226/null-check-in-java/…
— Чандра Секар

3
@Chandru для логічного значення, ви можете використовувати x.booleanValue()або !x.booleanValue(). x == trueабо x == falseу виразі стану - неприємний запах, ІМХО.
— Лоуренс Гонсалвес,

2
Тут він перевіряє наявність нуля. І бувають випадки, коли йому дійсно доводиться перевіряти логічну форму на наявність null, оскільки null не є ні true, ні false.
— Чандра Секар

1
Звикати використовувати null == objectлише для того, щоб переконатись, що ми випадково не перезапишемо об’єкт за допомогою друкарської помилки, взагалі не повинно бути випадком використання. Що означає, що ми тренуємось, що тепер, коли я спочатку використовую "null", це нормально, навіть якщо я помиляюся. Це не означає, що код працює належним чином. Навіть якщо null = objectвказано замість null == object, програма не працюватиме належним чином! Тоді немає сенсу дотримуватися цієї конвенції!
— VanagaS

32

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

Що не було згадано, так це те, що багато людей (і я, звичайно, в тому числі) вважають if (variable == constant)форму більш читабельною - це більш природний спосіб висловити себе. Це є причиною, щоб не сліпо копіювати конвенцію з C. Вам слід завжди ставити під сумнів практики (як ви робите тут :), перш ніж припускати, що те, що може бути корисним в одному середовищі, корисно в іншому.


3
Я погоджуюся на кожне ваше слово, особливо на частину "сліпого копіювання конвенції". Я зараз читаю код, і стиль null = object мене так дратує, що я шукаю його і прийшов сюди. Про що думав кодер?
— Адріан М

28

Це не має великої цінності в Java (1.5+), за винятком випадків, коли тип об'єкта Boolean. У такому випадку це все одно може стати в нагоді.

if (object = null)не спричинить збій компіляції в Java 1.5+, якщо об’єкт є, Booleanале видасть a NullPointerExceptionпід час виконання.


Ви, мабуть, мали на увазі, що це спричинить невдачу компіляції :)
— vava 03.03.10

7
Ні, це не призведе до помилки компіляції, коли об'єкт є булевим.
— Чандра Секар

Чи не однаково це для кожного типу об'єкта, крім булевого?
— Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

2
Для небулевих типів код не компілюється, оскільки тип виразу "object = null" не буде логічним. Завдяки автоматичному боксу, він буде скомпільований для Boolean.
— Chandra Sekar

Але чому така поведінка для Boolean? Будь-яке обгрунтування?
— Рохіт Банга,

9

У Java немає вагомих причин.

Кілька інших відповідей стверджували, що це тому, що ви можете випадково призначити це завдання замість рівності. Але в Java ви повинні мати логічну форму в if, отже, це:

if (o = null)

не буде компілювати.

Єдиний раз, коли це може мати значення в Java, це якщо змінна є логічною:

int m1(boolean x)
{
    if (x = true)  // oops, assignment instead of equality

4
Але чому ви коли-небудь писали == trueабо однаково == true == true.
— Том Хоутін - таклін

7
Немає вагомих причин писати == true. Але я бачив настільки поганий код у своїй кар’єрі, що більше не питаю, чому хтось щось писав, а просто приймаю, що деякі люди писали непотрібний / сумнівний код.
— R Самуель Клатчко 03.03.10

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, і обіцянка статті не буде виконуватися. Той факт, що рядки є об'єктами, а ints - примітивами, не має значення для того, що програміст може забути ініціювати змінну. У цьому питанні ми просто вирішуємо нульове порівняння рядків.
— 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; assignment - це вираз, тому ви ставите літерал ліворуч, щоб ви не могли його перезаписати, якщо випадково використаєте =замість ==.


Це проблема лише в 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), то це могло б змінити ситуацію (я думаю, насправді не намагався чи щось інше).
— Том Хоутін - таклін

3

Це для людей, які воліють мати константу з лівого боку. У більшості випадків наявність константи з лівого боку перешкоджатиме викиданню NullPointerException (або наявності іншої нульової перевірки). Наприклад, метод String дорівнює також робить також нульову перевірку. Наявність константи ліворуч не дозволить вам написати додатковий чек. Що, по-іншому, також виконується пізніше. Наявність нульового значення ліворуч просто узгоджується.

подібно до:

 String b = null;
 "constant".equals(b);  // result to false
 b.equals("constant");  // NullPointerException
 b != null && b.equals("constant");  // result to false

це приховування 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. Коротше кажучи: різниці немає! Перший цикл завжди повільніший.
— Марсель Яшке

У цьому тесті pingResult завжди не має значення null. Що відбувається з тим, що час pingResult дорівнює нулю? Я роблю ставку, що це не залежить від платформи, але на моєму стеку Oracle Java 1.6 / Linux результати є майже рівномірними (у циклі), крім випадків, коли pingResult має значення null, обидві перевірки на кілька відсотків швидші.
— Ogre Psalm33,

1
якщо ви поставите "pingResult! = null block перед null! = pingResult block, то вийде щось на зразок" pingResult! = null 325737 "
— Sola Yang

Як каже @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-тести, щоб перевірити поведінку; відсутність "=", природно, потрапляє в область дії.

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