How handle cache misses: NotFoundException, contains() or `if (null == result)`?

coding-style, java

Solution

The first is excessive I think and not a good use for exceptions. Do you have an expectation that there will be a cache hit? A cache miss is a fairly normal occurrence I would think and thus an exception becomes simply flow control. Not good imho.

The second is a race condition. There is a time delay between checking on the existence of the cache entry and querying it. That could lead to all sorts of trouble.

Returning null is probably appropriate in the general sense but that comes with some qualifications.

Firstly, what type of cache is it? Ideally you'd be talking to a read-through cache in which case if it's not in the cache it'll simply get it from the source, which is not the style of code you've written there.

Secondly, the get then insert is another race condition. Look at the interface for `ConcurrentHashMap` for a good general way of dealing with this kind of thing. Most notably, the `putIfAbsent()` call is an atomic operation that does the equivalent of you're third call.

Problem

Maybe this is slightly academic, but if I implement a cache for speeding up an application, how should I best handle cache misses? (In my case, the language would be Java, but maybe the answer can be more general.) Throw an exception: ``` ResultType res; try { res = Cache.resLookup(someKey); } catch (NotFoundException e) { res = Cache.resInsert(someKey, SlowDataSource.resLookup(someKey)); } ``` Ask before fetch: ``` ResultType res; if (Cache.contains(someKey) { res = Cache.resLookup(someKey); } else { res = Cache.resInsert(someKey, SlowDataSource.resLookup(someKey)); } ``` Return null: ``` ResultType res; res = Cache.resLookup(someKey); if (null == res) { res = Cache.resInsert(someKey, SlowDataSource.resLookup(someKey)); } ``` Throwing an Exception seems wrong, after all, this isn't an error. Letting the Cache do a look up for contains() and then again to retrieve the data seems wasteful, especially as this would occur every time. And checking for `null` of course requires that `null` can never be a valid result...

Original source