Java8使用Map中的computeIfAbsent方法構建本地快取
阿新 • • 發佈:2019-02-11
一、概念及使用介紹
在JAVA8的Map介面中,增加了一個方法computeIfAbsent,此方法簽名如下:
- public V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
Map介面的實現類如HashMap,ConcurrentHashMap,HashTable等繼承了此方法,通過此方法可以構建JAVA本地快取,降低程式的計算量,程式的複雜度,使程式碼簡潔,易懂。
此方法首先判斷快取MAP中是否存在指定key的值,如果不存在,會自動呼叫mappingFunction(key)計算key的value,然後將key = value放入到快取Map,java8會使用thread-safe的方式從cache中存取記錄。
如果mappingFunction(key)返回的值為null或丟擲異常,則不會有記錄存入map
二、程式碼樣例
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Map;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.TimeUnit;
- publicclass Main {
- static Map<Integer, Integer> cache = new ConcurrentHashMap<>();
- publicstaticvoid main(String[] args) throws InterruptedException {
- cache.put(0, 0);
- cache.put(1, 1);
- // 普通方式
- System.out.println("Fibonacci(7) = " + fibonacci(7));
- // 採用java7的同步執行緒方式及java8的本地快取的方式
- System.out.println("FibonacciJava8(7) = " + fibonacciJava8(7));
- System.out.println("FibonacciJava7(7) = " + fibonacciJava7(7));
- // 構建多值Map樣例程式碼
- Map<String, HashSet<String>> map1 = new HashMap<>();
- map1.computeIfAbsent("fruits", k -> genValue(k)).add("apple");
- map1.computeIfAbsent("fruits", k -> genValue(k)).add("orange");
- map1.computeIfAbsent("fruits", k -> genValue(k)).add("pear");
- map1.computeIfAbsent("fruits", k -> genValue(k)).add("banana");
- map1.computeIfAbsent("fruits", k -> genValue(k)).add("water");
- System.out.println(map1);
- //測試多執行緒併發處理,是否同步操作
- Map<String, String> map2 = new ConcurrentHashMap<>();
- ExecutorService exec = Executors.newCachedThreadPool();
- for (int i = 0; i < 5; i++) {
- exec.execute(() -> {
- map2.computeIfAbsent("name", k -> genValue2(k));
- map2.computeIfAbsent("addr", k -> genValue2(k));
- map2.computeIfAbsent("email", k -> genValue2(k));
- map2.computeIfAbsent("mobile", k -> genValue2(k));
- });
- }
- exec.shutdown();
- exec.awaitTermination(1, TimeUnit.SECONDS);
- System.out.println(map2);
- }
- static HashSet<String> genValue(String str) {
- returnnew HashSet<String>();
- }
- static String genValue2(String str) {
- System.out.println("===");
- return str + "2";
- }
- /**
- * 普通的實現方式 普通方式使用大量的計算,存在效能問題. 並且計算量隨著n的增加呈指數級增加,需要用到一些快取策略,並且是執行緒安全的.
- *
- * @param n
- * @return
- */
- staticint fibonacci(int n) {
- if (n == 0 || n == 1)
- return n;
- System.out.println("calculating Fibonacci(" + n + ")");
- return fibonacci(n - 2) + fibonacci(n - 1);
- }
- /**
- * 採用java8的本地快取方式 如果快取MAP中不存在指定key的值,會自動呼叫mappingFunction(key)計算key的value
- * 然後將key = value放入到快取Map,java8會使用thread-safe的方式從cache中存取記錄
- *
- * @param n
- * @return
- */
- staticint fibonacciJava8(int n) {
- return cache.computeIfAbsent(n, (key) -> {
- System.out.println("calculating FibonacciJava8 " + n);
- return fibonacciJava8(n - 2) + fibonacciJava8(n - 1);
- });
- }
- /**
- * 在java7中的實現方式
- * 在java7中,通過synchronized進行執行緒同步,檢查快取是否存在key對應的值,如果不存在才進行計算並放入快取中
- * 為了更好的效能,需要使用 double-checked locking,那樣程式碼會更復雜
- *
- * @param n
- * @return
- */
- staticint fibonacciJava7(int n) {
- if (n == 0 || n == 1)
- return n;
- Integer result = cache.get(n);
- if (result == null) {
- synchronized (cache) {
- result = cache.get(n);
- if (result == null) {
- System.out.println("calculating FibonacciJava7(" + n + ")");
- result = fibonacciJava7(n - 2) + fibonacciJava7(n - 1);
- cache.put(n, result);
- }
- }
- }
- return result;
- }
- }
三、程式執行結果
- calculating Fibonacci(7)
- calculating Fibonacci(5)
- calculating Fibonacci(3)
- calculating Fibonacci(2)
- calculating Fibonacci(4)
- calculating Fibonacci(2)
- calculating Fibonacci(3)
- calculating Fibonacci(2)
- calculating Fibonacci(6)
- calculating Fibonacci(4)
- calculating Fibonacci(2)
- calculating Fibonacci(3)
- calculating Fibonacci(2)
- calculating Fibonacci(5)
- calculating Fibonacci(3)
- calculating Fibonacci(2)
- calculating Fibonacci(4)
- calculating Fibonacci(2)
- calculating Fibonacci(3)
- calculating Fibonacci(2)
- Fibonacci(7) = 13
- calculating FibonacciJava8 7
- calculating FibonacciJava8 5
- calculating FibonacciJava8 3
- calculating FibonacciJava8 2
- calculating FibonacciJava8 4
- calculating FibonacciJava8 6
- FibonacciJava8(7) = 13
- FibonacciJava7(7) = 13
- {fruits=[orange, banana, apple, pear, water]}
- ===
- ===
- ===
- ===
- {name=name2, mobile=mobile2, addr=addr2, email=email2}