如何使用咖啡因 getAll()?
How to use caffeine getAll()?
标题非常简单,我正在尝试为我的 Minecraft 插件使用咖啡因缓存,但我似乎找不到 cache.getAll()
的任何好的示例。 documentation 也无济于事。我只看到 <
、>
和 ?
。我真的认为文档应该提供示例。所以我想问的是是否有人可以提供一个例子
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
的映射和 returns 到调用者的映射。您可以使用包装为异步的同步函数调用,也可以使用直接 returns 期货的异步函数。
AsyncCache<Key, Graph> cache = Caffeine.newBuilder().buildAsync();
CompletableFuture<Map<Key, Graph>> graphs1 = cache.getAll(Set.of(k1, k2, k3),
keys -> createExpensiveGraphs(keys));
CompletableFuture<Map<Key, Graph>> graphs2 = cache.getAll(Set.of(k1, k2, k3),
(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
调用。这是由于底层映射包含一个正在运行的未来条目,因此占位符会在批量操作完成时插入并完成。
实际使用文档你应该能够理解它期望的参数。作者做得很好。如果你不这样做,我建议你阅读 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<K,V> getAll(Iterable<? extends K> keys, Function<? super Set<? extends K>,? extends Map<? extends K,? extends V>> mappingFunction)
我们来分解一下。
Map<K,V> getAll
getAll
方法 return 是一个具有 K
类型键和 V
类型值的映射。如果您的缓存实现类似于:
Cache<String, Integer> cache = Caffeine.newBuilder().build();
然后 K == String
和 V == Integer
该方法的第一个参数是:
Iterable<? extends K> keys
现在 Iterable
是一个 JDK 接口,几乎所有的集合都实现了它。检查 this 是否“已知”实施 类。
问号实际上表示“扩展 K
的任何类型”(示例中 K
是字符串)
所以作为第一个参数,我们可以使用类似的东西:
List.of("one", "two")
Function<? super Set<? extends K>,? extends Map<? extends K,? extends V>>
这可能看起来令人困惑,但如果您尝试再次分解它就不会了。函数是一个接口(仅声明一个方法,因此是函数式的),它声明为第一种类型,输入类型和第二种类型,return 类型。更多信息 here.
所以 ? super Set<? extends K>
是 Set
的超集的任何类型,其元素类型为 K
(在示例中也称为 String)。为什么作者选择 super
关键字? Google "PECS" 是什么(生产者扩展,消费者超级)。
然后 ? extends Map<? extends K,? extends V>
正如您所想的那样,是 Map
的一个实现,其键类型为 K
,值类型为 V
(或整数)。
备注
Returns a map of the values associated with the keys, creating or retrieving those values if necessary. The returned map contains entries that were already cached, combined with the newly loaded entries; it will never contain null keys or values.
不言自明,但请注意,returned 地图将包含所有缓存值和您的 mappingFunction
的结果 - 没有 null
keys/values
A single request to the mappingFunction is performed for all keys which are not already present in the cache
您的 mappingFunction
将只被调用一次,其中包含已请求但未在缓存中找到的所有键的列表。
All entries returned by mappingFunction
will be stored in the cache, over-writing any previously cached values
同样不言自明,mappingFunction
return 将替换或存储在缓存中的地图
标题非常简单,我正在尝试为我的 Minecraft 插件使用咖啡因缓存,但我似乎找不到 cache.getAll()
的任何好的示例。 documentation 也无济于事。我只看到 <
、>
和 ?
。我真的认为文档应该提供示例。所以我想问的是是否有人可以提供一个例子
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
的映射和 returns 到调用者的映射。您可以使用包装为异步的同步函数调用,也可以使用直接 returns 期货的异步函数。
AsyncCache<Key, Graph> cache = Caffeine.newBuilder().buildAsync();
CompletableFuture<Map<Key, Graph>> graphs1 = cache.getAll(Set.of(k1, k2, k3),
keys -> createExpensiveGraphs(keys));
CompletableFuture<Map<Key, Graph>> graphs2 = cache.getAll(Set.of(k1, k2, k3),
(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
调用。这是由于底层映射包含一个正在运行的未来条目,因此占位符会在批量操作完成时插入并完成。
实际使用文档你应该能够理解它期望的参数。作者做得很好。如果你不这样做,我建议你阅读 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<K,V> getAll(Iterable<? extends K> keys, Function<? super Set<? extends K>,? extends Map<? extends K,? extends V>> mappingFunction)
我们来分解一下。
Map<K,V> getAll
getAll
方法 return 是一个具有 K
类型键和 V
类型值的映射。如果您的缓存实现类似于:
Cache<String, Integer> cache = Caffeine.newBuilder().build();
然后 K == String
和 V == Integer
该方法的第一个参数是:
Iterable<? extends K> keys
现在 Iterable
是一个 JDK 接口,几乎所有的集合都实现了它。检查 this 是否“已知”实施 类。
问号实际上表示“扩展 K
的任何类型”(示例中 K
是字符串)
所以作为第一个参数,我们可以使用类似的东西:
List.of("one", "two")
Function<? super Set<? extends K>,? extends Map<? extends K,? extends V>>
这可能看起来令人困惑,但如果您尝试再次分解它就不会了。函数是一个接口(仅声明一个方法,因此是函数式的),它声明为第一种类型,输入类型和第二种类型,return 类型。更多信息 here.
所以 ? super Set<? extends K>
是 Set
的超集的任何类型,其元素类型为 K
(在示例中也称为 String)。为什么作者选择 super
关键字? Google "PECS" 是什么(生产者扩展,消费者超级)。
然后 ? extends Map<? extends K,? extends V>
正如您所想的那样,是 Map
的一个实现,其键类型为 K
,值类型为 V
(或整数)。
备注
Returns a map of the values associated with the keys, creating or retrieving those values if necessary. The returned map contains entries that were already cached, combined with the newly loaded entries; it will never contain null keys or values.
不言自明,但请注意,returned 地图将包含所有缓存值和您的 mappingFunction
的结果 - 没有 null
keys/values
A single request to the mappingFunction is performed for all keys which are not already present in the cache
您的 mappingFunction
将只被调用一次,其中包含已请求但未在缓存中找到的所有键的列表。
All entries returned by
mappingFunction
will be stored in the cache, over-writing any previously cached values
同样不言自明,mappingFunction
return 将替换或存储在缓存中的地图