代码之家  ›  专栏  ›  技术社区  ›  dcp

转换两次或创建新实例是否更有效

  •  1
  • dcp  · 技术社区  · 15 年前

    考虑这两段代码(您可以假设 execeptionObj 属于类型 Object ,但我们知道这是 Throwable ):

    1)

    logger.log(Level.ERROR, (Throwable) exceptionObj,
        ((Throwable) exceptionObj).getMessage());
    

    2)

    Throwable t = new Throwable((Throwable)exceptionObj);
    logger.log(Level.ERROR, t, t.getMessage());
    

    在我正在进行的一个项目的代码评审中,一位评审员说第一种方法不如第二种方法有效,因为它涉及两个类型转换。我只是想知道你是怎么想的。似乎创建一个新实例也会涉及一些开销。

    6 回复  |  直到 15 年前
        1
  •  12
  •   Sean Owen    15 年前

    这两段代码做了不同的事情。在第二个例子中,您不再传递exceptionobj,而是“exceptionobj引起的未指定的抛出”。我想那不是你想要的。

    你是说第二行的第一行是:

    Throwable t = (Throwable) exceptionObj;
    

    我想,这是非常有效率的,但不会让这个决定问题。哪个更可读是关键,我认为(修改后的)第二个更可读。

    你真的非得用箱子扔吗?伐木工人肯定已经被扔了?

        2
  •  6
  •   Brian Agnew    15 年前

    考虑到一个例外的代价和仅仅打印内容的代价,我认为这场辩论有些似是而非。

        3
  •  4
  •   Padmarag    15 年前

    为什么不投一次用两次呢?

    Throwable t = (Throwable) exceptionObj;
    

    如果不分析和使用重载,很难说出实际的答案。

        4
  •  2
  •   Bart van Heukelom    15 年前
    可抛T=(可抛)除外;
    logger.log(level.error,t,t.getMessage());
    
        5
  •  1
  •   Joachim Sauer    15 年前
    1. 你会注意到两者在性能上几乎没有差别。特别是因为异常处理代码很可能不会在紧循环中运行
    2. 示例2只在以下情况下编译 exceptionObj 要么是 String 或A Throwable . 如果是 ,则第一个示例根本不会编译,如果它是 可抛出 ,那么在第一个示例中,您的类型转换是不必要的
    3. 创建新的 可抛出 避免强制转换是一件可怕的事情,因为它会改变代码的实际功能。
        6
  •  1
  •   Stephen C    15 年前
    logger.log(Level.ERROR, (Throwable) exceptionObj,
        ((Throwable) exceptionObj).getMessage());
    

    理论上,这将导致两种类型的类型转换的成本。实际上,jit编译器很可能会将其优化为只执行一个类型转换的本机代码。

    Throwable t = new Throwable((Throwable)exceptionObj);
    logger.log(Level.ERROR, t, t.getMessage());
    

    在这里,我们将两个类型转换替换为一个类型转换和一个对象创建。但是,所创建的对象是一个throwable,如果查看throwable的构造函数,就会发现它调用 fillInStackTrace() . 这个方法创建一堆其他对象来记录关于堆栈的信息,这可能是 更多 比执行(成功的)类型转换要贵。此外,很有可能这种类型转换已经被优化掉了。

    显然,彻底的调查需要分析这两个版本的代码并检查由jit编译器生成的本机代码……

    (正如其他人所指出的,这两段代码的效果是不同的。第一个记录原始异常,第二个将原始异常作为嵌套异常记录新的抛出异常。)