Как не добавить нулевое значение в LoadingCache Guava?

Я должен использовать LoadingCache Guava для кэширования выражения xpath в значения xpath.

Проблема в том, что не все xpaths имеют значения. В большинстве случаев значение равно 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$000(XpathEvaluator.java:32)
    at com.epam.cdatest.parsers.XpathEvaluator$1.load(XpathEvaluator.java:46)
    at com.epam.cdatest.parsers.XpathEvaluator$1.load(XpathEvaluator.java:43)

Как избежать вызова load(), когда значение xpath пусто?


person catch23    schedule 16.06.2015    source источник
comment
Почему вы хотите избежать вызова load() вместо того, чтобы просто возвращать пустой список? На самом деле кеш не может знать, какие ключи не разрешены, и поэтому попытается загрузить хотя бы один раз. Затем загрузчик должен решить, что делать с ключами.   -  person Thomas    schedule 16.06.2015
comment
@Thomas, как пропустить этот пустой список? или как настроить кеш для удаления пустых списков в первую очередь?   -  person catch23    schedule 16.06.2015
comment
Он не пропускает вызов return values, но после этого кеш больше не будет загружать значение для данного ключа и всегда будет возвращать этот пустой список, что указывает на отсутствие значений xpath для этого ключа.   -  person Thomas    schedule 16.06.2015
comment
Если вам действительно не нужно различать незаконные и ничего там, я бы предложил вернуть пустой список в обоих случаях.   -  person maaartinus    schedule 16.06.2015
comment
@maaartinus Мне интересно узнать эффективность этого кеша, если значения для List‹String› пусты. Удаляет ли этот кеш его дальше по сравнению со списком, который имеет некоторые значения? Можете ли вы объяснить больше об этом?   -  person catch23    schedule 16.06.2015
comment
@nazar_art Он будет обрабатывать это точно так же, как и другие значения, которые могут быть или не быть тем, что вы хотите. Но я думаю, это правильно, поскольку нелегальные пути, вероятно, требуют примерно такого же времени обработки, как и легальные (измерьте, если вам это действительно важно).   -  person maaartinus    schedule 16.06.2015


Ответы (1)


Если вы хотите отличить пустой 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, страница в разделе Wiki, а также всю документацию по Java 8, которая теперь включает эквивалентный класс.

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
}
person Frank Pavageau    schedule 16.06.2015