使用Guava MapMaker / CacheBuilder处理空值

时间:2011-11-28 15:39:27

标签: java guava

我尝试使用MapMaker / CacheBuilder创建缓存,但我不明白如何正确处理空值。

 ConcurrentMap<Key, Graph> graphs = new MapMaker()
       .concurrencyLevel(4)
       .weakKeys()
       .maximumSize(10000)
       .expireAfterWrite(10, TimeUnit.MINUTES)
       .makeComputingMap(
           new Function<Key, Graph>() {
             public Graph apply(Key key) {
               return createExpensiveGraph(key);
             }
           });

如果createExpensiveGraph方法返回null值,则抛出NullpointerException。 我不明白为什么ComputingConcurrentHashMap会抛出一个NPE而不是只返回一个空值。

如何妥善处理?只是捕获NPE并返回null? 我错过了什么吗?

3 个答案:

答案 0 :(得分:47)

Guava试图强迫您尽可能避免使用null,因为null存在的不正确或无证件行为会导致大量混淆和错误。我认为尽可能避免使用空值绝对是一个好主意,如果你可以修改你的代码使它不使用null,我强烈推荐这种方法。

您的问题的答案关键取决于“null”值在您的应用程序中实际意味着什么。最有可能的是,这意味着这个密钥“没有价值”,或“没有任何东西”。在这种情况下,最好的选择是使用Optional,使用Optional。并使用Optional.absent()而不是null包含非空值。如果必须将其转换为null或非null值,则可以使用Optional.orNull()

答案 1 :(得分:11)

请注意,即使在您的问题的完整陈述中,您仍然不清楚您的意图是否要缓存该空值。无论CacheBuilder是否决定缓存空值,它都会让许多预期相反的用户感到惊讶。再次,null会产生歧义(这就是它最擅长的!)。

所以这就是你做的。

  1. 在没有createExpensiveGraph的全部费用的情况下,是否可以确定答案为“空”?即,真的只是一个简单的前提条件检查吗?如果是这样,你应该在询问缓存之前这样做,此时是否应该缓存结果的问题就会消失。

  2. 您要缓存空值吗?然后按照路易斯的建议使用Optional<T>

  3. 否则,缓存无法完成为密钥召唤正确值的工作,相应的响应是从缓存加载器中抛出异常(如果这是程序员错误,则取消选中,否则检查)。这将提供您想要的行为。如果您抛出已检查的例外情况,请确保您在另一方使用的是Cache.get,而不是Cache.getUnchecked

答案 2 :(得分:9)

请参阅Guava wiki上的LivingWithNullHostileCollections以获取有关如何处理此问题的一些想法。