ConcurrentMap

ConcurrentMap接口继承自Map接口,并定义了最实用的并发集合类型之一。Java8通过将新的方法添加到这个接口,引入了函数式编程。

在下面的代码中,我们使用这个映射示例来展示那些新的方法:

ConcurrentMap<String, String> map = new ConcurrentHashMap<>();
map.put("foo", "bar");
map.put("han", "solo");
map.put("r2", "d2");
map.put("c3", "p0");

forEach()方法接受类型为BiConsumer的lambda表达式,以映射的键和值作为参数传递。它可以作为for-each循环的替代,来遍历并发映射中的元素。迭代在当前线程上串行执行。

map.forEach((key, value) -> System.out.printf("%s = %s\n", key, value));

新方法putIfAbsent()只在提供的键不存在时,将新的值添加到映射中。至少在ConcurrentHashMap的实现中,这一方法像put()一样是线程安全的,所以你在不同线程中并发访问映射时,不需要任何同步机制。

String value = map.putIfAbsent("c3", "p1");
System.out.println(value);    // p0

getOrDefault()方法返回指定键的值。在传入的键不存在时,会返回默认值:

String value = map.getOrDefault("hi", "there");
System.out.println(value);    // there

replaceAll()接受类型为BiFunction的lambda表达式。BiFunction接受两个参数并返回一个值。函数在这里以每个元素的键和值调用,并返回要映射到当前键的新值。

map.replaceAll((key, value) -> "r2".equals(key) ? "d3" : value);
System.out.println(map.get("r2"));    // d3

compute()允许我们转换单个元素,而不是替换映射中的所有值。这个方法接受需要处理的键,和用于指定值的转换的BiFunction

map.compute("foo", (key, value) -> value + value);
System.out.println(map.get("foo"));   // barbar

除了compute()之外还有两个变体:computeIfAbsent()computeIfPresent()。这些方法的函数式参数只在键不存在或存在时被调用。

最后,merge()方法可以用于以映射中的现有值来统一新的值。这个方法接受键、需要并入现有元素的新值,以及指定两个值的合并行为的BiFunction

map.merge("foo", "boo", (oldVal, newVal) -> newVal + " was " + oldVal);
System.out.println(map.get("foo"));   // boo was foo