为什么在这种情况下为原始函数返回null?

时间:2012-11-29 12:34:18

标签: java jls

如果s == null

,这段丑陋的代码会编译但会抛出NPE
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条件运算符? :

[...]

条件表达式的类型确定如下:

[...]

  • 如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是将装箱转换(第5.1.7节)应用于T的结果,则条件表达式的类型为T. / LI>

[...]

  • 否则,第二个和第三个操作数分别为S1和S2类型。让 T1是将拳击转换应用于S1,让T2成为的结果 将拳击转换应用于S2所产生的类型。 条件表达式的类型是应用捕获的结果 转换(§5.1.10)到lub(T1,T2)(§15.12.2.7)。

3 个答案:

答案 0 :(得分:16)

第一个有一个trenary运算符,其结果类型为Boolean。 NPE正在将null转换为boolean

实际上是这样的:

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

第二个试图返回错误的类型(Object而不是primitive) - 因此无法编译。

答案 1 :(得分:0)

Tricky Ternary Operator in JAVA类似

三元运算符使用JLS中引用的规则进行自动装箱:

Boxing Conversion

  

此规则是必要的,因为条件运算符(第15.25节)   将boxing转换应用于其操作数的类型,并使用   导致进一步的计算。

问题在于Java中的Autoboxing。问题是由于第二个操作数不是第三个。

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

此代码不会编译

JLS for Conditional Operator

答案 2 :(得分:0)

三元运算符需要为两个操作数找出最合适的返回类型。

因此,它允许对返回类型进行一些“抛光”。

如您的第一个代码段所示:

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

s.empty()返回原始boolean,而第三个操作数返回null。 因此,最具体的常见返回类型是Boolean。编译器的工作就像替换以下行:

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

返回类型方法需要一个boolean原语,因此编译器会说:“很酷,我只需要取消我的结果!”。不幸的是,null并非无法使用,导致丑陋的NPE。

使用您的第二个代码段:

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

由于编译器未链接此代码中的两个return语句,因此不会对返回前类型进行额外的“抛光”=>对它来说可能太难了。

因此,在这种情况下,由于nullBoolean无关,因此代码甚至无法编译是合乎逻辑的!所以,不会发生任何类型的演员。

要编译它,它应该写成:

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

但是在尝试拆箱时不会阻止着名的NPE;)