Java8使用Map中的computeIfAbsent方法构建本地缓存
2017-08-15 11:39
633 查看
一、概念及使用介绍
在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;
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));
// 构建多值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) {
return new HashSet<String>();
}
static String genValue2(String str) {
System.out.println("===");
return str + "2";
}
/**
* 普通的实现方式 普通方式使用大量的计算,存在性能问题. 并且计算量随着n的增加呈指数级增加,需要用到一些缓存策略,并且是线程安全的.
*
* @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的值,会自动调用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中的实现方式
* 在java7中,通过synchronized进行线程同步,检查缓存是否存在key对应的值,如果不存在才进行计算并放入缓存中
* 为了更好的性能,需要使用 double-checked locking,那样代码会更复杂
*
* @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;
}
}
三、程序运行结果
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}
原文链接:http://my.oschina.net/cloudcoder/blog/217775
在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;
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));
// 构建多值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) {
return new HashSet<String>();
}
static String genValue2(String str) {
System.out.println("===");
return str + "2";
}
/**
* 普通的实现方式 普通方式使用大量的计算,存在性能问题. 并且计算量随着n的增加呈指数级增加,需要用到一些缓存策略,并且是线程安全的.
*
* @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的值,会自动调用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中的实现方式
* 在java7中,通过synchronized进行线程同步,检查缓存是否存在key对应的值,如果不存在才进行计算并放入缓存中
* 为了更好的性能,需要使用 double-checked locking,那样代码会更复杂
*
* @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;
}
}
三、程序运行结果
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}
原文链接:http://my.oschina.net/cloudcoder/blog/217775
相关文章推荐
- Java8使用Map中的computeIfAbsent方法构建本地缓存
- java8 使用Map中的computeIfAbsent方法构建本地缓存,提高程序效率
- java8 Map中的computeIfAbsent方法
- Java中使用ResponseCache类构建本地缓存
- java代码之美(10)---Java8 Map中的computeIfAbsent方法
- Java开发工具IntelliJ IDEA本地历史记录的使用方法
- java中的map基本使用那几个方法(亲手试验过的)
- World Wind Java开发之八——加载本地缓存文件构建大范围三维场景
- Java中使用hql,sql查询--多表查询后的新实体构建方法详解
- Java中使用hql,sql查询--多表查询后的新实体构建方法详解
- Java代码优化-在某种情况下避免Map的containsKey方法的使用
- java中Map的使用方法
- 如何使用bloomfilter构建大型Java缓存系统
- 转:Java SoftReference 使用构建对象缓存
- java后台数据库同步使用map进行缓存
- 2015070304 - EffactiveJava笔记 - 第54条 谨慎使用本地方法
- android 针对于GridView中的getView方法的bug,使用本地缓存来处理图片显示的问题
- Java开发工具IntelliJ IDEA本地历史记录的使用方法
- 使用ngx_slowfs_cache模块构建本地缓存
- Java中使用hql,sql查询--多表查询后的新实体构建方法详解