web-dev-qa-db-ja.com

switchでnullを使う方法

Integer i = ...

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

上記のコードでは、switch case文にnullを使用できません。これを別の方法で行うことができますか? defaultは使用できません。それ以外のことをしたいのです。

175
hudi

これは、Javaのswitchステートメントでは不可能です。 nullの前にswitchを確認します。

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

switchステートメントで任意のオブジェクトを使用することはできません*iIntegerであるswitch (i)についてコンパイラが文句を言わないのは、JavaがIntegerintに自動アンボックス化するためです。アサイラスがすでに言ったように、NullPointerExceptioniの場合、ボックス化解除はnullをスローします。

* Java 7以降では、Stringステートメントでswitchを使用できます。

switch(null変数の例を含む)についての詳細は、Oracle Docs - Switch を参照してください。

243
Jesper
switch ((i != null) ? i : DEFAULT_VALUE) {
        //...
}
76
tetsuo

iがnullである場合、switch(i)はNullPointerExceptionをスローします。これは、Integerintにアンボックス化しようとするためです。そのため、case null(これは違法であることが起こります)は、とにかく決して到達されなかったでしょう。

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

32
assylias

Javaのドキュメントは明確にこう述べています。

スイッチラベルとしてnullを使用しないことで、決して実行できないコードを書くことを防ぐことができます。 switch式がボックス型プリミティブ型やenumなどの参照型の場合、式が実行時にnullと評価されると実行時エラーが発生します。

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

if (i == null)

switch文 を参照してください。

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

与えられた:

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はビジネスシナリオでは考えられない識別子ですが、明らかにあなたのユースケースに意味のあるものを選択してください)。

12
Beez

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

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

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

これは 彼らのドキュメント からの例です:

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

あなたはどんな述語も使うことができます、しかしそれらは箱から出してそれらの多くを提供します、そして$(null)は完全に合法です。私はこれが他のものよりももっと洗練された解決策であると思います、しかしこれはJava8とvavrライブラリへの依存を必要とします...

4
switch (String.valueOf(value)){
    case "null":
    default: 
}
1
l0v3

String.valueOf((Object) nullableString)を使うこともできます

switch (String.valueOf((Object) nullableString)) {
case "someCase"
    //...
    break;
...
case "null": // or default:
    //...
        break;
}

面白いSOを参照してくださいQ/A: String.valueOf(null)がNullPointerExceptionをスローするのはなぜですか

1
oikonomopo

SWITCHがどのように機能するかを考えてください。

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

できません。スイッチにはプリミティブ(int、char、short、byte)とString(Java 7のStringsのみ)を使用できます。プリミティブはnullにできません。
切り替えの前にiを別の状態で確認してください。

0