Groovy注入中奇怪的NullPointerException

时间:2014-11-18 22:14:23

标签: groovy nullpointerexception

groovy:000> ['homepages/gg','a','b','c','d'].inject([]) { list, conf -> if (!conf.contains('homepage')) { list << conf.trim() } }
ERROR java.lang.NullPointerException:
Cannot invoke method leftShift() on null object
        at groovysh_evaluate$_run_closure1.doCall (groovysh_evaluate:3)
groovy:000> ['homepages/gg','a','b','c','d'].inject([]) { list, conf -> conf.contains('homepage') ? list : list << conf.trim() }
===> [a, b, c, d]

为什么我在第一种情况下获得NullPointerException但在第二种情况下却没有?我使用的是Groovy 2.3.7。

1 个答案:

答案 0 :(得分:4)

因为这段代码:

if (!conf.contains('homepage')) { list << conf.trim() }
如果不满足条件,

不会返回任何内容。此else没有if。如果您添加else返回有意义的值,则可以避免异常。

另一方面,三元运算符确实返回一个值,无论条件是否满足,所以这段代码:

conf.contains('homepage') ? list : list << conf.trim()
即使conf包含'homepage'

也会返回实际对象

要了解这是一个问题,请看看inject方法的作用。

引用Javadoc:

  

遍历给定的Collection,将初始值与第一个项一起传递给2-arg闭包。结果与第二项一起传回(注入)到闭包中。新结果与第三个项目一起注入闭包,依此类推,直到整个集合被使用。

现在,我们来看一个稍微修改过的例子。我添加了一个println来查看闭包参数变成了什么:

 ['homepages/gg','a','b','c','d'].inject([]) { list, conf -> println "[$list, $conf]"; if (!conf.contains('homepage')) { list << conf.trim() } }

运行此产生:

[[], homepages/gg]
[null, a]
Exception thrown

java.lang.NullPointerException: Cannot invoke method leftShift() on null object

    at ConsoleScript9$_run_closure2.doCall(ConsoleScript9:2)

    at ConsoleScript9.run(ConsoleScript9:2)

第一次调用将您传递的空数组作为单个Object参数和列表的第一个元素,即"homepages/gg"。这将传递给if表达式。因为第一个元素"homepages/gg"确实包含字符串"homepage",所以if条件被评估为false。由于没有else不会返回任何内容

null引用表示的 nothing ,由闭包的第一次评估返回,用于第二次评估,以及列表的下一个元素。

conf现在等于"a“,list等于null。此外,您使用<<左移操作符{ {1}}列表(null)。

因此例外。

这是一个等效的版本:

list << conf.trim()

输出符合预期:

['homepages/gg','a','b','c','d'].inject([]) { list, conf ->  if (!conf.contains('homepage')) { list << conf.trim() } else list }