Як використовувати null в комутаторі


202
Integer i = ...

switch (i){
    case null:
        doSomething0();
        break;    
    }

У наведеному вище коді я не можу використовувати null у заяві випадку перемикача. Як я можу це зробити інакше? Я не можу використовувати, defaultтому що тоді я хочу зробити щось інше.


9
перед тим, як перевірити переключення на нульовий стан, якщо (i == null) {// dosomething}
Nagaraju Badaeni

8
Це фактично зробить комутатор корисним. Інші мови відповідності шаблону працюють таким чином.
Піролістичний

Відповіді:


276

Це неможливо із switchзаявою на Java. Перевірте nullперед switch:

if (i == null) {
    doSomething0();
} else {
    switch (i) {
    case 1:
        // ...
        break;
    }
}

Ви не можете використовувати довільні об’єкти в switchоператорах * . Причина , по якій компілятор не скаржиться , switch (i)де iце Integerвідбувається тому , що Java автоматично unboxes IntegerАнь int. Як вже говорив Ассілій, розпакування буде кидати NullPointerExceptionколи iє null.

* З Java 7 ви можете використовувати Stringв switchоператорах.

Більше про switch(включаючи приклад із нульовою змінною) в Oracle Docs - Switch


16
Ви також можете використовувати переписки в операторах переключення.
joriki

27
Має сенс, що ви не можете використовувати нульовий Integer чи інший клас Wrapper через розпакування. А як щодо переліків і струн? Чому вони не можуть бути недійсними?
Луан Ніко

9
Я не розумію, чому коротке замикання нуля, відображене у випадку "за замовчуванням", або спеціальний випадок для нульового вимикача не було реалізовано для Strings. Це робить використання перемикачів для спрощення коду безглуздим, оскільки завжди потрібно робити нульову перевірку. Я не кажу, що спрощення є єдиним використанням для комутаторів.
Рейміус,

3
@Reimius вам не завжди доведеться робити нульову перевірку. Якщо ви поважаєте кодові контракти, які ви надаєте своїм методам, ви майже завжди можете управляти таким чином, щоб ваш код не був захаращений нульовими чеками. Однак використання тверджень завжди приємно.
Джоффрі

Я також хотів би дізнатися відповідь на запит @ LuanNico. Це здається нерозумним , що nullне може бути дійсним випадком при роботі з Stringі enumтипів. Можливо, enumреалізація покладається на виклик ordinal()за кадром (хоча навіть так, чому б не трактувати nullяк «порядковий» -1?), А Stringверсія робить щось із використанням intern()та порівнянням вказівників (або іншим чином покладається на те, що суворо вимагає перенаправлення об’єкт)?
1616

98
switch ((i != null) ? i : DEFAULT_VALUE) {
        //...
}

чистіший спосіб, ніж використання однієї додаткової, якщо іншої
Vivek Agrawal

40

switch(i)викине NullPointerException, якщо я є null, тому що він спробує розпакувати папку Integerв int. Тож case null, що трапляється незаконно, ніколи б не було досягнуто.

Вам потрібно перевірити, що я не є нульовим перед switchвипискою.


23

Документи Java чітко сказали, що:

Заборона використовувати null як мітку перемикання перешкоджає написанню коду, який ніколи не може бути виконаний. Якщо вираз перемикання має опорний тип, наприклад, примітизований тип в коробці або перерахунок, виникає помилка під час виконання, якщо вираз оцінюється на нуль під час виконання.

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

if (i == null)

Див. Запис переключення

case null: // will never be executed, therefore disallowed.

1
Javadocs у вашому посиланні більше не кажуть "Заборона використовувати null як мітку перемикача [тощо]".
Патрік М


14

Подано:

public enum PersonType {
    COOL_GUY(1),
    JERK(2);

    private final int typeId;
    private PersonType(int typeId) {
        this.typeId = typeId;
    }

    public final int getTypeId() {
        return typeId;
    }

    public static PersonType findByTypeId(int typeId) {
        for (PersonType type : values()) {
            if (type.typeId == typeId) {
                return type;
            }
        }
        return null;
    }
}

Для мене це, як правило, співпадає з таблицею огляду в базі даних (лише для рідко оновлюваних таблиць).

Однак, коли я намагаюся використовувати findByTypeIdв операторі комутатора (з, швидше за все, введення користувача) ...

int userInput = 3;
PersonType personType = PersonType.findByTypeId(userInput);
switch(personType) {
case COOL_GUY:
    // Do things only a cool guy would do.
    break;
case JERK:
    // Push back. Don't enable him.
    break;
default:
    // I don't know or care what to do with this mess.
}

... як інші заявили, це призводить до створення NPE @ switch(personType) {. Один обхід (тобто "рішення"), який я почав впроваджувати, - це додати UNKNOWN(-1)тип.

public enum PersonType {
    UNKNOWN(-1),
    COOL_GUY(1),
    JERK(2);
    ...
    public static PersonType findByTypeId(int id) {
        ...
        return UNKNOWN;
    }
}

Тепер вам не доведеться робити нульову перевірку, куди вона зараховується, і ви можете обрати чи не обробляти UNKNOWNтипи. (ПРИМІТКА: -1це малоймовірний ідентифікатор у бізнес-сценарії, але, очевидно, вибирайте щось, що має сенс для вашого використання).


2
UNKNOWNє найкращим рішенням у цьому, що я коли-небудь бачив, і переборювати нульові перевірки.
члени звуку

5

Ви повинні зробити

if (i == null) {
   doSomething0();
} else {
   switch (i) {
   }
}

4

Деякі бібліотеки намагаються запропонувати альтернативи вбудованому switchоператору Java . Вавр - один із них, вони узагальнюють його для узгодження моделей.

Ось приклад з їх документації :

String s = Match(i).of(
    Case($(1), "one"),
    Case($(2), "two"),
    Case($(), "?")
);

Ви можете використовувати будь-який присудок, але вони пропонують багато з них поза вікном, і $(null)це абсолютно законно. Я вважаю це більш елегантним рішенням, ніж альтернативи, але для цього потрібні java8 та залежність від бібліотеки vavr ...




0

Ви не можете. Ви можете використовувати примітиві (int, char, short, byte) та String (String in java 7 only) в комутаторі. примітиви не можуть бути нульовими. Перед перемиканням
перевірте iокремий стан.


4
Ви також можете використовувати переліки.
Кару

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

1
Застереження @LeonardoKenji за замовчуванням насправді не має нічого спільного з null; все, що ви вмикаєте, буде скасовано, щоб перевірити будь-які інші випадки, тому за замовчуванням пункт не обробляє нульовий випадок (NullPointerException буде викинуто до того, як у нього з’явиться шанс).
Бен-

2
Я думаю, що він мав на увазі, що за замовчуванням застереження має обробити нуль, як будь-яке інше можливе значення перерахунку, яке не було схоплено попереднім випадком
Лев

0

Подумайте, як може працювати SWITCH,

  • у випадку примітивів ми знаємо, що це може вийти з ладу NPE для автоматичного боксу
  • але для String або enum це може бути виклик методу рівних, який, очевидно, потребує значення LHS, на яке викликається рівне. Отже, з огляду на те, що жоден метод не може бути застосований до нуля, перемикач не може обробляти null.

0

На основі відповіді @tetsuo, з java 8:

Integer i = ...

switch (Optional.ofNullable(i).orElse(DEFAULT_VALUE)) {
    case DEFAULT_VALUE:
        doDefault();
        break;    
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.