I’m using the MapMaker to implement caching of data objects in my application:
public class DataObjectCache<DO extends MyDataObject> {
private final ConcurrentMap<String, DO> innerCache;
public DataObjectCache(Class<DO> doClass) {
Function<String, DO> loadFunction = new Function<String, DO>() {
@Override
public DO apply(String id) {
//load and return DO instance
}
};
innerCache = new MapMaker()
.softValues()
.makeComputingMap(loadFunction);
}
private DO getDataObject(String id) {
return innerCache.get(id);
}
private void putDataObject(DO dataObject) {
innerCache.putIfAbsent(dataObject.getID(), dataObject);
}
}
One of these DataObjectCaches would be instantiated for each data object class, and they would be kept in a master Map, using the Class objects as keys.
There’s a minority of data object classes whose instances I don’t want cached. However I would still like them to be instantiated by the same code, which the Function is calling, and would still need concurrency in regard to loading them distinctly.
In these cases, I’m wondering if I can just set the maximum size of the map to 0, so that entries are evicted immediately, but still take advantage of the atomic computing aspects of the map. Is this a good idea? Inefficient?
EDIT:
I realized that if I evicted entries immediately after loading them, there’s no way to guarantee they are distinctly loaded – if the Map isn’t keeping track of them, multiple instances of an object with the same ID could be floating around the environment. So instead of doing this, I think I’ll use weak values instead of soft values for the types of objects I don’t want taking up cache – let me know if anyone has an opinion on this.
In light of your edit, it sounds like what you’re looking for is an interner. An interner returns a representative instance; the same object will be returned by
Interner.internfor all objects that are equal according to yourequalsmethod. From the Javadoc:See http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Interner.html and http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Interners.html
That said, it depends what you mean when you say you don’t want it cached. If you truly want to return a fresh instance every time, then you’d have to have multiple instances of equivalent objects “floating around”.
Interning is holding on to an instance (so it can return the same one), so it is still sort of a cache. I would want to know why you want to avoid caching. If it is because of the size of the objects, you can use a weak interner; the instance will be available for GC when it’s no longer referenced. Then again, simply using a
MapMakermap with weak values would accomplish that as well.If, on the other hand, the reason you don’t want to cache is because your data is liable to change, interning could be your answer. I would imagine what you’d want is to retrieve the object every time, and then intern it. If the object is equal to the cached one, the interner would simply return the existing instance. If it is different, the interner would cache the new one. Your responsibility then would be to write an
equalsmethod on your object that meets the requirements for using a new vs interned instance.