3 回答
TA贡献1942条经验 获得超3个赞
public class Test { int value; public int getValue() { return value; } public void reset() { value = 0; } // Calculates without exception public void method1(int i) { value = ((value + i) / i) << 1; // Will never be true if ((i & 0xFFFFFFF) == 1000000000) { System.out.println("You'll never see this!"); } } // Could in theory throw one, but never will public void method2(int i) throws Exception { value = ((value + i) / i) << 1; // Will never be true if ((i & 0xFFFFFFF) == 1000000000) { throw new Exception(); } } // This one will regularly throw one public void method3(int i) throws Exception { value = ((value + i) / i) << 1; // i & 1 is equally fast to calculate as i & 0xFFFFFFF; it is both // an AND operation between two integers. The size of the number plays // no role. AND on 32 BIT always ANDs all 32 bits if ((i & 0x1) == 1) { throw new Exception(); } } public static void main(String[] args) { int i; long l; Test t = new Test(); l = System.currentTimeMillis(); t.reset(); for (i = 1; i < 100000000; i++) { t.method1(i); } l = System.currentTimeMillis() - l; System.out.println( "method1 took " + l + " ms, result was " + t.getValue() ); l = System.currentTimeMillis(); t.reset(); for (i = 1; i < 100000000; i++) { try { t.method2(i); } catch (Exception e) { System.out.println("You'll never see this!"); } } l = System.currentTimeMillis() - l; System.out.println( "method2 took " + l + " ms, result was " + t.getValue() ); l = System.currentTimeMillis(); t.reset(); for (i = 1; i < 100000000; i++) { try { t.method3(i); } catch (Exception e) { // Do nothing here, as we will get here } } l = System.currentTimeMillis() - l; System.out.println( "method3 took " + l + " ms, result was " + t.getValue() ); }}
method1 took 972 ms, result was 2method2 took 1003 ms, result was 2method3 took 66716 ms, result was 2
TA贡献2080条经验 获得超4个赞
method1 took 1733 ms, result was 2method2 took 1248 ms, result was 2method3 took 83997 ms, result was 2method4 took 1692 ms, result was 2method5 took 60946 ms, result was 2method6 took 25746 ms, result was 2
new Integer(1)
throw new Exception()
.
new Exception()
TA贡献1797条经验 获得超4个赞
新创建的异常与预先创建的异常 启用堆栈跟踪的VS禁用 堆栈跟踪请求与从未请求 在最高级别抓到,在每个级别重新抛出,在每个级别上被链锁/包装 不同级别的Java调用堆栈深度 没有内联优化和极端内联与默认设置 用户定义的字段读取和未读取
真正的例外是出色的表演。
如果您按照设计使用它们,并且只在由常规代码处理的大量非例外情况中进行真正的例外情况交流,那么使用异常将是性能上的胜利。 例外情况的执行费用有两个主要组成部分: 栈迹构造当异常被实例化并且 堆栈展开在异常抛出过程中。 堆栈跟踪施工成本与堆垛深度成正比。
在异常时刻实例化。这已经很糟糕了,因为地球上有谁知道这个抛出方法会被调用的堆栈深度?即使关闭堆栈跟踪生成和/或缓存异常,也只能消除这部分性能成本。 堆栈展开成本取决于我们在编译代码中更接近异常处理程序的幸运程度。
仔细构造代码以避免深入的异常处理程序查找可能有助于我们变得更幸运。 如果消除这两种影响,例外的性能成本就是本地分支的性能成本。
无论听起来多么美妙,这并不意味着您应该使用异常作为通常的控制流,因为在这种情况下 优化编译器是任由您摆布的!您应该只在真正特殊的情况下使用它们,在这种情况下,异常频率 摊销增加实际异常可能带来的不幸代价。 乐观的经验法则似乎是 10^-4异常的频率是足够的。当然,这取决于异常本身的重量级、异常处理程序中所采取的确切操作等。
if
添加回答
举报