JAVA8的computeIfAbsent使用方法
基础说明
computeIfAbsent
是 Java 8 引入的 Map
接口中的一个默认方法。它允许你以原子操作的方式在给定键不存在时计算其值,并将其添加到映射中。如果该键已经存在,则返回已存在的值而不执行任何计算。
下面是 computeIfAbsent
的基本用法:
Map<K, V> map = new ConcurrentHashMap<>();
V value = map.computeIfAbsent(key, k -> {
// 只有当 key 对应的 value 不存在时,这段代码才会执行。
// 计算新的 value 值,通常这里会是一个可能较耗时的操作。
return computeExpensiveValue(k);
});
在这个例子中,computeExpensiveValue(k)
方法只会在 key
不在 map
中的时候调用。如果 key
已经存在,那么它将直接返回对应的值而不会执行提供的映射函数。
用法理解
computeIfAbsent
方法特别适用于缓存场景,尤其是在需要避免重复执行资源密集型操作的情况下。当一个键不在映射中时,使用 computeIfAbsent
可以确保只计算一次值,并将其存储在映射中供后续使用,从而提高性能和效率。
为了更好地说明这一点,让我们来看一个更详细的例子,其中包含了一个模拟的资源密集型操作,比如从数据库获取数据或进行复杂的计算:
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class ComputeIfAbsentCacheExample {
// 模拟的缓存
private static final Map<Integer, String> cache = new ConcurrentHashMap<>();
// 模拟的资源开销大的操作,例如查询数据库
private static String expensiveDatabaseQuery(Integer id) throws InterruptedException {
System.out.println("Executing expensive operation for ID: " + id);
// 模拟延迟
TimeUnit.SECONDS.sleep(2); // 假设需要2秒来完成这个昂贵的操作
return "Data for ID: " + id;
}
public static void main(String[] args) throws InterruptedException {
Integer key = 1;
// 第一次调用 computeIfAbsent,将执行昂贵的操作
long startTime = System.currentTimeMillis();
String data = cache.computeIfAbsent(key, ComputeIfAbsentCacheExample::expensiveDatabaseQuery);
System.out.println("Data: " + data);
System.out.println("Time taken: " + (System.currentTimeMillis() - startTime) + " ms");
// 第二次调用,由于值已经在缓存中,所以不会再次执行昂贵的操作
startTime = System.currentTimeMillis();
data = cache.computeIfAbsent(key, ComputeIfAbsentCacheExample::expensiveDatabaseQuery);
System.out.println("Data: " + data);
System.out.println("Time taken: " + (System.currentTimeMillis() - startTime) + " ms");
// 查看最终的映射内容
System.out.println("Final map content: " + cache);
}
}
在这个例子中,第一次调用 computeIfAbsent
会触发 expensiveDatabaseQuery
方法的执行,这可能是一个耗时的操作(如查询数据库)。但是,一旦结果被缓存,后续对该相同键的请求将直接从缓存中返回结果,而不会再次执行昂贵的操作,这样就显著提高了性能。