为什么 Java 12 尝试将开关的结果转换为数字?

2022-08-31 23:41:42

我同意此代码:

var y = switch (0) {
    case 0 -> '0';
    case 1 -> 0.0F;
    case 2 -> 2L;
    case 3 -> true;
    default -> 4;
};
System.out.println(y);
System.out.println(((Object) y).getClass().getName());

返回以下内容:

0
java.lang.Character

但是,如果删除布尔值:

var y = switch (0) {
    case 0 -> '0';
    case 1 -> 0.0F;
    case 2 -> 2L;
    default -> 4;
};
System.out.println(y);
System.out.println(((Object) y).getClass().getName());

返回以下内容:

48.0
java.lang.Float

我想这个结果是出乎意料的。


答案 1

根据开关表达式的 JEP,开关表达式是 poly 表达式:

开关表达式是多元表达式;如果目标类型已知,则将此类型向下推入每个臂中。开关表达式的类型是其目标类型(如果已知);如果不是,则通过组合每个案例臂的类型来计算独立类型。

由于您没有目标类型,因此不会检查表达式是否与任何给定类型匹配,这是预期的。

您可以通过替换为类型来验证这一点:var

int y = switch (0) {
    case 0 -> '0';
    case 1 -> 0.0F;
    case 2 -> 2L;
    case 3 -> true;
    default -> 4;
};

在我的 shell 中,此操作失败,如下所示:

|  Error:
|  incompatible types: bad type in switch expression
|      possible lossy conversion from float to int
|      case 1 -> 0.0F;
|                ^--^
|  Error:
|  incompatible types: bad type in switch expression
|      possible lossy conversion from long to int
|      case 2 -> 2L;
|                ^^
|  Error:
|  incompatible types: bad type in switch expression
|      boolean cannot be converted to int
|      case 3 -> true;
|                ^--^

但是,如果您删除布尔值:...

看看如何确定独立类型就足够了(这里的规则):

独立开关表达式的类型确定如下

  • 如果结果表达式都具有相同的类型(可能是 null 类型),则这就是 switch 表达式的类型。

  • 否则,如果每个结果表达式的类型是布尔值或布尔值,则会将取消装箱转换 (5.1.8) 应用于布尔类型的每个结果表达式,并且 switch 表达式具有布尔值类型。

  • 否则,如果每个结果表达式的类型可转换为数值类型 (5.1.8),则 switch 表达式的类型是应用于结果表达式的数字升级 (5.6) 的结果。

  • 否则,装箱转换 (5.1.7) 将应用于具有基元类型的每个结果表达式,之后开关表达式的类型是将捕获转换 (5.1.10) 应用于结果表达式类型的最小上限 (4.10.4) 的结果。

据我所知,当您删除布尔表达式时,您会得到数值表达式( () 被提升为 )。请参阅上面的第三个项目符号点。char'0'int 48float48.0

至于结果类型为什么,请参阅“数值上下文”部分。float


答案 2