groovy:安全地在地图中找到一个键并返回它的值
Posted
技术标签:
【中文标题】groovy:安全地在地图中找到一个键并返回它的值【英文标题】:groovy: safely find a key in a map and return its value 【发布时间】:2012-12-21 05:05:23 【问题描述】:我想在给定的地图中找到一个特定的键。如果找到键,我想从地图中获取该键的值。
这是我目前所管理的:
def mymap = [name:"Gromit", likes:"cheese", id:1234]
def x = mymap.find it.key == "likes"
if(x)
println x.value
这行得通,输出如预期的那样是“奶酪”。很好,但我不想在最后做x.value
,我也不想做if(x)
。我希望 x 以某种方式直接包含该值。
我无法像这样将值直接放入 x 中:
def mymap = [name:"Gromit", likes:"cheese", id:1234]
def x = mymap.find it.key == "likesZZZ" .value
println x
因为在这种情况下 find 闭包为空,这会导致空指针异常。当然,上面的代码sn -p在it.key == "likes"
时有效,但我不确定我是否总能在map中找到目标键。
什么是在地图上执行此操作的“Groovier”和安全方式:
检查地图是否有给定的键, 如果是,则获取此键的值【问题讨论】:
【参考方案1】:您忘记提及当密钥不存在时会发生什么。我假设null
没问题。
可以使用property notation 查询 Groovy 地图。所以你可以这样做:
def x = mymap.likes
在这种情况下,x
将包含 mymap['likes']
的值(如果存在),否则为 null。
如果您要查找的键(例如'likes.key'
)本身包含一个点,那么您可以像这样引用该键:
def x = mymap.'likes.key'
如果密钥存储在变量中,请使用带有 属性表示法的string interpolation,如下所示:
def key = 'likes'
def x = mymap."$key"
如果你不喜欢null
,那么使用你使用elvis operator来分配一个默认值来代替(类似于java.util.Map.getOrDefault
):
def x = mymap.someKey ?: 'default value'
现在你知道所有的秘密了。
请记住,groovy 映射仍然只是带有“enhancements”的 Java 映射,因此适用于 Java 的规则仍然适用于 groovy。值得注意的是,java.util.Map
界面中有一条注释,上面写着:
一些地图实现对它们可能包含的键和值有限制。例如,一些实现禁止空键和值,而一些实现对其键的类型有限制。尝试插入不合格的键或值会引发未经检查的异常,通常是
NullPointerException
或ClassCastException
。尝试查询是否存在不合格的键或值可能会引发异常,或者它可能只是返回 false;一些实现会表现出前一种行为,而另一些会表现出后者。更一般地,尝试对不合格的键或值进行操作,其完成不会导致将不合格的元素插入到映射中,这可能会引发异常,也可能会成功,这取决于实现的选择。此类异常在此接口的规范中被标记为“可选”。
基本上这就是说:并非所有地图都是相同的,因此在尝试对它们进行这些操作时,请确保您对(内部)正在处理的地图类型有所了解。这对于简单的东西应该不是问题,因为 Groovy 默认使用 java.util.LinkedHashMap
。
【讨论】:
【参考方案2】:一般来说,这取决于您的地图所包含的内容。如果它有空值,事情就会变得棘手,应该使用containsKey(key)
或get(key, default)
来检测元素是否真的存在。在很多情况下,代码可以变得更简单,您可以定义一个默认值:
def mymap = [name:"Gromit", likes:"cheese", id:1234]
def x1 = mymap.get('likes', '[nothing specified]')
println "x value: $x"
还要注意containsKey()
或get()
比设置闭包检查元素mymap.find it.key == "likes"
要快得多。只有当你真的在那里做了更复杂的事情时,使用闭包才有意义。你可以例如这样做:
mymap.find // "it" is the default parameter
if (it.key != "likes") return false
println "x value: $it.value"
return true // stop searching
或者带有显式参数:
mymap.find key,value ->
(key != "likes") return false
println "x value: $value"
return true // stop searching
【讨论】:
【参考方案3】:def mymap = [name:"Gromit", id:1234]
def x = mymap.find it.key == "likes" ?.value
if(x)
println "x value: $x"
println x.getClass().name
?.
检查 null 并且不会在 Groovy 中创建异常。如果键不存在,结果将是org.codehaus.groovy.runtime.NullObject
。
【讨论】:
太棒了。这比我选择的原始答案更时髦,更符合我的要求。标记这是答案。谢谢。 使用闭包非常昂贵。最好在那里使用def x = mymap.get("likes")?.value
,效率更高
接近我的情况所需,我使用了findAll it.key in list
【参考方案4】:
您得到空指针异常的原因是因为在您的第二个示例中没有键 likesZZZ。试试:
def mymap = [name:"Gromit", likes:"cheese", id:1234]
def x = mymap.find it.key == "likes" .value
if(x)
println "x value: $x"
【讨论】:
如问题所述,我不能确定钥匙是否始终在地图中,所以我想要一种安全工作的方法(无例外),即使钥匙在或不在地图。【参考方案5】:使用地图的重点在于直接访问。如果您确定地图中的值永远不会是 Groovy-false
,那么您可以这样做:
def mymap = [name:"Gromit", likes:"cheese", id:1234]
def key = "likes"
if(mymap[key])
println mymap[key]
但是,如果该值可能是 Groovy-false
,您应该使用:
if(mymap.containsKey(key))
println mymap[key]
不过,如果您知道该值不会是 Groovy-false
(或者您可以忽略它)并且想要一个默认值,那么最简单的解决方案是这样的:
def value = mymap[key] ?: "default"
所有这三个解决方案都比您的示例快得多,因为它们不会扫描整个地图以查找键。他们利用了HashMap
(或LinkedHashMap
)设计,使直接密钥访问几乎瞬间完成。
【讨论】:
如果需要默认值,可以将映射定义为def map = [:].withDefault "Default"
。那么你就不需要使用 Elvis Operator 作为默认值了。当然,这也会更新地图,所以如果你不想这样,那么猫王就是你的方式。
Key 也可以用双引号引起来,例如 def headers = ["Content-Type":"application/json"]以上是关于groovy:安全地在地图中找到一个键并返回它的值的主要内容,如果未能解决你的问题,请参考以下文章