Java8使用Map中的computeIfAbsent方法構(gòu)建本地緩存
作者:cloud-coder
java8在接口Map中增加了computeIfAbsent方法,可以通過此方法構(gòu)建本地緩存,降低程序的計算量,程序的復(fù)雜度,使代碼簡潔,易懂。
一、概念及使用介紹
在JAVA8的Map接口中,增加了一個方法computeIfAbsent,此方法簽名如下:
- public V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
Map接口的實現(xiàn)類如HashMap,ConcurrentHashMap,HashTable等繼承了此方法,通過此方法可以構(gòu)建JAVA本地緩存,降低程序的計算量,程序的復(fù)雜度,使代碼簡潔,易懂。
此方法首先判斷緩存MAP中是否存在指定key的值,如果不存在,會自動調(diào)用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;
- public class Main {
- static Map<Integer, Integer> cache = new ConcurrentHashMap<>();
- public static void 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));
- // 構(gòu)建多值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);
- //測試多線程并發(fā)處理,是否同步操作
- 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) {
- return new HashSet<String>();
- }
- static String genValue2(String str) {
- System.out.println("===");
- return str + "2";
- }
- /**
- * 普通的實現(xiàn)方式 普通方式使用大量的計算,存在性能問題. 并且計算量隨著n的增加呈指數(shù)級增加,需要用到一些緩存策略,并且是線程安全的.
- *
- * @param n
- * @return
- */
- static int 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的值,會自動調(diào)用mappingFunction(key)計算key的value
- * 然后將key = value放入到緩存Map,java8會使用thread-safe的方式從cache中存取記錄
- *
- * @param n
- * @return
- */
- static int fibonacciJava8(int n) {
- return cache.computeIfAbsent(n, (key) -> {
- System.out.println("calculating FibonacciJava8 " + n);
- return fibonacciJava8(n - 2) + fibonacciJava8(n - 1);
- });
- }
- /**
- * 在java7中的實現(xiàn)方式
- * 在java7中,通過synchronized進行線程同步,檢查緩存是否存在key對應(yīng)的值,如果不存在才進行計算并放入緩存中
- * 為了更好的性能,需要使用 double-checked locking,那樣代碼會更復(fù)雜
- *
- * @param n
- * @return
- */
- static int 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;
- }
- }
三、程序運行結(jié)果
- 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}
責(zé)任編輯:林師授
來源:
oschina