web-dev-qa-db-ja.com

Java 12はスイッチの結果を数値に変換しようとするのはなぜですか?

私はこのコードに同意します:

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

この結果は予想外だと思います。

43
Ilya

スイッチ式の [〜#〜] jep [〜#〜] によると、スイッチ式はポリ式です:

スイッチ式はポリ式です。ターゲットのタイプがわかっている場合、このタイプは各アームに押し下げられます。スイッチ式のタイプは、既知であれば、そのターゲットタイプです。そうでない場合、スタンドアロンタイプは、各ケースアームのタイプを組み合わせて計算されます。

ターゲットの型がないため、式は指定された型と一致するようにチェックされません。

これを確認するには、varをタイプに置き換えます。

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

私のシェルでは、これは失敗します:

|  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型の場合もある)の場合、それがスイッチ式の型になります。
  • それ以外の場合で、各結果式のタイプがブールまたはブールの場合、ブール型の各結果式にボックス化解除変換(5.1.8)が適用され、スイッチ式のタイプはブールになります。
  • それ以外の場合、各結果式のタイプが数値タイプ(5.1.8)に変換可能な場合、スイッチ式のタイプは、結果式に適用された数値昇格(5.6)の結果です。

  • それ以外の場合、ボックス型変換(5.1.7)はプリミティブ型を持つ各結果式に適用されます。その後、スイッチ式の型はキャプチャ変換(5.1.10)を最小上限(4.10.4)に適用した結果になります。 )結果式のタイプ。

私が見る限り、ブール式を削除すると、数値式が残ります(char'0'int 48)はfloat48.0に昇格されます)。上記の3番目の箇条書きを参照してください。

そして、floatが結果の型である理由については、 数値コンテキスト セクションを参照してください。

48
ernest_k