groovy:在地图中安全地找到一个键并返回它的值

non*_*ing 43 groovy closures dictionary

我想在给定的地图中找到一个特定的键.如果找到密钥,那么我想从地图中获取该密钥的值.

这是我到目前为止所管理的:

def mymap = [name:"Gromit", likes:"cheese", id:1234]

def x = mymap.find{ it.key == "likes" }

if(x)
    println x.value
Run Code Online (Sandbox Code Playgroud)

这是有效的,输出是"奶酪"如预期的那样.太好了,但最后我不想做x.value,我不想做if(x).我希望x以某种方式直接包含值.

我不能像这样直接获取x的值:

def mymap = [name:"Gromit", likes:"cheese", id:1234]

def x = mymap.find{ it.key == "likesZZZ" }.value

println x
Run Code Online (Sandbox Code Playgroud)

因为在这种情况下find闭包为null,所以这会导致Null指针异常.当然,上面的代码片段可以工作it.key == "likes",但我不确定我是否总会在地图中找到目标键.

什么是"Groovier"并且在地图上安全地执行此操作:

  • 检查地图是否有给定的密钥,
  • 如果是这样,请获取此密钥的值

Ove*_*ous 57

使用地图的重点是直接访问.如果您确定地图中的值永远不会是Groovy- false,那么您可以这样做:

def mymap = [name:"Gromit", likes:"cheese", id:1234]
def key = "likes"

if(mymap[key]) {
    println mymap[key]
}
Run Code Online (Sandbox Code Playgroud)

但是,如果值可能是Groovy- false,则应使用:

if(mymap.containsKey(key)) {
    println mymap[key]
}
Run Code Online (Sandbox Code Playgroud)

但是,最简单的解决方案是,如果您知道值不是Groovy- false(或者您可以忽略它),并且想要一个默认值,则如下所示:

def value = mymap[key] ?: "default"
Run Code Online (Sandbox Code Playgroud)

所有这三个解决方案都明显快于您的示例,因为它们不扫描整个地图中的密钥.他们利用HashMap(或LinkedHashMap)设计使直接密钥访问几乎是即时的.

  • 如果你想要默认值,你可以将地图定义为 `def map = [:].withDefault {"Default"}`。那么你就不需要使用 Elvis Operator 作为默认值了。当然,这也会更新地图,所以如果你不想那样,那么 Elvis 就是你的方式。 (2认同)

Dor*_*ler 21

def mymap = [name:"Gromit", id:1234]
def x = mymap.find{ it.key == "likes" }?.value
if(x)
    println "x value: ${x}"

println x.getClass().name
Run Code Online (Sandbox Code Playgroud)

?.检查null并且不在Groovy中创建异常.如果密钥不存在,结果将是a org.codehaus.groovy.runtime.NullObject.

  • 使用封闭物非常昂贵.更好地使用`def x = mymap.get("likes")?.value`,效率更高 (4认同)

Axe*_*der 5

一般来说,这取决于您的地图包含的内容。如果它具有空值,事情可能会变得棘手,并且应该使用containsKey(key)orget(key, default)来检测元素是否确实存在。在许多情况下,代码可以变得更简单,您可以定义一个默认值:

def mymap = [name:"Gromit", likes:"cheese", id:1234]
def x1 = mymap.get('likes', '[nothing specified]')
println "x value: ${x}" }
Run Code Online (Sandbox Code Playgroud)

另请注意,containsKey()orget()比设置闭包来检查元素要快得多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
}
Run Code Online (Sandbox Code Playgroud)

或者使用显式参数:

mymap.find{ key,value ->
  (key != "likes")  return false
  println "x value: ${value}" 
  return true // stop searching
}
Run Code Online (Sandbox Code Playgroud)


sma*_*c89 5

您忘记提及当密钥不存在时会发生什么。我假设null是好的。


Groovy 映射可以使用属性表示法进行查询。所以你可以这样做:

def x = mymap.likes
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果存在则x包含该值mymap['likes'],否则将为 null。

如果您正在查找的键(例如'likes.key')本身包含一个点,那么您可以像这样引用该键:

def x = mymap.'likes.key'
Run Code Online (Sandbox Code Playgroud)

如果键存储在变量中,请使用带有属性表示法的字符串插值,如下所示:

def key = 'likes'
def x = mymap."$key"
Run Code Online (Sandbox Code Playgroud)

如果您不喜欢null,则可以使用elvis 运算符来分配默认值(类似于java.util.Map.getOrDefault):

def x = mymap.someKey ?: 'default value'
Run Code Online (Sandbox Code Playgroud)

现在你知道了所有的秘密。

请记住,groovy 映射仍然只是具有“增强功能”的 Java 映射,因此适用于 Java 的规则仍然适用于 groovy。值得注意的是,该java.util.Map界面有一个注释,上面写着:

某些映射实现对其可能包含的键和值有限制。例如,某些实现禁止空键和值,而某些实现对其键的类型有限制。尝试插入不合格的键或值会引发未经检查的异常,通常NullPointerException为 或ClassCastException。尝试查询是否存在不合格的键或值可能会引发异常,或者可能只是返回 false;一些实现将表现出前一种行为,而另一些实现将表现出后者。更一般地,尝试对不合格的键或值进行操作(其完成不会导致将不合格的元素插入到映射中)可能会引发异常,也可能会成功,具体取决于实现的选择。此类异常在此接口的规范中被标记为“可选”。

基本上这就是说:并非所有地图都是相同的,因此当您尝试对地图进行这些操作时,请确保您在某种程度上了解正在处理的地图类型(内部)。对于简单的东西来说这不应该是问题,因为Groovy 默认使用java.util.LinkedHashMap.