美文网首页
Guava LoadingCache不能缓存null值

Guava LoadingCache不能缓存null值

作者: 木杉是谁 | 来源:发表于2020-02-08 09:55 被阅读0次

    测试的时候发现项目中的LoadingCache没有刷新,但是明明调用了refresh方法了。后来发现LoadingCache是不支持缓存null值的,如果load回调方法返回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触发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函数返回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不会触发load
            stringCache.invalidate("hello");
    
            // invalidate后,再次get,触发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触发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对象来封装结果:

    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();
        }
    }
    

    如果你的场景中认为null是不存在的,那么你可以在load函数中抛出异常,这个异常会通过get抛出。

    另外还有一个问题,如果是key==null呢?答案是直接抛出java.lang.NullPointerException。Guava对于null是很不待见的。

    参考资料

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

    相关文章

      网友评论

          本文标题:Guava LoadingCache不能缓存null值

          本文链接:https://www.haomeiwen.com/subject/kcnbxhtx.html