如何在 switch 中使用 null

IT小君   2021-10-24T06:20:52
Integer i = ...

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

在上面的代码中,我不能在 switch case 语句中使用 null。我怎样才能以不同的方式做到这一点?我无法使用,default因为那时我想做其他事情。

评论(13)
IT小君

switch对于 Java 中语句是不可能的检查null之前switch

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

您不能在switch语句* 中使用任意对象编译器不抱怨switch (i)where iis anInteger的原因是因为 Java 自动将 the 拆箱Integer为 an int正如 assylias 已经说过的,拆箱会抛出一个NullPointerExceptionwhen iis null

*从 Java 7 开始,您可以Stringswitch语句中使用

Oracle Docs 中的更多信息switch(包括带有空变量的示例)- Switch

2021-10-24T06:20:53   回复
IT小君
switch ((i != null) ? i : DEFAULT_VALUE) {
        //...
}
2021-10-24T06:20:53   回复
IT小君

switch(i)如果 i 是null则会抛出 NullPointerException ,因为它会尝试将 拆箱Integerint因此case null,碰巧是非法的 ,无论如何都不会达到。

您需要在switch语句之前检查 i 是否为空

2021-10-24T06:20:53   回复
IT小君

Java 文档明确指出:

禁止使用 null 作为开关标签可以防止编写永远无法执行的代码。如果 switch 表达式是引用类型,例如装箱的原始类型或枚举,则如果表达式在运行时计算为 null,则会发生运行时错误。

在执行Swithch 语句之前,您必须验证是否为空。

if (i == null)

请参阅Switch 语句

case null: // will never be executed, therefore disallowed.
2021-10-24T06:20:53   回复
IT小君

鉴于:

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) {我开始实施的一个变通方法(即“解决方案”)是添加一个UNKNOWN(-1)类型。

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

现在,您不必在重要的地方进行空值检查,您可以选择是否处理UNKNOWN类型。(注意:-1在业务场景中不太可能是标识符,但显然选择对您的用例有意义的东西)。

2021-10-24T06:20:53   回复
IT小君

你必须做一个

if (i == null) {
   doSomething0();
} else {
   switch (i) {
   }
}
2021-10-24T06:20:53   回复
IT小君

一些库试图提供内置 javaswitch语句的替代方案Vavr就是其中之一,他们将其概括为模式匹配。

这是他们文档中的一个例子

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

您可以使用任何谓词,但它们提供了许多开箱即用的谓词,并且$(null)是完全合法的。我发现这是一个比替代方案更优雅的解决方案,但这需要 java8 和对 vavr 库的依赖...

2021-10-24T06:20:53   回复
IT小君

你也可以使用String.valueOf((Object) nullableString)

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

查看有趣的 SO Q/A:Why does String.valueOf(null) throw a NullPointerException

2021-10-24T06:20:54   回复
IT小君
switch (String.valueOf(value)){
    case "null":
    default: 
}
2021-10-24T06:20:54   回复
IT小君

基于@tetsuo 的回答,使用 java 8 :

Integer i = ...

switch (Optional.ofNullable(i).orElse(DEFAULT_VALUE)) {
    case DEFAULT_VALUE:
        doDefault();
        break;    
}
2021-10-24T06:20:54   回复
IT小君

你不能。您可以在 switch 中使用原语(int、char、short、byte)和字符串(仅限 java 7 中的字符串)。原语不能为空。切换前在单独的条件下
检查i

2021-10-24T06:20:54   回复
IT小君

只要考虑一下 SWITCH 可能如何工作,

  • 对于原语,我们知道它可能会因 NPE 自动装箱而失败
  • 但是对于Stringenum,它可能正在调用 equals 方法,这显然需要一个 LHS 值,在该值上调用 equals。因此,鉴于无法在 null 上调用任何方法,switch无法处理 null。
2021-10-24T06:20:54   回复
IT小君

我今天刚刚了解到,您不必仅仅因为检查空值的 if 就再放一层缩进/大括号。您可以执行以下任一操作:

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

或者

if (i != null) switch (i) {
    case 1:
        // ...
        break;
    default:
        // ...
} else {
    // ...
}
2021-10-24T06:20:54   回复