tags:

views:

290

answers:

5

Which is less expensive and preferable: put1 or put2?

Map<String, Animal> map = new Map<String, Animal>();

void put1(){
 for (.....)
  if (Animal.class.isAssignableFrom(item[i].getClass())
   map.put(key[i], item[i]);

void put2(){
 for (.....)
  try{
   map.put(key[i], item[i]);}
  catch (...){}

Question revision: The question wasn't that clear. Let me revise the question a little. I forgot the casting so that put2 depends on cast exception failure. isAssignableFrom(), isInstanceOf() and instanceof are similar functionally and therefore incur the same expense just one is a method to include subclasses,while the 2nd is for exact type matching and the 3rd is the operator version. Both reflective methods and exceptions are expensive operations.

My question is for those who have done some benchmarking in this area - which is less expensive and preferable: instanceof/isassignablefrom vs cast exception?

void put1(){
 for (.....)
  if (Animal.class.isAssignableFrom(item[i].getClass())
   map.put(key[i], (Animal)item[i]);

void put2(){
 for (.....)
  try{
   map.put(key[i], (Animal)item[i]);}
  catch (...){}
+2  A: 

I'm confused. If item[i] is not an Animal, then how does map.put(key[i], item[i]) even compile?

That said, the first method says what you're intending to do, although I believe instanceof would be an even better check.

280Z28
+11  A: 

Probably you want:

if (item[i] instanceof Animal)
    map.put(key[i], (Animal) item[i]);

This is almost certainly much better than calling isAssignableFrom.

Or in C# (since you added the c# tag):

var a = item[i] as Animal;
if (a != null)
    map[key[i]] = a;

EDIT: The updated question is which is better: instanceof or cast-and-catch. The functionality is basically the same. The performance difference might not be significant and I would have to measure it; generally throwing an exception is slow, but I don't know about the rest. So I would decide based on style. Say what you mean.

If you always expect expect item[i] to be an Animal, and you're just being extra careful, cast-and-catch. Otherwise I find it much clearer to use instanceof, because that plainly says what you mean: "if this object is an Animal, put it in the map".

Jason Orendorff
+1 for the second suggestion - definitely the best way
AdamRalph
The following is also valid c# (just for comparison with your Java example:if (item[i] is Animal) map[key[i]] = (Animal) item[i];
David Hall
Oh, and +1 btw, nice answer :)
David Hall
It's valid C#, but it's also inferior to using `as`.
Joren
it is lot better to check with if because: 1. your FOR loop will do less map.put(), exception version will make call to map.put() maximum possible number with producing exception each time conditions are not satisfied. 2. process of creating exception is expencive, it takes memory on stack, produces changes in CPU registry etc, in any way a lot more than plain simple if
ante.sabo
Please revise your answer due to my revision of the question. The question is not about instanceof vs isassignablefrom but instanceof/isassignablefrom vs cast exception.
Blessed Geek
the second suggestion in this answer is better than either of the options you have suggested
AdamRalph
+1  A: 

Typically exception handling will be significantly slower because, since it is supposed to be used for exceptional things (rarely occurring) not much work is spent by VM makers on speeding it up.

The tr/catch version of your code I would consider to be abuse of exception handling and would never consider doing it. The fact that you are thinking of doing something like this probably means you have a poor design, items should probably an Animal[] not something else, in which case you don't need to check at runtime at all. Let the compiler do the work for you.

TofuBeer
+1  A: 

I agree with a previous answer - this will not compile.

But, in my opinion, whether it is an exception or a check depends on the purpose of the function.

Is item[i] not being a Animal an error/exceptional case? Is it expected to happen rarely? In this case, it should be an exception.

If it is part of the logic - meaning you expect item[i] to be many things - and only if it is an Animal you want to put in a map. In this case, the instanceof check is the right way.

UPDATE : I'll also add an example (bit lame) :

Which is better : (1)

if ( aNumber < 100 ) {   
 processNumber(aNumber); 
}

or (2)

try {
    processNumber(aNumber); //Throws exception if aNumber >= 100
} catch () {
}

This depends on what the program does. (1) may be used for counting numbers < 100 for any integer input. (2) will be used if processNumber expects a percentage value which cannot be greater than 100.

The difference is, it is an error for program (2) to get aNumber > 100. However, for program (1) aNumber > 100 is valid, but "something" happens only when aNumber is < 100.

PS - This may not be helpful to you at all, and I apologize if this is the case.

Chip
Please revise your answer due to my revision of the question. The question is instanceof/isassignablefrom vs cast exception.
Blessed Geek
A: 

Your two alternatives are not really equivalent. Which one to choose, depends totally on what your code is supposed to do:

  • If the item is expected to always be an Animal, then you should use put2 (which will throw, if that's not the case...)
  • If the item may or may not be an Animal, you should use put1 (which checks a condition, not an error...)

Never care about performance in the first place, if you're writing code!

Thomas Weller