这段丑陋的代码可以编译,但如果为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条件运算符?:
..。
条件表达式的类型如下所示:
..。
..。
第二个和第三个操作数的类型分别为S1和S2。设T1是将装箱转换应用于S1的类型,T2是将装箱转换应用于S2的类型。条件表达式的类型是将捕获转换(§5.1.10)应用到lub(T1,T2) (§15.12.2.7).的结果
发布于 2012-11-29 20:36:47
第一个有一个三元运算符,其结果类型为Boolean
。NPE正在将null
转换为boolean
。
它实际上是这样的:
Boolean temp = s != null ? s.isEmpty() : null; //no problems here
return temp; //crash when temp==null
第二个试图返回错误的类型(对象而不是原始类型)-因此无法编译。
发布于 2012-11-29 20:49:13
类似于Tricky Ternary Operator in JAVA
三元运算符使用JLS中引用的规则执行自动装箱:
此规则是必需的,因为条件运算符(§15.25)将装箱转换应用于其操作数的类型,并在进一步的计算中使用结果。
问题出在中的自动装箱。这个问题是由于第二个操作数而不是第三个操作数造成的。
public static boolean isNullOrEmpty(String s)
{
return s != null ? null : null;
}
这段代码不能编译
发布于 2012-11-29 21:44:12
三元运算符需要为两个操作数找出最合适的返回类型。
因此,它允许对返回类型进行一些“润色”。
如您的第一个代码片段所示:
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;
}
由于编译器不会链接这段代码中的两个返回语句,因此不会对预返回类型进行额外的“润色”。=>对它来说可能是一项太难的工作。
因此,在这种情况下,由于null
与Boolean
没有关联,因此代码甚至不编译是合乎逻辑的!因此,不会发生任何类型的强制转换。
要编译它,应将其编写为:
public static boolean isNullOrEmpty(String s)
{
if(s != null)
return s.isEmpty();
else
return (Boolean)null;
}
但不能防止在尝试取消装箱时发生著名的NPE ;)
https://stackoverflow.com/questions/13625956
复制相似问题