即使从未引发异常,使用 try-catch 块是否成本高昂?
2022-08-31 06:05:42
我们知道,捕获异常是昂贵的。但是,在Java中使用try-catch块是否也代价高昂,即使从未抛出异常?
我发现堆栈溢出问题/答案为什么尝试块很昂贵?,但它是针对.NET的。
我们知道,捕获异常是昂贵的。但是,在Java中使用try-catch块是否也代价高昂,即使从未抛出异常?
我发现堆栈溢出问题/答案为什么尝试块很昂贵?,但它是针对.NET的。
try
几乎没有任何费用。代码的元数据不是在运行时设置工作,而是在编译时构建的,这样当抛出异常时,它现在执行相对昂贵的操作,即在堆栈中行走并查看是否存在任何可以捕获此异常的块。从外行人的角度来看,还不如自由。它实际上是抛出异常,导致您付出代价 - 但除非您抛出数百或数千个异常,否则您仍然不会注意到成本。try
try
try
try
有一些与之相关的小成本。Java无法对块中的代码进行一些优化,否则它会这样做。例如,Java通常会重新排列方法中的指令以使其运行得更快 - 但Java还需要保证,如果抛出异常,则观察该方法的执行,就好像其在源代码中编写的语句按顺序执行一样。try
因为在块中可以抛出异常(在 try 块中的任何一行!一些异常是异步引发的,例如通过调用线程(已弃用),甚至除了OutOfMemoryError几乎可以在任何地方发生)之外,但它可以被捕获并且代码继续以相同的方法继续执行,因此更难以推理可以进行的优化,因此它们不太可能发生。(有人必须对编译器进行编程才能做到这一点,推理并保证正确性等。对于一些意味着“特殊”的东西来说,这将是一个很大的痛苦)但是,在实践中,你不会注意到这样的事情。try
stop
让我们来衡量一下,好吗?
public abstract class Benchmark {
final String name;
public Benchmark(String name) {
this.name = name;
}
abstract int run(int iterations) throws Throwable;
private BigDecimal time() {
try {
int nextI = 1;
int i;
long duration;
do {
i = nextI;
long start = System.nanoTime();
run(i);
duration = System.nanoTime() - start;
nextI = (i << 1) | 1;
} while (duration < 100000000 && nextI > 0);
return new BigDecimal((duration) * 1000 / i).movePointLeft(3);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return name + "\t" + time() + " ns";
}
public static void main(String[] args) throws Exception {
Benchmark[] benchmarks = {
new Benchmark("try") {
@Override int run(int iterations) throws Throwable {
int x = 0;
for (int i = 0; i < iterations; i++) {
try {
x += i;
} catch (Exception e) {
e.printStackTrace();
}
}
return x;
}
}, new Benchmark("no try") {
@Override int run(int iterations) throws Throwable {
int x = 0;
for (int i = 0; i < iterations; i++) {
x += i;
}
return x;
}
}
};
for (Benchmark bm : benchmarks) {
System.out.println(bm);
}
}
}
在我的计算机上,这将打印如下内容:
try 0.598 ns
no try 0.601 ns
至少在这个微不足道的示例中,try 语句对性能没有可衡量的影响。随意测量更复杂的。
一般来说,我建议在代码中有实际性能问题的证据之前,不要担心语言构造的性能成本。或者正如唐纳德·高德纳所说:“过早的优化是万恶之源”。