Lambdas和putIfAbsent

Old*_*eon 7 java lambda java-8

我在这里发布了一个答案,其中代码演示了如何使用read putIfAbsent方法ConcurrentMap:

ConcurrentMap<String, AtomicLong> map = new ConcurrentHashMap<String, AtomicLong> ();

public long addTo(String key, long value) {
  // The final value it became.
  long result = value;
  // Make a new one to put in the map.
  AtomicLong newValue = new AtomicLong(value);
  // Insert my new one or get me the old one.
  AtomicLong oldValue = map.putIfAbsent(key, newValue);
  // Was it already there? Note the deliberate use of '!='.
  if ( oldValue != newValue ) {
    // Update it.
    result = oldValue.addAndGet(value);
  }
  return result;
}
Run Code Online (Sandbox Code Playgroud)

这种方法的主要缺点是你必须创建一个新的对象,无论它是否被使用,都要放入地图中.如果物体很重,这可能会产生很大的影响.

在我看来,这将是一个使用Lambdas的机会.我没有下载Java 8或者我能够直到它是官方的(公司政策)所以我不能测试这个但这样的东西是否有效且有效?

public long addTo(String key, long value) {
  return map.putIfAbsent( key, () -> new AtomicLong(0) ).addAndGet(value);
}
Run Code Online (Sandbox Code Playgroud)

我希望使用lambda来延迟new AtomicLong(0)对它的评估,直到实际确定它应该被创建,因为它在地图中不存在.

正如您所看到的,这更加简洁和实用.

基本上我认为我的问题是:

  1. 这会有用吗?
  2. 还是我完全曲解了lambdas?
  3. 有一天可能会有这样的工作吗?

Stu*_*rks 7

更新2015-08-01

computeIfAbsent确实已将下面描述的方法添加到Java SE 8中.语义似乎非常接近预发布版本.

此外,computeIfAbsent还有一大堆新的默认方法,已添加到Map界面中.当然,地图通常不支持原子更新,但新方法为API增加了相当大的便利.


你想要做的是非常合理的,但不幸的是它不适用于当前版本的ConcurrentMap.然而,一项改进正在进行中.新版本的并发库包含ConcurrentHashMapV8一个包含新方法的新版本computeIfAbsent.这几乎可以让你完全按照自己的意愿去做.使用这种新方法,您的示例可以重写如下:

public long addTo(String key, long value) {
    return map.computeIfAbsent( key, () -> new AtomicLong(0) ).addAndGet(value);
}
Run Code Online (Sandbox Code Playgroud)

有关的更多信息ConcurrentHashMapV8,请参阅Doug Lea 在并发兴趣邮件列表上的初始公告主题.线程下面的几条消息是一条后续消息,显示的示例与您尝试的内容非常相似.(不过请注意老lambda语法.这消息是从2011年8月后所有.)这里是最近的javadocConcurrentHashMapV8.

这项工作旨在集成到Java 8中,但我还没有看到它.此外,这仍然是一项正在进行中的工作,名称和规格可能会发生变化等.