首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >XTend空安全抛出NullPointerException

XTend空安全抛出NullPointerException
EN

Stack Overflow用户
提问于 2015-06-13 02:28:27
回答 2查看 1.1K关注 0票数 3

我正在将我的模板代码移植到XTend。在某种程度上,我在测试用例中进行了这种类型的条件处理:

代码语言:javascript
复制
@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方法的返回类型简单地更改为布尔(包装):

代码语言:javascript
复制
def Boolean isNotNull(Object o) {
    return o != null
}

使用NullPointerException失败。通过检查为此生成的java代码,我可以看到XTend使用的是中间布尔对象表达式,这就是NPE的原因。我是否遗漏了XTend空安全运算符的点(?)或者我不能在接线员之后用这样的方法?

谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-06-15 21:40:13

操作人员行为正常。抛出此异常是因为在if-表达式中使用布尔值,这需要自动取消装箱。

如果您尝试以下方法:

代码语言:javascript
复制
@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:

代码语言:javascript
复制
@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
    }
}

希望这能有所帮助。

票数 2
EN

Stack Overflow用户

发布于 2016-08-09 17:52:37

简短回答:将第二个空安全调用更改为常规调用。

即变化

代码语言:javascript
复制
obj?.property?.isNotNull

对此:

代码语言:javascript
复制
obj?.property.isNotNull

长答案:

文档如实地描述了空安全操作符:

在许多情况下,如果接收方为空,则表达式返回空是可以的。

这意味着在您的示例中的第二个调用,如果调用的左侧是property?.,则甚至不会调用isNotNull。相反,它将返回null。因此,条件“有效”的计算结果为:

代码语言:javascript
复制
if (true && null) {  // causes NPE when java tries to unbox the Boolean 

(顺便说一句,在这种情况下,true是多余的,但我保留它,以防您有另一个条件需要检查--我假设您只是将其简化为true。)

如果您做了我建议的更改,将对obj?.property进行评估,然后将结果传递给isNotNull,计算结果如下:

代码语言:javascript
复制
if (true && isNotNull(null)) {

返回正确的Boolean对象,该对象将按预期自动取消装箱。

--警告词

在第一种形式的isNotNull中,即返回原语boolean的形式中,您实际上应该得到一个警告,比如“原始值特性isNotNull的零安全调用,将使用默认值false”。

这是因为您扩展了空安全调用的意图,即如果运算符的左侧是null,则返回null而不调用右侧方法。但是如果您的isNotNull返回一个原始的boolean,那么整个表达式显然不能计算为null,所以X趋向使用默认的方法,即用于布尔人的false

要以不同的方式强调这个问题--它的计算结果为false而不调用isNotNull --这意味着即使您在操作符后面使用了isNull方法,它仍然会返回false

文档还提到了这种行为(尽管一般情况下):

对于原语类型,将返回默认值(例如,0表示int)。在某些情况下,这可能不是您想要的,因此默认情况下将引发警告。

因此,我建议始终在空安全调用的右侧使用非原始返回值。但是,如果要像我建议的那样将isNotNull转换为常规调用,那么这个规则就不适用了,而且这两种返回类型都可以。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30814510

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档