Groovy 注入中奇怪的 NullPointerException

aa8*_*a8y 3 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]
Run Code Online (Sandbox Code Playgroud)

为什么我NullPointerException在第一种情况下得到 a而在第二种情况下没有?我正在使用 Groovy 2.3.7。

ton*_*edz 5

因为这段代码:

if (!conf.contains('homepage')) { list << conf.trim() }
Run Code Online (Sandbox Code Playgroud)

不满足条件时不返回任何内容。没有else这个if。如果您添加一个else返回有意义的值,您将避免异常。

另一方面,无论条件是否满足,三元运算符都会返回一个值,因此以下代码:

conf.contains('homepage') ? list : list << conf.trim()
Run Code Online (Sandbox Code Playgroud)

返回一个实际对象,即使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() } }
Run Code Online (Sandbox Code Playgroud)

运行这个会产生:

[[], 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)
Run Code Online (Sandbox Code Playgroud)

第一次调用将您传递的空数组作为单个Object参数和列表的第一个元素,即"homepages/gg". 这将传递给if表达式。因为第一个元素"homepages/gg"确实包含 string "homepage",所以if条件被评估为假。因为没有else什么也没有返回

闭包的第一次评估返回的由引用表示的nothingnull与列表的下一个元素一起用于第二次评估。

conf现在等于"a" 并且list等于null。进一步,您<<null列表 ( list << conf.trim())上使用左移运算符。

因此例外。

这是一个与有效版本等效的版本:

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

输出如预期:

===> [a, b, c, d]
Run Code Online (Sandbox Code Playgroud)