I'm refactoring some code to use guava Cache.
Initial code:
public Post getPost(Integer key) throws SQLException, IOException { return PostsDB.findPostByID(key); }
In order not to break something I need to preserve any thrown exception as is, without wrapping it.
Current solution appears somewhat ugly:
public Post getPost(final Integer key) throws SQLException, IOException { try { return cache.get(key, new Callable<Post>() { @Override public Post call() throws Exception { return PostsDB.findPostByID(key); } }); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof SQLException) { throw (SQLException) cause; } else if (cause instanceof IOException) { throw (IOException) cause; } else if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } else { throw new IllegalStateException(e); } } }
Is there any possible way to make it nicer?
The Guava Cache is an incremental cache, in the sense that when you request an object from the cache, it checks to see if it already has the corresponding value for the supplied key. If it does, it simply returns it (assuming it hasn't expired).
Guava provides a very powerful memory based caching mechanism by an interface LoadingCache<K,V>. Values are automatically loaded in the cache and it provides many utility methods useful for caching needs.
Interface LoadingCache<K,V> A semi-persistent mapping from keys to values. Values are automatically loaded by the cache, and are stored in the cache until either evicted or manually invalidated. Implementations of this interface are expected to be thread-safe, and can be safely accessed by multiple concurrent threads.
Just after writing the question started thinking about utility method powered with generics. Then remembered something about Throwables. And yes, it's already there! )
It may also be necessary to handle UncheckedExecutionException or even ExecutionError.
So the solution is:
public Post getPost(final Integer key) throws SQLException, IOException { try { return cache.get(key, new Callable<Post>() { @Override public Post call() throws Exception { return PostsDB.findPostByID(key); } }); } catch (ExecutionException e) { Throwables.propagateIfPossible( e.getCause(), SQLException.class, IOException.class); throw new IllegalStateException(e); } catch (UncheckedExecutionException e) { Throwables.throwIfUnchecked(e.getCause()); throw new IllegalStateException(e); } }
Very nice!
See also ThrowablesExplained, LoadingCache.getUnchecked and Why we deprecated Throwables.propagate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With