Groovy注入中奇怪的NullPointerException [英] Weird NullPointerException in Groovy inject

查看:188
本文介绍了Groovy注入中奇怪的NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 常规:000> ['homepages / gg','a','b','c','d']。inject([]){list,conf  - > if(!conf.contains('homepage')){list<< conf.trim()}} 
错误java.lang.NullPointerException:
无法在空对象
处调用方法leftShift()at groovysh_evaluate $ _run_closure1.doCall(groovysh_evaluate:3)
常规:000> ['homepages / gg','a','b','c','d']。inject([]){list,conf - > conf.contains('homepage')?列表:列表<< conf.trim()}
===> [a,b,c,d]

为什么我得到 NullPointerException 在第一种情况下,但不是在第二种?我使用Groovy 2.3.7。

解决方案

因为这段代码:

  if(!conf.contains('homepage')){list<< conf.trim()} 

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



三元运算符on另一方面,返回一个值是否符合条件,所以这段代码:

  conf.contains('homepage' )?列表:列表<< conf.trim()

返回一个实际的对象,即使 conf 确实包含'homepage'



要看看为什么这是一个问题,请看看 注入 方法。



引用Javadoc:


遍历给定的Collection,传入初始值与第一个项目一起用于2-arg闭包。结果与第二个项目一起返回(注入)关闭。新的结果会连同第三个项目一起注入到关闭中,直到整个集合被使用。


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

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

运行这个结果:

  [[],homepages / gg] 
[null,a]
抛出的异常

java.lang.NullPointerException :无法在ConsoleScript9上的空对象

上调用方法leftShift()$ _run_closure2.doCall(ConsoleScript9:2)
$ b $在ConsoleScript9.run(ConsoleScript9:2)

第一次调用将您传递的空数组作为单个 Object 参数和列表的第一个元素,即homepages / gg。如果表达式被传递给。因为第一个元素homepages / gg确实包含字符串homepage,所以如果条件评估为false。因为没有 else 什么都没有返回



由第一次封闭评估返回的 null 引用表示,并与列表的下一个元素一起用于第二次评估。 p>

conf 现在等于a list 等于 null 。更进一步,您可以在 null 列表中使用< 左移运算符(

这里有一个相当于一个版本的版本:

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

输出如预期:

  ===> [a,b,c,d] 


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]

Why do I get a NullPointerException in the first case but not in the second? I am using Groovy 2.3.7.

解决方案

Because this code:

if (!conf.contains('homepage')) { list << conf.trim() }

does not return anything when the condition is not met. There's no else to this if. If you add an else returning a meaningful value, you'll avoid the exception.

The ternary operator, on the other hand, does return a value whether or not the condition is met so this code:

conf.contains('homepage') ? list : list << conf.trim()

returns an actual object even if conf does contain 'homepage'

To see why this is a problem, take a look at what the inject method does.

To quote the Javadoc:

Iterates through the given Collection, passing in the initial value to the 2-arg closure along with the first item. The result is passed back (injected) into the closure along with the second item. The new result is injected back into the closure along with the third item and so on until the entire collection has been used.

Now, let's take a look at a slightly modified example. I added a println to see what the closure parameters become:

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

Running this yields:

[[], 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)

The first call takes the empty array that you pass as the single Object parameter and the first element of the list, namely "homepages/gg". This gets passed to the if expression. Because the first element, "homepages/gg" does indeed contain the string "homepage", the if condition is evaluated to false. Because there is no else, nothing is returned.

The nothing, represented by a null reference, returned by the first evaluation of the closure is used in the second evaluation, along with the next element of the list.

conf is now equal to "a" and list is equal to null. Further on, you use the << left shift operator on the null list (list << conf.trim()).

Hence the exception.

Here's a version equivalent to the one that works:

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

The output is as expected:

===> [a, b, c, d]

这篇关于Groovy注入中奇怪的NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆