更新值 在Java7时,对ConcurrentHashMap进行线程安全的更新操作需要使用循环来处理(可以参见http://blog.csdn.net/zero__007/article/details/49833819),但是在Java8中提供了更方便的原子更新方法。
1 2 3 public V compute (K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 对于指定key做remappingFunction函数调用,remappingFunction函数返回值即为新的value,如果返回值为null ,则从map中删除对应的key。compute返回key更新后的值(remappingFunction函数返回值)
1 2 3 4 public V computeIfAbsent (K key, Function<? super K, ? extends V> mappingFunction) 如果指定的key不存在,对该key做mappingFunction函数操作,mappingFunction函数返回值不为null ,则将对应的k-v放到map中,否则不操作。如果key不存在computeIfAbsent返回值同mappingFunction,如果key存在返回key对应的value(此时mappingFunction不会调用)。
1 2 3 public V computeIfPresent (K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) 类似与computeIfAbsent,仅对已经存在的key才计算新value。同样,如果remappingFunction返回值为null ,会删除对应的k-v。
compute示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public static void demo2 () { final Map<String, Integer> count = new ConcurrentHashMap <>(); final CountDownLatch endLatch = new CountDownLatch (2 ); count.put("b" , 4 ); Runnable task = new Runnable () { @Override public void run () { Integer oldValue, newValue; for (int i = 0 ; i < 50 ; i++) { count.compute("a" , new BiFunction <String, Integer, Integer>() { @Override public Integer apply (String k, Integer v) { return v == null ? 1 : v + 1 ; } }); } endLatch.countDown(); } }; new Thread (task).start(); new Thread (task).start(); try { endLatch.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println(count.compute("b" , (k, v) -> { System.out.println(k + " --- " + v); return null ; })); System.out.println(count.compute("a" , (k, v) -> v == null ? 1 : v + 1 )); System.out.println(count); }
运行结果:
1 2 3 4 b --- 4 null 101 {a=101}
还有一个新的操作merge:
1 2 3 4 public V merge (K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) 当key为尚未存在,直接插入对应value,remappingFunction不会被调用;否则,对oldValue与value做remappingFunction函数,结果作为新的newValue插入到map中。同样null 结果会删除对应的k-v。
merge与compute不同之处在于,若key不存在,merge传入的函数不会调用,而compute传入的函数会有调用。
注意:使用merge或则compute方法时,所传入的函数不应该进行大量的工作。当该函数运行时,其它一些更新映射的操作可能会被阻塞。当然,该函数也不应该更新映射的其它部分。
批量数据操作: search 会对每个键和(或)值应用一个函数,直到该函数返回一个非null的结果,然后search会终止并返回该函数的结果。
reduce会通过提供的累计函数,将所有的键和(或)值组合起来。
forEach会对所有的键和(或)值应用一个函数。
具体的函数如下:
1 2 3 4 searchKeys/reduceKeys/forEachkey searchValues/reduceValues/forEachValue search/reduce/forEach searchEntries/reduceEntries/forEachEntry
在使用这几个操作时需要指定一个并行阈值。如果希望操作在一个线程中,使用Long.MAX_VALUE作为阈值。
示例:
找到第一个出现次数超过1000的单词,需要搜索键和值:
1 String result = map.search(threshold, (k, v) -> v > 1000 ? k : null );
遍历所有键和值:
1 map.forEach(threshold, (k , v) -> sout(k + “ - ” + v));
或则可以接收一个转换/过滤函数:
1 2 3 4 Map.forEach(threshold, (k, v) -> v > 1000 ? k + “ - ” + v, null , System.out::println);