简体   繁体   中英

Which is preferable and less expensive: class matching vs exception?

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 (...){}

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

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.

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.

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.

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM