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

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...

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.

The last option (if null == result) is best, in my opinion.
A cache miss is not an exceptional condition, and should be handled in the normal code flow.
And if the action of checking if something exists in the cache may be a somewhat expensive operation (e.g. the network overhead of a memcached call), it shouldn't be a separate operation. Also, the value of contains() may change before you actually retrieve the item, if the cache is shared among threads.

What about a 4th option? You could use a holder for the return value, and have the lookup return a boolean for success:
ResultHolder result = new ResultHolder();
if(!cache.resLookup(someKey, result))
{
// get from slower source and insert to cache
}
if(result.value == null)
{
// special case if you wanted null as a valid value
}
This is basically your third option, keeping a single call, but if you wanted to have null as a value you could.

I would tend towards a checked exception, since you can't inadvertently ignore it and accidently return a null. I'm assuming (unlike most people here) that a cache miss is an unusual scenario.
I also assume you're talking about the cache internal implementation. From the client perspective this should be invisible.

Since you are speeding up an existing api via caching the invisible one (2nd one) would apply. I say this as I'm assuming that the api exists and you're not prematurely optimising.

(3) looks like the easiest to read and most performant (even though the actual difference in performance between these alternatives is problably neglible).
With (2) you have to make two lookups in the cache (first "contains" and then "resLookup").
With (1) you create an additional object, the code gets more complicated and harder to read, and a cache miss isn't a exceptional case.

From a 'clear code' perspective
A cache-miss is not an exception but a normal case. So I'd not use an Exception here.
null-values should be avoided when ever possible. Choose something meaningful instead
This leaves option 'ask before fetch' or a variation of your third option, where you don't return 'null' but a special ResultType object that signals a cache-miss
Example:
public class ResultType {
public final static ResultType CACHE_MISS = new ResultType();
// ... rest of the class implementation
}
and later on
ResultType res;
res = Cache.resLookup(someKey);
if (ResultType.CACHE_MISS == res) {
res = Cache.resInsert(someKey, SlowDataSource.resLookup(someKey));
}
Advantage over 'null' solution: the reader now immediatly knows that is 'if' handles a cache miss.

Related

reliably forcing Guava map eviction to take place

EDIT: I've reorganized this question to reflect the new information that since became available.
This question is based on the responses to a question by Viliam concerning Guava Maps' use of lazy eviction: Laziness of eviction in Guava's maps
Please read this question and its response first, but essentially the conclusion is that Guava maps do not asynchronously calculate and enforce eviction. Given the following map:
ConcurrentMap<String, MyObject> cache = new MapMaker()
.expireAfterAccess(10, TimeUnit.MINUTES)
.makeMap();
Once ten minutes has passed following access to an entry, it will still not be evicted until the map is "touched" again. Known ways to do this include the usual accessors - get() and put() and containsKey().
The first part of my question [solved]: what other calls cause the map to be "touched"? Specifically, does anyone know if size() falls into this category?
The reason for wondering this is that I've implemented a scheduled task to occasionally nudge the Guava map I'm using for caching, using this simple method:
public static void nudgeEviction() {
cache.containsKey("");
}
However I'm also using cache.size() to programmatically report the number of objects contained in the map, as a way to confirm this strategy is working. But I haven't been able to see a difference from these reports, and now I'm wondering if size() also causes eviction to take place.
Answer: So Mark has pointed out that in release 9, eviction is invoked only by the get(), put(), and replace() methods, which would explain why I wasn't seeing an effect for containsKey(). This will apparently change with the next version of guava which is set for release soon, but unfortunately my project's release is set sooner.
This puts me in an interesting predicament. Normally I could still touch the map by calling get(""), but I'm actually using a computing map:
ConcurrentMap<String, MyObject> cache = new MapMaker()
.expireAfterAccess(10, TimeUnit.MINUTES)
.makeComputingMap(loadFunction);
where loadFunction loads the MyObject corresponding to the key from a database. It's starting to look like I have no easy way of forcing eviction until r10. But even being able to reliably force eviction is put into doubt by the second part of my question:
The second part of my question [solved]: In reaction to one of the responses to the linked question, does touching the map reliably evict all expired entries? In the linked answer, Niraj Tolia indicates otherwise, saying eviction is potentially only processed in batches, which would mean multiple calls to touch the map might be needed to ensure all expired objects were evicted. He did not elaborate, however this seems related to the map being split into segments based on concurrency level. Assuming I used r10, in which a containsKey("") does invoke eviction, would this then be for the entire map, or only for one of the segments?
Answer: maaartinus has addressed this part of the question:
Beware that containsKey and other reading methods only run postReadCleanup, which does nothing but on each 64th invocation (see DRAIN_THRESHOLD). Moreover, it looks like all cleanup methods work with single Segment only.
So it looks like calling containsKey("") wouldn't be a viable fix, even in r10. This reduces my question to the title: How can I reliably force eviction to occur?
Note: Part of the reason my web app is noticeably affected by this issue is that when I implemented caching I decided to use multiple maps - one for each class of my data objects. So with this issue there is the possibility that one area of code is executed, causing a bunch of Foo objects to be cached, and then the Foo cache isn't touched again for a long time so it doesn't evict anything. Meanwhile Bar and Baz objects are being cached from other areas of code, and memory is being eaten. I'm setting a maximum size on these maps, but this is a flimsy safeguard at best (I'm assuming its effect is immediate - still need to confirm this).
UPDATE 1: Thanks to Darren for linking the relevant issues - they now have my votes. So it looks like a resolution is in the pipeline, but seems unlikely to be in r10. In the meantime, my question remains.
UPDATE 2: At this point I'm just waiting for a Guava team member to give feedback on the hack maaartinus and I put together (see answers below).
LAST UPDATE: feedback received!
I just added the method Cache.cleanUp() to Guava. Once you migrate from MapMaker to CacheBuilder you can use that to force eviction.
I was wondering the about the same issue you described in the first part of your question. From what I can tell from looking at the source code for Guava's CustomConcurrentHashMap (release 9), it appears that entries are evicted on the get(), put(), and replace() methods. The containsKey() method does not appear to invoke eviction. I'm not 100% sure because I took a quick pass at the code.
Update:
I also found a more recent version of the CustomConcurrentHashmap in Guava's git repository and it looks like containsKey() has been updated to invoke eviction.
Both release 9 and the latest version I just found do not invoke eviction when size() is called.
Update 2:
I recently noticed that Guava r10 (yet to be released) has a new class called CacheBuilder. Basically this class is a forked version of the MapMaker but with caching in mind. The documentation suggests that it will support some of the eviction requirements you are looking for.
I reviewed the updated code in r10's version of the CustomConcurrentHashMap and found what looks like a scheduled map cleaner. Unfortunately, that code appears unfinished at this point but r10 looks more and more promising each day.
Beware that containsKey and other reading methods only run postReadCleanup, which does nothing but on each 64th invocation (see DRAIN_THRESHOLD). Moreover, it looks like all cleanup methods work with single Segment only.
The easiest way to enforce eviction seems to be to put some dummy object into each segment. For this to work, you'd need to analyze CustomConcurrentHashMap.hash(Object), which is surely no good idea, as this method may change anytime. Moreover, depending on the key class it may be hard to find a key with a hashCode ensuring it lands in a given segment.
You could use reads instead, but would have to repeat them 64 times per segment. Here, it'd easy to find a key with an appropriate hashCode, since here any object is allowed as an argument.
Maybe you could hack into the CustomConcurrentHashMap source code instead, it could be as trivial as
public void runCleanup() {
final Segment<K, V>[] segments = this.segments;
for (int i = 0; i < segments.length; ++i) {
segments[i].runCleanup();
}
}
but I wouldn't do it without a lot of testing and/or an OK by a guava team member.
Yep, we've gone back and forth a few times on whether these cleanup tasks should be done on a background thread (or pool), or should be done on user threads. If they were done on a background thread, this would eventually happen automatically; as it is, it'll only happen as each segment gets used. We're still trying to come up with the right approach here - I wouldn't be surprised to see this change in some future release, but I also can't promise anything or even make a credible guess as to how it will change. Still, you've presented a reasonable use case for some kind of background or user-triggered cleanup.
Your hack is reasonable, as long as you keep in mind that it's a hack, and liable to break (possibly in subtle ways) in future releases. As you can see in the source, Segment.runCleanup() calls runLockedCleanup and runUnlockedCleanup: runLockedCleanup() will have no effect if it can't lock the segment, but if it can't lock the segment it's because some other thread has the segment locked, and that other thread can be expected to call runLockedCleanup as part of its operation.
Also, in r10, there's CacheBuilder/Cache, analogous to MapMaker/Map. Cache is the preferred approach for many current users of makeComputingMap. It uses a separate CustomConcurrentHashMap, in the common.cache package; depending on your needs, you may want your GuavaEvictionHacker to work with both. (The mechanism is the same, but they're different Classes and therefore different Methods.)
I'm not a big fan of hacking into or forking external code until absolutely necessary. This problem occurs in part due to an early decision for MapMaker to fork ConcurrentHashMap, thereby dragging in a lot of complexity that could have been deferred until after the algorithms were worked out. By patching above MapMaker, the code is robust to library changes so that you can remove your workaround on your own schedule.
An easy approach is to use a priority queue of weak reference tasks and a dedicated thread. This has the drawback of creating many stale no-op tasks, which can become excessive in due to the O(lg n) insertion penalty. It works reasonably well for small, less frequently used caches. It was the original approach taken by MapMaker and its simple to write your own decorator.
A more robust choice is to mirror the lock amortization model with a single expiration queue. The head of the queue can be volatile so that a read can always peek to determine if it has expired. This allows all reads to trigger an expiration and an optional clean-up thread to check regularly.
By far the simplest is to use #concurrencyLevel(1) to force MapMaker to use a single segment. This reduces the write concurrency, but most caches are read heavy so the loss is minimal. The original hack to nudge the map with a dummy key would then work fine. This would be my preferred approach, but the other two options are okay if you have high write loads.
I don't know if it is appropriate for your use case, but your main concern about the lack of background cache eviction seems to be memory consumption, so I would have thought that using softValues() on the MapMaker to allow the Garbage Collector to reclaim entries from the cache when a low memory situation occurs. Could easily be the solution for you. I have used this on a subscription-server (ATOM) where entries are served through a Guava cache using SoftReferences for values.
Based on maaartinus's answer, I came up with the following code which uses reflection rather than directly modifying the source (If you find this useful please upvote his answer!). While it will come at a performance penalty for using reflection, the difference should be negligible since I'll run it about once every 20 minutes for each caching Map (I'm also caching the dynamic lookups in the static block which will help). I have done some initial testing and it appears to work as intended:
public class GuavaEvictionHacker {
//Class objects necessary for reflection on Guava classes - see Guava docs for info
private static final Class<?> computingMapAdapterClass;
private static final Class<?> nullConcurrentMapClass;
private static final Class<?> nullComputingConcurrentMapClass;
private static final Class<?> customConcurrentHashMapClass;
private static final Class<?> computingConcurrentHashMapClass;
private static final Class<?> segmentClass;
//MapMaker$ComputingMapAdapter#cache points to the wrapped CustomConcurrentHashMap
private static final Field cacheField;
//CustomConcurrentHashMap#segments points to the array of Segments (map partitions)
private static final Field segmentsField;
//CustomConcurrentHashMap$Segment#runCleanup() enforces eviction on the calling Segment
private static final Method runCleanupMethod;
static {
try {
//look up Classes
computingMapAdapterClass = Class.forName("com.google.common.collect.MapMaker$ComputingMapAdapter");
nullConcurrentMapClass = Class.forName("com.google.common.collect.MapMaker$NullConcurrentMap");
nullComputingConcurrentMapClass = Class.forName("com.google.common.collect.MapMaker$NullComputingConcurrentMap");
customConcurrentHashMapClass = Class.forName("com.google.common.collect.CustomConcurrentHashMap");
computingConcurrentHashMapClass = Class.forName("com.google.common.collect.ComputingConcurrentHashMap");
segmentClass = Class.forName("com.google.common.collect.CustomConcurrentHashMap$Segment");
//look up Fields and set accessible
cacheField = computingMapAdapterClass.getDeclaredField("cache");
segmentsField = customConcurrentHashMapClass.getDeclaredField("segments");
cacheField.setAccessible(true);
segmentsField.setAccessible(true);
//look up the cleanup Method and set accessible
runCleanupMethod = segmentClass.getDeclaredMethod("runCleanup");
runCleanupMethod.setAccessible(true);
}
catch (ClassNotFoundException cnfe) {
throw new RuntimeException("ClassNotFoundException thrown in GuavaEvictionHacker static initialization block.", cnfe);
}
catch (NoSuchFieldException nsfe) {
throw new RuntimeException("NoSuchFieldException thrown in GuavaEvictionHacker static initialization block.", nsfe);
}
catch (NoSuchMethodException nsme) {
throw new RuntimeException("NoSuchMethodException thrown in GuavaEvictionHacker static initialization block.", nsme);
}
}
/**
* Forces eviction to take place on the provided Guava Map. The Map must be an instance
* of either {#code CustomConcurrentHashMap} or {#code MapMaker$ComputingMapAdapter}.
*
* #param guavaMap the Guava Map to force eviction on.
*/
public static void forceEvictionOnGuavaMap(ConcurrentMap<?, ?> guavaMap) {
try {
//we need to get the CustomConcurrentHashMap instance
Object customConcurrentHashMap;
//get the type of what was passed in
Class<?> guavaMapClass = guavaMap.getClass();
//if it's a CustomConcurrentHashMap we have what we need
if (guavaMapClass == customConcurrentHashMapClass) {
customConcurrentHashMap = guavaMap;
}
//if it's a NullConcurrentMap (auto-evictor), return early
else if (guavaMapClass == nullConcurrentMapClass) {
return;
}
//if it's a computing map we need to pull the instance from the adapter's "cache" field
else if (guavaMapClass == computingMapAdapterClass) {
customConcurrentHashMap = cacheField.get(guavaMap);
//get the type of what we pulled out
Class<?> innerCacheClass = customConcurrentHashMap.getClass();
//if it's a NullComputingConcurrentMap (auto-evictor), return early
if (innerCacheClass == nullComputingConcurrentMapClass) {
return;
}
//otherwise make sure it's a ComputingConcurrentHashMap - error if it isn't
else if (innerCacheClass != computingConcurrentHashMapClass) {
throw new IllegalArgumentException("Provided ComputingMapAdapter's inner cache was an unexpected type: " + innerCacheClass);
}
}
//error for anything else passed in
else {
throw new IllegalArgumentException("Provided ConcurrentMap was not an expected Guava Map: " + guavaMapClass);
}
//pull the array of Segments out of the CustomConcurrentHashMap instance
Object[] segments = (Object[])segmentsField.get(customConcurrentHashMap);
//loop over them and invoke the cleanup method on each one
for (Object segment : segments) {
runCleanupMethod.invoke(segment);
}
}
catch (IllegalAccessException iae) {
throw new RuntimeException(iae);
}
catch (InvocationTargetException ite) {
throw new RuntimeException(ite.getCause());
}
}
}
I'm looking for feedback on whether this approach is advisable as a stopgap until the issue is resolved in a Guava release, particularly from members of the Guava team when they get a minute.
EDIT: updated the solution to allow for auto-evicting maps (NullConcurrentMap or NullComputingConcurrentMap residing in a ComputingMapAdapter). This turned out to be necessary in my case, since I'm calling this method on all of my maps and a few of them are auto-evictors.

What is an alternative to exceptions for flow control?

I inherited a java application that processes requests and throws an exception if it determines a request should be cancelled. Exceptions have been convenient for the previous developer because they are an easy way to exit out of a tree of logic that no longer applies (yes a goto) and it prints a stack trace to the log which is good info to have. It seems to be the consenus on forums and blogs that exceptions should not be used for flow control and over half of the requests processed are cancelled, so they're definitely not exceptional situations. One argument is performance, which doesn't apply because our exception-ful code has run fast enough for years. Another argument is that the goto-ness of it is not clear, which I agree with. My question is: What is the alternative. The only thing I can think of is to have every method return true if processing should continue or false if it shouldn't. This seems like it would hugely bloat my code changing this:
checkSomething();
checkSomethingElse();
into this:
boolean continueProcessing = false;
continueProcessing = checkSomething();
if (!continueProcessing) {
return false;
}
continueProcessing = checkSomethingElse();
if (!continueProcessing) {
return false;
}
And then what if the method is supposed to return something? Any guidance would be great. I'd really like to observe whatever "best practices" are available.
Update:
Another bit I probably should have mentioned in the first place is that a request is cancelled more than 50% of the time and does not mean something didn't go right, it means the request wasn't needed after all.
In your scenario, the alternatives are throwing an exception and returning a result.
Which is best (and which is "best practice") depends on whether the failure of the "check..." methods should be classed as normal or exceptional. To some degree this is a judgement call that you have to make. In making that call there are a couple of things to bear in mind:
Creating + throwing + catching an exception is roughly 3 orders of magnitude SLOWER than testing a boolean result.
The big problem with returning status codes is that it is easy to forget to test them.
In summary, best practice is to not use exceptions to implement normal flow control, but it is up to you to decide where the borderline between normal and exceptional is.
Without seeing the real code / context, my gut feeling is that this is likely to be an appropriate place to use exceptions.
See How slow are Java exceptions? for a great discussion on this topic.
tl;dr
Separation of Concerns, and IMO you should do this:
continue = checkSomething() && checkSomethingElse();
or perhaps there are other design problems in the code.
What's the concern of the function -- as you want to define it (this can be a subjective question)? If the error fits into the function's concern, then don't throw an exception. If you are confused about whether or not the error fits into the concern, then perhaps the function is trying to accomplish too many concerns on its own (bad design).
Error control options:
don't report error. It either is handled directly by function or doesn't matter enough
return value is
null instead of an object
the error information (perhaps even a different data type than the object returned on success).
an argument passed in will be used to store error data.
trigger an event
call a closure passed to function if an error occurs.
throw an exception. (I'm arguing this should usually only be done if it's not a part of the arbitrarily defined purpose of the function)
If the purpose of the code is to check some state, then knowing that the state is false is directly the point of the function. Don't throw an exception, but return false.
That's what it looks like you are wanting. You have process X which is running checkers Y and Z. Control flow for process X (or any calling process) is not the same concern as checking states of a system.
How about
if (!checkSomething()) return false;
if (!checkSomethingElse()) return false;
No need for the flag if you exit early.
int error = 0;
do
{//try-alt
error = operation_1(); if(error > 0){break;}
error = operation_2(); if(error > 0){break;}
error = operation_3(); if(error > 0){break;}
}while(false);
switch(error) //catch-alt
{
case 1: handle(1); break;
case 2: handle(2); break;
case 3: handle(3); break;
}

Java dead code elimination... is this code at risk of being optimized out?

So, I'm using an API which is a little unfriendly in certain ways. Basically, this API creates a resource which can be fetched later. This resource may or may not still exist when we go to fetch it later.
To fetch the previously created resource, you have to use a result guid like so:
String resultKey = "12345";
PersistedResult r = mFactory.getPersistedResult(resultKey);
Now, the tricky thing here is that getPersistedResult does NOT throw an exception when called with an invalid guid... PersistedResult is a lazy loader and will only fail when one of its methods is called (causing the object to load itself).
So, to try and determine whether or not the resource is valid, I'm doing the following:
PersistedResult r = null;
if (!StringUtils.isEmpty(resultKey)) {
try {
r = mFactory.getPersistedResult(resultKey);
r.getResultCount(); // Triggers exception if result key was invalid.
} catch (Exception e) {
// handle exception
}
}
Is my call to getResultCount at risk of being optimized out because I'm not using the value?
Calling any method on PersistedResult goes to an external database, just in case that matters.
Thanks
The compiler can't assume that getResultCount() has no side-effects -- therefore it can't remove the call.
No, why would it be? Either getResultCount won't be inlined, in which case it's a black box and has to be executed because it can do anything, or it will get inlined, in which case the compiler can see that it could potentially throw an exception, and will perform that action.
The fact that it has a return value doesn't matter. If that was a factor, then any function of any complexity would be at risk of getting optimized out if the caller doesn't check its return value.
Optimizations at runtime (or compile time, same) are not allowed to give you different results than it would be when nothing is optimized (apart from runtime or memory savings). If here your exception is not thrown because of optimization, this is definitively another behavior, and thus would be a bug.
(Note than in multithreaded environments this is a bit relaxed when concerning the relations between different threads.)
No. Because optimize cannot change semantic of code.

How to avoid lots of checks for null when using get() on a Java Collection?

I have a statement as follows
getLD().get(cam.getName()).getAGS().get(aG.getName())
getLD(), getAGS() return Java collections
I would not consider it to be an error if getAGS() were empty, nor if the result of getAGS().get(aG.getName()) were empty. However it is rather messy and somewhat of a pain checking for these null conditions.
e.g. if(getLD().get(camp.getName()).getAGS() !=null && getLD().get(cam.getName()).getAGS().get(aG.getName()) != null) {
Can anyone suggest the best way to deal with this? Obviously I could create a variable x = getLD().get(camp.getName()).getAGS() to shorten the code, but is there a way in which I would not have to do the two checks for null?
All help is much appreciated!
IMO, the best strategy is to design your data structures so that there aren't any nulls in the first place. For example, use empty collections or zero length arrays, or "" instead of null. For application classes, consider implementing special instance that you can use instead of null.
A second strategy is to replace use of exposed generic data structures (e.g. maps, lists, arrays) with custom classes. This hides the implementation details inside a class, and allows you to make use of Java's static typing to avoid many of the situations where a null check would be required.
A third strategy is to create a helper class with a bunch of methods that implement common operations; e.g. "get the Cam for an LD". (IMO, this approach is a poor alternative, compared with the others, but at least it reduces the amount of code repetition.)
To the extent that you cannot get rid of the nulls, you've got no option but to explicitly test for them. (There was a proposal to add an "elvis" operator to Java 7 as part of project Coin, but unfortunately it was cut.)
The best way would be to avoid the chain. If you aren't familiar with the Law of Demeter (LoD), in my opinion you should. You've given a perfect example of a message chain that is overly intimate with classes that it has no business knowing anything about.
Law of Demeter: http://en.wikipedia.org/wiki/Law_of_Demeter
The apache commons project has a library called Bean Introspection Utilities (BeanUtils), which looks like it can do what you need. Check out the nested property access section, in the user guide, and look at the BeanUtils class:
http://commons.apache.org/beanutils/
It has utility classes that I think can do what you need.
Another thing to consider: you should try to avoid doing this many levels of nested property access. This is a code smell called "feature envy", where an object wants to use features of another object regularly. Consider creating methods on the top-level object, or find a way to redesign so that the feature you need is shared more readily.
try {
foo().bar().baz();
} catch (NullPointerException e) {
// Check if it was actually an error
}
Code in groovy!.
Not always possible depending on your environment and performance requirments. But its a joy to just type
if (getLD(camp?.GetName())?.getAGS(ag?.GetName()))
Alternativly you could just code what you mean and catch the null pointer exception. In your case this would be much more readable especially of you dont care which element is null.
I think Something is more complext than needed if you require to do
getLD().get(cam.getName()).getAGS().get(aG.getName())
If you need to check if the second collection or the result is null you can do something like:
Map<?,?> firstList= getLD();
Object value = null;
if (firstList!=null && !firstList.isEmpty() && fistList.containsKey(cam.getName())){
Map<?,?> secondList = firstList.get(cam.getName());
if (secondList!=null && !secondList.isEmpty() && secondList.containsKey(aG.getName())){
value = secondList.get(aG.getName());
}
}
if(value != null){
// Do the required operations if the value is not null
}else{
// Do the required operations if the value is null
}
With this code i checked if the first collection is not null, is not empty and if it has the content. The i get the second collection and i repeated the process in the second collection.
Also a method can be created to do this operation:
private Map<?,?> getItem(Map<?,?> map,Object key){
if (map!=null && !map.isEmpty() && map.containsKey(key)){
return map.get(key);
}
return null;
}
and in your code:
Object value = getItem(getItem(getLD(),cam.getName()),aG.getName());
if(value != null){
// Do the required operations if the value is not null
}else{
// Do the required operations if the value is null
}

Which is better/more efficient: check for bad values or catch Exceptions in Java

Which is more efficient in Java: to check for bad values to prevent exceptions or let the exceptions happen and catch them?
Here are two blocks of sample code to illustrate this difference:
void doSomething(type value1) {
ResultType result = genericError;
if (value1 == badvalue || value1 == badvalue2 || ...) {
result = specificError;
} else {
DoSomeActionThatFailsIfValue1IsBad(value1);
// ...
result = success;
}
callback(result);
}
versus
void doSomething(type value1) {
ResultType result = genericError;
try {
DoSomeActionThatFailsIfValue1IsBad(value1);
// ...
result = success;
} catch (ExceptionType e) {
result = specificError;
} finally {
callback(result);
}
}
On the one hand, you're always doing a comparison. On the other hand, I honestly don't know what the internals of the system do to generate an exception, throw it, and then trigger the catch clause. It has the sound of being less efficient, but if it doesn't add overhead in the non-error case, then it's more efficient, on average. Which is it? Does it add similar checking anyway? Is that checking there in the implicit code added for exception handling, even with the additional layer of explicit checking? Perhaps it always depends on the type of exception? What am I not considering?
Let's also assume that all "bad values" are known -- that's an obvious issue. If you don't know all the bad values -- or the list is too long and not regular -- then exception handling may be the only way, anyway.
So, what are the pros and cons of each, and why?
Side questions to consider:
How does your answer change if the value is "bad" (would throw an exception) most of the time?
How much of this would depend on the specifics of the VM in use?
If this same question was asked for language-X, would the answer be different? (Which, more generally, is asking if it can be assumed checking values is always more efficient than relying on exception handling simply because it adds more overhead by current compilers/interpreters.)
(New) The act of throwing an exception is slow. Does entering a try block have overhead, even if an exception is not thrown?
Similarities on SO:
This is similar to the code sample in this answer, but states they are similar only in concept, not compiled reality.
The premise is similar to this question but, in my case, the requester of the task (e.g. "Something") isn't the caller of the method (e.g. "doSomething") (thus no returns).
And this one is very similar, but I didn't find an answer to my question.
And similar to far too many other questions to list, except:
I'm not asking about theoretical best practice. I'm asking more about runtime performance and efficiency (which should mean, for specific cases, there are non-opinion answers), especially on resource limited platforms. For instance, if the only bad value was simply a null object, would it be better/more efficient to check for that or just attempt to use it and catch the exception?
"How does your answer change if the value is "bad" (would throw an exception) most of the time?" I think that's the key right there. Exceptions are expensive as compared to comparisons, so you really want to use exceptions for exceptional conditions.
Similarly, your question about how this answer might change depending on the language/environment ties into that: The expense of exceptions is different in different environments. .Net 1.1 and 2.0 are incredibly slow the first time an exception is thrown, for instance.
Purely from an efficiency standpoint, and given your code examples, I think it depends on how often you expect to see bad values. If bad values are not too uncommon, it's faster to do the comparison because exceptions are expensive. If bad values are very rare, however, it may be faster to use the exception.
The bottom line, though, is that if you're looking for performance, profile your code. This block of code may not even be a concern. If it is, then try it both ways and see which is faster. Again, it depends on how often you expect to see bad values.
I could find surprisingly little current information about the cost of throwing Exceptions. Pretty obviously there must be some, you are creating an object, and probably getting stack trace information.
In the specific example you talk about:
if (value1 == badvalue || value1 == badvalue2 || ...) {
result = specificError;
} else {
DoSomeActionThatFailsIfValue1IsBad(value1);
// ...
result = success;
}
The problem for me here is that you are in danger if (probably incompletely) replicating logic in the caller that should be owned by the method you are calling.
Hence I would not perform those checks. Your code is not performing an experiment, it does "know" the data it's supposed to be sending down I suppose? Hence the likelyhood of the Exception being thrown should be low. Hence keep it simple, let the callee do the checks.
In my opinion you should have try/catch blocks around anything that could potentially throw exceptions, if only to have a safe running system. You have finer control of error responses if you check for possible data errors fist. So I suggest doing both.
Well, exceptions are more expensive, yes but for me, its about weighting the cost of efficiency vs bad design. unless your use case demands it, always stick to the best design.
the question really is, when do you throw an exception? in exceptional situations.
if your arguments are not in the range that you're looking for, i'd suggest returning an error code or a boolean.
for instance, a method,
public int IsAuthenticated(String username, String password)
{
if(!Validated(username,password)
{
// just an error
// log it
return -2;
}
// contacting the Database here
if cannot connect to db
{
// woww this is HUUGE
throw new DBException('cannot connect'); // or something like that
}
// validate against db here
if validated, return 0;
// etc etc
}
thats my 2 cents
My personal opinion is that exceptions indicate that something is broken - this might well be an API called with illegal arguments or division by zero or file not found etc. This means that exceptions could be thrown by checking values.
For the reader of your code - again my personal opinion - it is much easier to follow the flow if you can be certain that it is not put aside by all kinds of strange throws (which is essentially gotos in disguise if used as part of the program flow). You simply have less to think about.
This is in my opinion a good thing. "Smart" code is hard to wrap your head around.
On a side note - JVM's get much much smarter - coding for efficiency usually doesn't pay off.
Normally, one would assume that try-catch is more expensive because it looks heavier in the code, but that entirely depends on the JIT. My guess is that it's impossible to tell without having a real case and some performance measurements. The comparisons could be more expensive, especially when you have many values, for example, or because you have to call equals() since == won't work in many cases.
As for which one you should chose (as in "code style"), my answer is: Make sure that the user gets a useful error message when it fails. Anything else is a matter of taste and I can't give you rules for that.
To be safe, assume exceptions are expensive. They often are, and if they aren't it will at least push you towards using exceptions wisely. (Entering a try block is usually trivially cheap, since implementors do their best to make it so, even at the cost of making exceptions more expensive. After all, if exceptions are used properly, the code will enter the try block many times more often than it will throw.)
More importantly, exceptions are a style issue. Exceptions for exceptional conditions make code simpler because there's less error-checking code, so the actual functionality is clearer and more compact.
However, if exceptions might be thrown in more normal circumstances, there's invisible flows of control that the reader has to keep in mind, comparable to Intercal's COME FROM...UNLESS... statement. (Intercal was one of the very early joke languages.) This is very confusing, and can easily lead to misreading and misunderstanding the code.
My advice, which applies to every language and environment I know about:
Don't worry about efficiency here. There are strong reasons besides efficiency for using exceptions in a way that will prove efficient.
Use try blocks freely.
Use exceptions for exceptional conditions. If an exception is likely, test for it and handle it in another way.
a question like this is like asking,
"is it more efficient to write an interface or a base class with all abstract functions"
does it matter which is more efficient? only one of them is the right way for a given situation
Note that if your code doesn't throw exceptions then it doesn't always imply that the input is within bounds. Relying on throwing exceptions by the standard Java (API + JVM), such as NullPointerException or ArrayIndexOutOfBoundsExceptions is a very unhealthy way to validate input. Garbage-in sometimes generates garbage-but-no-exception-out.
And yes, exceptions are quite expensive. They should not be thrown during a normal processing flow.
Optimizationally, I think you're going to find it's probably a wash. They'll both perform alright, I don't think exception throwing is ever going to be your bottleneck. You should probably be more concerned with what Java is designed to do (and what other Java programmers will expect) and that is thrown exceptions. Java is very much designed around throwing/catching exceptions and you can bet the designers made that process as efficient as possible.
I think it's mostly a philosophy and language culture sort of thing. In Java, the general accepted practice is that the method signature is a contract between your method and the code calling it. So if you receive an improper value, you generally throw an unchecked exception and let it be dealt with at a higher level:
public void setAge(int age)
{
if(age < 0)
{
throw new IllegalArgumentException("Array can't be negative");
}
this.age = age;
}
In this case, the caller broke their end of the contract, so you spit their input back at them with an exception. The "throws" clause is for use when you can't fulfill your end of the contract for some reason.
public void readFile(String filename) throws IOException
{
File myfile = new File(filename);
FileInputStream fis = new FileInputStream(myfile);
//do stuff
fis.read();
//do more stuff
}
In this case, as the method writer, you've broken your end of the contract because the user gave you valid input, but you couldn't complete their request due to an IOException.
Hope that kinda puts you on the right track. Good luck!

Categories