如何解决如何使用咖啡因 getAll()? TL;DR:长版注意事项
标题非常简单,我正在尝试为我的 minecraft 插件使用咖啡因缓存,但我似乎找不到任何关于 cache.getAll()
的好例子。 documentation 也无济于事。我看到的只有<
、>
和?
。我真的认为文档应该提供示例。所以我要问的是是否有人可以提供一个例子
解决方法
实际上使用文档您应该能够理解它期望作为参数的内容。作者做得非常好。如果你不这样做,我建议你阅读 Java 泛型并理解语法。
TL;DR:
Cache<String,Integer> cache = Caffeine.newBuilder().build();
cache.getAll(List.of("one","two","three"),keys -> {
Map<String,Integer> result = new HashMap<>();
keys.forEach(key -> {
if (key.equals("one")) result.put(key,1);
else if (key.equals("two")) result.put(key,2);
else if (key.equals("three")) result.put(key,3);
});
return result;
});
这个例子在功能方面可能没有多大意义,但它是一个例子。
长版
文档有一个方法签名:
Map 让我们分解一下。 Map 然后 该方法的第一个参数是: 可迭代扩展 K> 键 现在 所以作为第一个参数,我们可以使用类似的东西: 功能超级集扩展 K>,?扩展地图扩展 K,?扩展V>> 这可能看起来令人困惑,但如果您再次尝试分解它,则不会。函数是一个接口(只声明一个方法,因此是函数式的),它声明第一种类型,输入类型,第二种类型,返回类型。更多信息here。 所以 然后 返回与键关联的值的映射,必要时创建或检索这些值。返回的映射包含已经缓存的条目,以及新加载的条目;它永远不会包含空键或值。 不言自明,但请注意,返回的地图将包含所有缓存值和 对尚未出现在缓存中的所有键执行对 mappingFunction 的单个请求 您的 同样不言自明,getAll
方法返回一个 Map,其键类型为 K
,值类型为 V
。如果您的缓存实现类似于:Cache<String,Integer> cache = Caffeine.newBuilder().build();
K == String
和V == Integer
Iterable
是一个 JDK 接口,几乎所有集合都实现了它。检查 this 以获取“已知”实现类。
问号实际上表示“任何扩展 K
的类型”(其中 K
在示例中是 String)List.of("one","two")
? super Set<? extends K>
是具有 Set
类型元素(在示例中也称为 String)的 K
超集的任何类型。为什么作者选择了 super
关键字?谷歌什么是“PECS”(生产者扩展,消费者超级)。? extends Map<? extends K,? extends V>
就如您所想的那样,是 Map
的实现,其键类型为 K
,值类型为 V
(或整数)。>
注意事项
mappingFunction
的结果 - 没有 null
键/值mappingFunction
将仅被调用一次,其中包含已请求但未在缓存中找到的所有键的列表。mappingFunction
返回的所有条目都将存储在缓存中,覆盖任何先前缓存的值mappingFunction
返回的地图将替换或存储在缓存中
user-guide 提供了此功能的简单示例。 getAll
方法适用于所有类型的缓存。
同步缓存
在这个抽象中,调用者将阻塞等待加载完成
Cache<Key,Graph> cache = Caffeine.newBuilder().build();
cache.put(k1,v1);
// Loads k2 & k3 (uses k1)
Map<Key,Graph> graphs = cache.getAll(Set.of(k1,k2,k3),keys -> createExpensiveGraphs(keys));
如果您希望将调用者与加载函数分离,则创建一个 LoadingCache
。如果提供的 CacheLoader
没有实现批量功能,那么它将回退到一对一加载。
LoadingCache<Key,Graph> cache = Caffeine.newBuilder()
.build(CacheLoader.bulk(keys -> createExpensiveGraphs(keys)));
Map<Key,Graph> graphs = cache.getAll(keys);
请注意,在此抽象中,加载是非阻塞的。如果 getAll
正在检索 k2
并且阻塞 get(k2)
同时发生,则两个加载都将在进行中。当 getAll
完成时,它将覆盖现有值。这种行为是因为我们无法在 ConcurrentHashMap
计算方法中锁定多个条目,但如果使用 AsyncCache
,则可以解决该问题。
异步缓存
在此抽象中,缓存存储到 CompletableFuture
的映射并将其返回给调用者。您可以使用包装为异步的同步函数进行调用,也可以使用直接返回期货的异步函数。
AsyncCache<Key,Graph> cache = Caffeine.newBuilder().buildAsync();
CompletableFuture<Map<Key,Graph>> graphs1 = cache.getAll(Set.of(k1,keys -> createExpensiveGraphs(keys));
CompletableFuture<Map<Key,Graph>> graphs2 = cache.getAll(Set.of(k1,(keys,executor) -> createExpensiveGraphFutures(keys));
可以使用 AsyncLoadingCache
对调用者隐藏加载逻辑。
AsyncLoadingCache<Key,Graph> cache = Caffeine.newBuilder()
.build(AsyncCacheLoader.bulk(keys -> createExpensiveGraphs(keys)));
CompletableFuture<Map<Key,Graph>> graphs = cache.getAll(keys);
在此抽象中,getAll
将阻止对同一密钥的后续 get
调用。这是因为底层映射保存了一个进行中的未来条目,因此在批量操作完成时插入并完成占位符。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。