如何使用咖啡因 getAll()? TL;DR:长版注意事项

如何解决如何使用咖啡因 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 getAll (Iterable extends K> keys,Function super Set extends K>,? extends Map extends K,? extends V>> mappingFunction)

让我们分解一下。

Map getAll

getAll 方法返回一个 Map,其键类型为 K,值类型为 V。如果您的缓存实现类似于:

Cache<String,Integer> cache = Caffeine.newBuilder().build();

然后K == StringV == Integer

该方法的第一个参数是:

可迭代扩展 K> 键

现在 Iterable 是一个 JDK 接口,几乎所有集合都实现了它。检查 this 以获取“已知”实现类。 问号实际上表示“任何扩展 K 的类型”(其中 K 在示例中是 String)

所以作为第一个参数,我们可以使用类似的东西:

List.of("one","two")

功能超级集扩展 K>,?扩展地图扩展 K,?扩展V>>

这可能看起来令人困惑,但如果您再次尝试分解它,则不会。函数是一个接口(只声明一个方法,因此是函数式的),它声明第一种类型,输入类型,第二种类型,返回类型。更多信息here

所以 ? super Set<? extends K> 是具有 Set 类型元素(在示例中也称为 String)的 K 超集的任何类型。为什么作者选择了 super 关键字?谷歌什么是“PECS”(生产者扩展,消费者超级)。

然后 ​? extends Map<? extends K,​? extends V> 就如您所想的那样,是 Map 的实现,其键类型为 K,值类型为 V(或整数)。>

注意事项

返回与键关联的值的映射,必要时创建或检索这些值。返回的映射包含已经缓存的条目,以及新加载的条目;它永远不会包含空键或值。

不言自明,但请注意,返回的地图将包含所有缓存值和 mappingFunction 的结果 - 没有 null 键/值

对尚未出现在缓存中的所有键执行对 mappingFunction 的单个请求

您的 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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?