【问题标题】:Strange lambda behaviour in Java streamJava流中奇怪的lambda行为
【发布时间】:2021-12-02 14:00:14
【问题描述】:

我创建了以下方法,将给定的 UUID 值与给定的整数添加到 map 变量中。

final Map<Integer, List<UUID>> map = new TreeMap<>();

private void addToMap(Integer key, UUID value) {
    map.computeIfAbsent(key, val -> new ArrayList<>()).add(value);
}

通常我试图通过将 value 参数传递给 lambda 函数来使用 map.computeIfAbsent(key, value -&gt; new ArrayList&lt;&gt;()).add(value);,它会抛出“变量'值'已在范围内定义”错误指向“值" 在.. value -&gt; ... 部分。

我更新的addToMap 方法有效,但我认为val 毫无意义。那么,这个方法应该如何更新呢?

【问题讨论】:

  • 我不认为你能做的比你已经做的更多。其他语言为此使用 _,但这是自 Java 9 以来的保留关键字
  • 非常感谢。问完问题,看到computeIfAbsent方法解释中有类似用法。所以,val 只在那个地方使用。所以,我可以像以前一样使用它。

标签: java lambda stream hashmap java-stream


【解决方案1】:

你的addToMap()方法意味着对computeIfAbsent()方法参数的错误理解:

private void addToMap(Integer key, UUID value) {
    map.computeIfAbsent(key, val -> new ArrayList<>()).add(value);
}

val -&gt; new ArrayList&lt;&gt;()中的参数与你传入addToMap()value无关!

如果您查看 Map.computeIfAbsent() 的 JavaDoc,您会发现第二个参数是 Function&lt;? super K,​? extends V&gt; - 即一个函数,它接受一个键并返回应该存储在映射中的任何内容。

最好把addToMap()方法写成

private void addToMap(Integer key, UUID value) {
    map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
}

请注意,toniedzwiedz 的回答很危险。它仅适用于具有大于或等于 0 的键的 Map&lt;Integer, ?&gt;

这很危险,因为它基本上将k -&gt; new ArrayList&lt;&gt;() 替换为k -&gt; new ArrayList&lt;&gt;(k) - 这恰好适用于具有Integer 键的地图,并使用键值来定义ArrayList 的初始容量。

如果k 为负数,它将不起作用(如果 k 为负数,new ArrayList&lt;&gt;(k) 将抛出 IllegalArgumentException)。

它也不适用于Map&lt;String, UUID&gt;,因为没有采用String 参数的ArrayList 构造函数。

【讨论】:

  • 使用ArrayList::new 不仅危险,因为当密钥为负数时它可能会失败并出现异常,它也可能看起来运行时没有立即可识别的问题,而是可怕的性能,until you realize something’s wrong...
猜你喜欢
  • 1970-01-01
  • 2011-06-23
  • 2013-11-15
  • 2023-03-28
  • 2014-07-09
  • 1970-01-01
  • 1970-01-01
  • 2019-01-24
  • 2023-01-26
相关资源
最近更新 更多