スイッチでnullを使用する方法


202
Integer i = ...

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

上記のコードでは、switch caseステートメントでnullを使用できません。どうすればこれを別の方法で実行できますか?他のことdefaultをしたいので使えません。


9
スイッチの前にnull条件のチェックif(i == null){// dosomething}
Nagaraju Badaeni 2012

8
これにより、スイッチが実際に役立ちます。他のパターンマッチング言語はこのように機能します。
Pyrolistical 2014年

回答:


277

これはswitch、Javaのステートメントでは不可能です。のnull前に確認してくださいswitch

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

switchステートメントで任意のオブジェクトを使用することはできません*。コンパイラがswitch (i)どこにiあるかについて文句を言わない理由Integerは、Javaがへの自動アンボックスIntegerを行うためintです。assyliasは、すでに述べたように、アンボクシングがスローされますNullPointerExceptionときiですnull

* Java 7以降Stringswitchステートメントで使用できます。

Oracle Docsの詳細switch(null変数の例を含む)-スイッチ


16
enumをswitchステートメントで使用することもできます。
joriki 2013年

27
ボックス化解除のため、null Integerまたは他のWrapperクラスを使用できないことは理にかなっています。しかし、列挙型と文字列はどうですか?なぜnullにできないのですか?
Luan Nico

9
「デフォルト」の場合またはnullスイッチの特別な場合にマッピングされているnullの短絡が文字列に実装されなかった理由がわかりません。常にnullチェックを行わなければならないため、スイッチを使用してコードを単純化することは無意味です。ただし、スイッチを使用するのは単純化だけだと言っているのではありません。
Reimius 2014年

3
@Reimiusでは、常にnullチェックを行う必要はありません。メソッドに与えるコードコントラクトを尊重すると、ほとんどの場合、コードがnullチェックで乱雑にならないようにすることができます。ただし、アサートの使用は常に便利です。
ジョフリー、

@LuanNicoのクエリに対する答えも知りたいです。とタイプを操作するnull場合、これは妥当なケースではありません。おそらく、実装は舞台裏での呼び出しに依存しますが(それでも、「序数」が-1として扱われるのはなぜですか?)、バージョンはポインタ比較を使用して何かを行います(または、厳密に逆参照が必要なものに依存します)オブジェクト)?Stringenumenumordinal()nullStringintern()
2016


40

switch(i)私の場合はNullPointerExceptionがスローされますnull、それはVHS版しようとするので、Integerint。したがってcase null、たまたま違法であり、とにかく到達することはなかっただろう。

switchステートメントの前に、iがnullではないことを確認する必要があります。


23

Javaのドキュメントでは、次のように明確に述べられています。

スイッチラベルとしてnullを使用することの禁止により、実行できないコードを作成できなくなります。スイッチ式がボックス化されたプリミティブ型や列挙型などの参照型である場合、式が実行時にnullと評価されると、実行時エラーが発生します。

Swithchステートメントを実行する前にnullを確認する必要があります。

if (i == null)

Switchステートメントを参照してください

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

1
リンク先のjavadocは、「nullをスイッチラベルとして使用することの禁止[など]」と表示しなくなりました。
Patrick M


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(おそらくユーザー入力からの)switchステートメントで使用しようとすると...

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) {ます。私が実装し始めた1つの回避策(つまり、「ソリューション」)は、UNKNOWN(-1)型を追加することでした。

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

これで、カウントする場所でnullチェックを行う必要がなくなり、UNKNOWN型を処理するかどうかを選択できます。(注:-1ビジネスシナリオではありそうもない識別子ですが、明らかにユースケースに適したものを選択してください)。


2
UNKNOWNこれは私がこれまでに見た中で最高の解決策であり、nullchecksを克服します。
membersound

5

あなたは作る必要があります

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

4

一部のライブラリは、組み込みのjava switchステートメントに代わるものを提供しようとします。Vavrはその1つであり、パターンマッチングに一般化されています。

ドキュメントの例を以下に示します

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

任意の述語を使用できますが、それらの多くはそのまま使用でき、$(null)完全に合法です。これは他の方法よりもエレガントな解決策ですが、これにはjava8とvavrライブラリへの依存関係が必要です...



2
switch (String.valueOf(value)){
    case "null":
    default: 
}

0

できません。プリミティブ(int、char、short、byte)とString(Java 7の文字列のみ)をスイッチで使用できます。プリミティブをnullにすることはできません。スイッチの前に別の状態で
チェックiしてください。


4
列挙型も使用できます。
Karu

5
列挙型がnullの場合、同じ問題が発生します。ところで、デフォルト句があるので、スイッチがnullを処理できないのは奇妙です

1
@LeonardoKenjiデフォルト句は、実際にはnullとは関係ありません。他のケースをチェックするために、スイッチをオンにしているものはすべて逆参照されるため、デフォルト句はnullのケースを処理しません(NullPointerExceptionが発生する前にスローされます)。
ベン

2
彼はデフォルトの句が前のケースでキャッチされなかった他の可能な列挙値としてnullを処理する必要があることを意味したと思います
Leo

0

SWITCHがどのように機能するかを検討してください。

  • プリミティブの場合、自動ボクシングのNPEで失敗する可能性があることがわかっています
  • ただし、Stringまたはenumの場合、equalsメソッドを呼び出す可能性があります。明らかに、equalsが呼び出されるLHS値が必要です。したがって、nullではメソッドを呼び出せないため、スイッチはnullを処理できません。

0

@tetsuoの回答に基づいて、Java 8で:

Integer i = ...

switch (Optional.ofNullable(i).orElse(DEFAULT_VALUE)) {
    case DEFAULT_VALUE:
        doDefault();
        break;    
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.