Guava LoadingCache不能緩存null值

測試的時候發(fā)現(xiàn)項目中的LoadingCache沒有刷新,但是明明調(diào)用了refresh方法了。后來發(fā)現(xiàn)LoadingCache是不支持緩存null值的,如果load回調(diào)方法返回null,則在get的時候會拋出異常。

通過幾個例子開看這個問題:

public void test_loadNull() {
    LoadingCache<String, String> stringCache = CacheBuilder.newBuilder()
            .maximumSize(10)
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String s) throws Exception {
                    System.out.println("xx");
                    if (s.equals("hello"))
                        return "world";
                    else
                        return null;
                }
            });

    try {
        System.out.println(stringCache.get("hello"));

        // get觸發(fā)load,load返回null則拋出異常:
        // com.google.common.cache.CacheLoader$InvalidCacheLoadException: CacheLoader returned null for key other_key.
        System.out.println(stringCache.get("other_key"));
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}
public void test_loadNullWhenRefresh() {
    LoadingCache<String, String> stringCache = CacheBuilder.newBuilder()
            .maximumSize(10)
            .build(new CacheLoader<String, String>() {
                int i = 0;

                @Override
                public String load(String s) throws Exception {
                    if (i == 0) {
                        i++;
                        return "world";
                    }
                    return null;
                }
            });

    try {
        System.out.println(stringCache.get("hello"));
        System.out.println(stringCache.get("hello"));

        // refresh的時候,如果load函數(shù)返回null,則refresh拋出異常:
        // Exception thrown during refresh
        // com.google.common.cache.CacheLoader$InvalidCacheLoadException: CacheLoader returned null for key hello.
        stringCache.refresh("hello");

        System.out.println(stringCache.get("hello"));
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}
public void test_loadNullAfterInvalidate() {
    LoadingCache<String, String> stringCache = CacheBuilder.newBuilder()
            .maximumSize(10)
            .build(new CacheLoader<String, String>() {
                int i = 0;

                @Override
                public String load(String s) throws Exception {
                    if (i == 0) {
                        i++;
                        return "world";
                    }
                    return null;
                }
            });

    try {
        System.out.println(stringCache.get("hello"));
        System.out.println(stringCache.get("hello"));

        // invalidate不會觸發(fā)load
        stringCache.invalidate("hello");

        // invalidate后,再次get,觸發(fā)load,拋出異常:
        // com.google.common.cache.CacheLoader$InvalidCacheLoadException: CacheLoader returned null for key hello.
        System.out.println(stringCache.get("hello"));
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}
public void test_loadThrowException() {
    LoadingCache<String, String> stringCache = CacheBuilder.newBuilder()
            .maximumSize(10)
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String s) throws Exception {
                    if (s.equals("hello"))
                        return "world";
                    else
                        throw new IllegalArgumentException("only_hello");
                }
            });

    try {
        System.out.println(stringCache.get("hello"));

        // get觸發(fā)load,load拋出異常,get也會拋出封裝后的異常:
        // com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalArgumentException: only_hello
        System.out.println(stringCache.get("other_key"));
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

所以如果你需要緩存“空”值,推薦的做法是使用Optional對象來封裝結(jié)果:

public void test_loadUseOptional() {
    LoadingCache<String, Optional<String>> stringCache = CacheBuilder.newBuilder()
            .maximumSize(10)
            .build(new CacheLoader<String, Optional<String>>() {
                @Override
                public Optional<String> load(String s) throws Exception {
                    if (s.equals("hello"))
                        return Optional.of("world");
                    else
                        return Optional.absent();
                }
            });

    try {
        Optional<String> hello = stringCache.get("hello");
        if(hello.isPresent()) {
            System.out.println(hello.get());
        }

        Optional<String> otherKey = stringCache.get("other_key");
        if(otherKey.isPresent()){
            System.out.println(otherKey.get());
        }
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
}

如果你的場景中認(rèn)為null是不存在的,那么你可以在load函數(shù)中拋出異常,這個異常會通過get拋出。

另外還有一個問題,如果是key==null呢?答案是直接拋出java.lang.NullPointerException。Guava對于null是很不待見的。

參考資料

本文獨立博客地址:Guava LoadingCache不能緩存null值 | 木杉的博客

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 使用場景 緩存在很多場景下都是相當(dāng)有用的。例如,計算或檢索一個值的代價很高,并且對同樣的輸入需要不止一次獲取值的時...
    jiangmo閱讀 857評論 0 3
  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,920評論 0 13
  • 緩存 范例 適用性 緩存在很多場景下都是相當(dāng)有用的。例如,計算或檢索一個值的代價很高,并且對同樣的輸入需要不止一次...
    小雞在路上閱讀 3,419評論 0 2
  • 緩存在應(yīng)用中是必不可少的,經(jīng)常用的如redis、memcache以及內(nèi)存緩存等。Guava是Google出的一個工...
    timothyue1閱讀 1,689評論 1 1
  • 原文 使用Guava cache構(gòu)建本地緩存 - sameLuo的個人空間 - OSCHINA Guava Cac...
    OoLukeoO閱讀 6,751評論 0 3

友情鏈接更多精彩內(nèi)容