【问题标题】:Which is preferable and less expensive: class matching vs exception?哪个更可取且更便宜:类匹配与异常?
【发布时间】:2009-11-20 07:04:49
【问题描述】:

哪个更便宜,更可取:put1 还是 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 (...){}

问题修订: 问题不是那么清楚。让我稍微修改一下这个问题。我忘记了强制转换,所以 put2 依赖于强制转换异常失败。 isAssignableFrom()、isInstanceOf() 和 instanceof 在功能上相似,因此产生相同的费用,只有一个是包含子类的方法,而第二个是精确类型匹配,第三个是运算符版本。反射方法和异常都是昂贵的操作。

我的问题是针对那些在该领域进行过一些基准测试的人 - 成本更低且更可取:instanceof/isassignablefrom 与强制转换异常?

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

【问题讨论】:

  • 听起来您高估了原始 CPU 速度的问题。您应该更多地担心什么是正确、清晰、可读和惯用的 Java 代码。只有在极少数情况下,您才会为了缩短几个时钟周期而扭曲它。

标签: c# java exception


【解决方案1】:

也许你想要:

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

这几乎肯定比调用isAssignableFrom 好得多。

或者在 C# 中(因为你添加了 c# 标签):

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

编辑:更新后的问题是哪个更好:instanceof 或 cast-and-catch。功能基本相同。性能差异可能并不显着,我必须对其进行测量;通常抛出异常很慢,但我不知道其余的。所以我会根据风格来决定。说出你的意思。

如果您总是期望 item[i] 成为 Animal,那么您只是要格外小心,即投即取。否则我发现使用 instanceof 会更清楚,因为这清楚地说明了你的意思:“如果这个对象是动物,把它放在地图中”。

【讨论】:

  • 以下也是有效的 c#(仅用于与您的 Java 示例进行比较: if (item[i] is Animal) map[key[i]] = (Animal) item[i];跨度>
  • 哦,顺便说一句,+1,不错的答案:)
  • 它是有效的 C#,但也不如使用 as
  • 检查 if 会更好,因为:1. 你的 FOR 循环会做更少的 map.put(),异常版本会调用 map.put() 的最大可能数,每个都会产生异常时间条件不满足。 2. 创建异常的过程是昂贵的,它占用堆栈内存,在 CPU 注册表中产生变化等,在任何方面都比简单的 if 更简单
  • 由于我对问题的修改,请修改您的答案。问题不在于instanceof vs isassignablefrom,而是instanceof/isassignablefrom vs cast 异常。
【解决方案2】:

我很困惑。如果item[i] 不是Animal,那么map.put(key[i], item[i]) 怎么编译呢?

也就是说,第一种方法说明了您打算做什么,尽管我相信instanceof 会是一个更好的检查。

【讨论】:

    【解决方案3】:

    通常情况下,异常处理会明显变慢,因为它应该用于异常情况(很少发生),VM 制造商不会花太多精力来加速它。

    我认为您的代码的 tr/catch 版本滥用了异常处理,并且永远不会考虑这样做。您正在考虑做这样的事情的事实可能意味着您的设计很糟糕,项目可能应该是 Animal[] 而不是其他东西,在这种情况下您根本不需要在运行时检查。让编译器为您完成工作。

    【讨论】:

      【解决方案4】:

      我同意之前的回答 - 这不会编译。

      但是,在我看来,是异常还是检查取决于函数的目的。

      item[i] 不是 Animal 是错误/例外情况吗?预计会很少发生吗?在这种情况下,它应该是一个例外。

      如果它是逻辑的一部分——意味着你希望 item[i] 是很多东西——并且只有当它是你想要放入地图的 Animal 时。在这种情况下,instanceof 检查是正确的方法。

      更新: 我还会添加一个示例(有点蹩脚):

      哪个更好: (1)

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

      或 (2)

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

      这取决于程序的作用。 (1) 可用于对任何整数输入的小于 100 的数字进行计数。如果 processNumber 期望的百分比值不能大于 100,则将使用 (2)。

      不同的是,程序(2)得到aNumber > 100是错误的。但是,对于程序(1),aNumber > 100是有效的,但是只有当aNumber

      PS - 这可能对你一点帮助都没有,如果是这种情况,我深表歉意。

      【讨论】:

      • 由于我对问题的修改,请修改您的答案。问题是 instanceof/isassignablefrom 与强制转换异常。
      【解决方案5】:

      您的两种选择并不完全等效。选择哪一个,完全取决于你的代码应该做什么:

      • 如果项目预计总是 Animal,那么你应该使用 put2(如果 事实并非如此......)
      • 如果项目可能是也可能不是 Animal,你应该使用put1( 检查条件,而不是错误...)

      如果您正在编写代码,从一开始就不要关心性能!

      【讨论】:

        猜你喜欢
        • 2013-03-12
        • 2017-07-17
        • 1970-01-01
        • 1970-01-01
        • 2011-01-28
        • 2021-02-06
        • 2017-11-26
        • 2015-03-27
        • 2018-06-27
        相关资源
        最近更新 更多