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.