18

この見苦しいコードはコンパイルされますが、次の場合に NPE がスローされます。s == null

public static boolean isNullOrEmpty(String s)
{
    return s != null ? s.isEmpty() : null;
}

これはそうではありませんが(予想どおり):

public static boolean isNullOrEmpty(String s)
{
    if(s != null)
        return s.isEmpty();
    else
        return null;
}

どちらも明らかに間違っていることはわかっていますが、ソースで最初のコードを見つけたとき、それがコンパイルされたことに非常に驚きました。

編集: Java 7 の JLS の関連部分は次のとおりです。最初のステートメントが適用されると思いましたが、太字のステートメントが適用されます。

15.25 条件演算子 ? :

[...]

条件式のタイプは、次のように決定されます。

[...]

  • 2 番目と 3 番目のオペランドの一方がプリミティブ型 T で、もう一方の型が T にボックス化変換 (§5.1.7) を適用した結果である場合、条件式の型は T です。

[...]

  • それ以外の場合、2 番目と 3 番目のオペランドの型はそれぞれ S1 と S2 です。T1 を S1 にボックス化変換を適用した結果の型とし、T2 を S2 にボックス化変換を適用した結果の型とする。条件式の型は、キャプチャ変換 (§5.1.10) を lub(T1, T2) (§15.12.2.7) に適用した結果です。
4

3 に答える 3

16

1 つ目は、結果の型が の三項演算子を持ちBooleanます。NPE は を に変換しnullていbooleanます。

それは実際には次のようなものです:

Boolean temp = s != null ? s.isEmpty() : null; //no problems here
return temp; //crash when temp==null

2 つ目は、間違った型 (プリミティブではなくオブジェクト) を返そうとしているため、コンパイルされません。

于 2012-11-29T12:36:46.600 に答える
0

JAVAのトリッキーな三項演算子に似ています

三項演算子は、JLSで引用されているルールを使用してオートボクシングを実行します。

ボクシングの変換

この規則が必要なのは、条件演算子(§15.25)がそのオペランドの型にボクシング変換を適用し、その結果をさらなる計算に使用するためです。

問題は、Javaのオートボクシングにあります。この問題は、第2オペランドがthridではないことが原因です。

public static boolean isNullOrEmpty(String s)
    {
        return s != null ? null : null;
    }

このコードはコンパイルされません

条件付き演算子のJLS

于 2012-11-29T12:49:12.547 に答える
0

三項演算子は、両方のオペランドに最も適切な戻り値を見つける必要があります。

したがって、リターンタイプの「ポリッシュ」が可能になります。

最初のコードスニペットに示されているように:

public static boolean isNullOrEmpty(String s)
{
    return s != null ? s.isEmpty() : null;
}

s.empty()プリミティブを返しますがboolean、3番目のオペランドはを返しますnull。したがって、最も具体的な一般的なリターンタイプはBooleanです。コンパイラの仕事は、行を次のように置き換えるようなものです。

return s != null ? s.isEmpty() : (Boolean)null; 

Return型メソッドはbooleanプリミティブを期待しているので、コンパイラーは「かっこいい、結果を箱から出さなければならない!」と言います。残念ながら、null箱から出すことはできず、醜いNPEにつながります。

2番目のスニペットで:

public static boolean isNullOrEmpty(String s)
{
    if(s != null)
        return s.isEmpty();
    else
        return null;
}

コンパイラはこのコードの両方のreturnステートメントをリンクしないため、pre-returnタイプの追加の「ポリッシュ」は行われません=>それは非常に難しい作業である可能性があります。

したがって、この場合、!nullに関連付けられていないため、コードがコンパイルされないのは論理的です。Booleanしたがって、キャストは発生しません。

コンパイルするには、次のように記述する必要があります。

public static boolean isNullOrEmpty(String s)
    {
        if(s != null)
            return s.isEmpty();
        else
            return (Boolean)null;
    }

しかし、開梱しようとしているときに有名なNPEが発生するのを防ぐことはできません;)

于 2012-11-29T13:44:11.743 に答える