Guava的LoadingCache怎么不加null值?

How doesn't add null value to Guava's LoadingCache?

我必须使用 Guava 的 LoadingCache 将 xpath 表达式缓存到 xpath 值。

问题是不是所有的 xpath 都有值。大多数时候该值为 null.

代码片段:

private LoadingCache<String, List<String>> cachedXpaths = CacheBuilder.newBuilder()
        .expireAfterWrite(3, TimeUnit.MINUTES)
        .maximumSize(1000)
        .concurrencyLevel(5)
        .weakKeys()
        .build(new CacheLoader<String, List<String>>() {
            @Override
            public List<String> load(String key) throws Exception {
                return createListByKey(key);
            }
        });

private static List<String> createListByKey(String key) throws Exception {
    List<String> values = null;
    try {
        values = instance.getXpathValues(key);
    } catch (XPathExpressionException ignore) {
    }
    return values;
}

结果:

testEncounterSection(com.epam.cdatest.section.EncountersSectionTest)  Time elapsed: 0.002 sec  <<< FAILURE!
com.google.common.util.concurrent.UncheckedExecutionException: com.epam.cdatest.exceptions.XpathHasEmptyValueException
    at com.epam.cdatest.parsers.XpathEvaluator.getXpathValues(XpathEvaluator.java:123)
    at com.epam.cdatest.parsers.XpathEvaluator.createListByKey(XpathEvaluator.java:53)
    at com.epam.cdatest.parsers.XpathEvaluator.access[=11=]0(XpathEvaluator.java:32)
    at com.epam.cdatest.parsers.XpathEvaluator.load(XpathEvaluator.java:46)
    at com.epam.cdatest.parsers.XpathEvaluator.load(XpathEvaluator.java:43)

xpath值为空时如何避免调用load()

如果要区分空 List<String> 和空值,因为 LoadingCache 不支持空值,您可以使用 LoadingCache<String, Optional<List<String>>>:

private LoadingCache<String, Optional<List<String>>> cachedXpaths = CacheBuilder.newBuilder()
        .expireAfterWrite(3, TimeUnit.MINUTES)
        .maximumSize(1000)
        .concurrencyLevel(5)
        .weakKeys()
        .build(new CacheLoader<String, Optional<List<String>>>() {
            @Override
            public Optional<List<String>> load(String key) {
                try {
                    // If getXpathValues() can also return null, use fromNullable()
                    return Optional.of(instance.getXpathValues(key));
                } catch (XPathExpressionException | XpathHasEmptyValueException ignore) {
                    // Maybe log something here as well
                    return Optional.absent();
                }
            }
        });

更新:如果您不熟悉 Optional,这里有 Javadoc, a page in the Wiki,以及 Java 8 的所有文档,现在包括等效的 class.

TL;DR 它是一个包装器,可以测试其内容是否存在:

Optional<List<String>> optionalXpaths = cachedXpaths.getUnchecked(str);
if (optionalXpaths.isPresent()) {
    List<String> xpaths = optionalXpaths.get();
    // Do something with xpaths
}

或者(但更难看):

List<String> xpaths = cachedXpaths.getUnchecked(str).orNull();
if (xpaths != null) {
    // Do something with xpaths
}