A Java cache example with Guava


Octocat Save up to a workweek a year by efficiently managing your coding bookmarks, aka #codingmarks, on www.codingmarks.org. Share your favorites with the community and they will be published weekly on Github. Help us build the programming-resources location - Star


Last week I showed you how to increase the performance of multiple java calls by making them asynchronous and parallel. This week we take a look at another potential performance booster, you should always keep in mind - caching.

Let’s imagine a scenario where you call a REST service and you know the returned values don’t change very often. In this case you really need to consider caching the response. We will use Guava’s provided caching capabilities to implement such a cache for this example.

Here is the piece of code that might do just that:

import org.codingpedia.example;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import javax.inject.Inject;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


public class GuavaCacheDemoService {

    static LoadingCache<String, ToDo> toDosCache = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .expireAfterAccess(60, TimeUnit.SECONDS)
            .build(
                    new CacheLoader<String, ToDo>() {
                        public ToDo load(String id) {
                               final ToDo toDo = restApiClient.getToDo(id);    
                               return toDo;
                        }
                    }
            );
    
    @Inject
    RestApiClient restApiClient;
    
    ToDo getToDo(String toDoId) throws ExecutionException {
        final ToDO toDo = toDosCache.get(toDoId);
        return toDo; 
    }
    
}

Notes:

  • you obtain a Cache by using the CacheBuilder builder pattern
  • our cache should not grow beyound 1000 entries - CacheBuilder.maximumSize(1000)
  • CacheBuilder.expireAfterAccess(60, TimeUnit.SECONDS) only expire entries after the 60 seconds have passed since the entry was last accessed by a read or a write
  • we use for caching a LoadingCache, which is a Cache built with an attached CacheLoader
    • to create a CacheLoader you just need to implementing the method V load(K key) throws Exception
    • inside the method’s body you would put the expensive method - here the REST call
  • to return the value associated with the key in the cache you need to use the V get(K key) throws ExecutionException method; in our case toDosCache.get(toDoId)
  • your ToDos might change every night - then you want to evict all entries from the cache by using Cache.invalidateAll()
  • Guava caches are local to a single run of your application. They do not store data in files, or on outside servers. If this does not fit your needs, consider a tool like Memcached.

I encourage you to read the Guava Caches Explained Guide to learn about other caching capabilities like writing to cache, using other eviction methods, explicit removals and so on.

Adrian Matei

Adrian Matei
Life force expressing itself as a coding capable human being

How I save a workweek a year by efficiently managing my codingmarks

Finding a desired link, you already visited, can be a tedious job and sometimes even frustrating. It normally takes 30 seconds or more to look for a link the traditional way, and I do that at least 20 times a day. With codingmarks.org it takes about 10 seconds, so I get a time saving of around 20 * 20 / 60 = 6.66 minutes a day. Over a year's time this translates to around 40+ hours of saved time. Continue reading

New codingmarks published in week 52 of 2018

Published on January 01, 2019