57

我想在给定的地图中找到一个特定的键。如果找到键,我想从地图中获取该键的值。

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

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 闭包为空,因此会导致空指针异常。当然,上面的代码片段在 时有效it.key == "likes",但我不确定我是否总能在地图中找到目标键。

在地图上执行此操作的“Groovier”和安全方法是什么:

  • 检查地图是否有给定的键,
  • 如果是这样,得到这个键的值
4

5 回答 5

71

使用地图的重点是直接访问。如果您确定地图中的值永远不会是 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)设计使直接密钥访问几乎是即时的。

于 2013-01-07T15:51:49.837 回答
30
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.

于 2017-01-09T14:46:31.997 回答
4

通常,这取决于您的地图包含的内容。如果它有空值,事情可能会变得棘手,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()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
}

或使用显式参数:

mymap.find{ key,value ->
  (key != "likes")  return false
  println "x value: ${value}" 
  return true // stop searching
}
于 2017-03-08T16:34:48.123 回答
4

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


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

def x = mymap.likes

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

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

def x = mymap.'likes.key'

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

def key = 'likes'
def x = mymap."$key"

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

def x = mymap.someKey ?: 'default value'

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

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

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

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

于 2019-10-10T04:26:27.283 回答
1

您获得空指针异常的原因是因为在您的第二个示例中没有键 likesZZZ。尝试:

def mymap = [name:"Gromit", likes:"cheese", id:1234]
def x = mymap.find{ it.key == "likes" }.value
if(x)
    println "x value: ${x}"
于 2017-01-06T17:48:36.163 回答