我正在将我的模板代码移植到XTend。在某种程度上,我在测试用例中进行了这种类型的条件处理:
@Test
def xtendIfTest() {
val obj = new FD
if (true && obj?.property?.isNotNull) {
return
}
fail("Not passed")
}
def boolean isNotNull(Object o) {
return o != null
}
class FD {
@Accessors
String property
}这与预期的一样,因为属性为null,测试将在“未传递”消息中失败。但是,将isNotNull方法的返回类型简单地更改为布尔(包装):
def Boolean isNotNull(Object o) {
return o != null
}使用NullPointerException失败。通过检查为此生成的java代码,我可以看到XTend使用的是中间布尔对象表达式,这就是NPE的原因。我是否遗漏了XTend空安全运算符的点(?)或者我不能在接线员之后用这样的方法?
谢谢。
发布于 2015-06-15 21:40:13
操作人员行为正常。抛出此异常是因为在if-表达式中使用布尔值,这需要自动取消装箱。
如果您尝试以下方法:
@Test
def xtendIfTest() {
val Boolean obj = null
if (obj) {
return
}
fail("Not passed")
}您还将遇到一个NullPointerException。
这与Java规范(https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.8)是一致的--当需要自动取消装箱时,可以产生一个NullPointerException:
@Test
public void test() {
Boolean value = null;
if (value) { // warning: Null pointer access: This expression of type Boolean is null but requires auto-unboxing
// dead code
}
}希望这能有所帮助。
发布于 2016-08-09 17:52:37
简短回答:将第二个空安全调用更改为常规调用。
即变化
obj?.property?.isNotNull对此:
obj?.property.isNotNull长答案:
文档如实地描述了空安全操作符:
在许多情况下,如果接收方为空,则表达式返回空是可以的。
这意味着在您的示例中的第二个调用,如果调用的左侧是property?.,则甚至不会调用isNotNull。相反,它将返回null。因此,条件“有效”的计算结果为:
if (true && null) { // causes NPE when java tries to unbox the Boolean (顺便说一句,在这种情况下,true是多余的,但我保留它,以防您有另一个条件需要检查--我假设您只是将其简化为true。)
如果您做了我建议的更改,将对obj?.property进行评估,然后将结果传递给isNotNull,计算结果如下:
if (true && isNotNull(null)) {返回正确的Boolean对象,该对象将按预期自动取消装箱。
--警告词
在第一种形式的isNotNull中,即返回原语boolean的形式中,您实际上应该得到一个警告,比如“原始值特性isNotNull的零安全调用,将使用默认值false”。
这是因为您扩展了空安全调用的意图,即如果运算符的左侧是null,则返回null而不调用右侧方法。但是如果您的isNotNull返回一个原始的boolean,那么整个表达式显然不能计算为null,所以X趋向使用默认的方法,即用于布尔人的false。
要以不同的方式强调这个问题--它的计算结果为false而不调用isNotNull --这意味着即使您在操作符后面使用了isNull方法,它仍然会返回false!
文档还提到了这种行为(尽管一般情况下):
对于原语类型,将返回默认值(例如,0表示int)。在某些情况下,这可能不是您想要的,因此默认情况下将引发警告。
因此,我建议始终在空安全调用的右侧使用非原始返回值。但是,如果要像我建议的那样将isNotNull转换为常规调用,那么这个规则就不适用了,而且这两种返回类型都可以。
https://stackoverflow.com/questions/30814510
复制相似问题