使用Guava MapMaker / CacheBuilder处理空值
我尝试使用MapMaker / CacheBuilder创建缓存,但我不明白如何正确处理空值。
ConcurrentMap graphs = new MapMaker() .concurrencyLevel(4) .weakKeys() .maximumSize(10000) .expireAfterWrite(10, TimeUnit.MINUTES) .makeComputingMap( new Function() { public Graph apply(Key key) { return createExpensiveGraph(key); } });
如果createExpensiveGraph方法返回null值,则抛出NullpointerException。 我不明白为什么ComputingConcurrentHashMap会抛出一个NPE而不是只返回一个空值。
如何妥善处理? 只是捕获NPE并返回null? 我错过了什么吗?
Guava试图强迫你尽可能避免使用null
,因为在null
存在的情况下不正确或未记录的行为会导致大量的混淆和错误。 我认为尽可能避免使用空值绝对是一个好主意,如果你可以修改你的代码使它不使用null
,我强烈推荐这种方法。
您的问题的答案关键取决于“null”值在您的应用程序中实际意味着什么。 最有可能的是,这意味着这个密钥“没有价值”,或“没有任何东西”。 在这种情况下,您最好的选择是使用Optional
,使用Optional
.of包装非空值并使用Optional.absent()
而不是null
。 如果必须将其转换为null或非null值,则可以使用Optional.orNull()
。
请注意,即使在您的问题的完整陈述中,您仍然不清楚您的意图是否要缓存该空值。 无论CacheBuilder是否决定缓存空值,它都会让许多预期相反的用户感到惊讶。 再一次, null
会产生歧义(这就是它最擅长的!)。
所以这就是你做的。
-
如果没有
createExpensiveGraph
的全部费用,是否可以确定答案是“null”? 即,真的只是一个简单的前提条件检查吗? 如果是这样,你应该在询问缓存之前这样做,此时是否应该缓存结果的问题就会消失。 -
要缓存空值吗? 然后按照路易斯的建议使用
Optional
。 -
否则,缓存无法完成为密钥召唤正确值的工作,并且相应的响应是从缓存加载器中抛出exception(如果这是程序员错误,则取消选中,否则检查)。 这将提供您想要的行为。 如果抛出已检查的exception,请确保在另一侧使用
Cache.get
,而不是Cache.getUnchecked
。
请参阅Guava wiki上的LivingWithNullHostileCollections ,了解如何处理此问题。