我们知道捕获异常的代价很高。但是,即使从未抛出异常,在Java中使用try-catch块的代价也很高吗?
我发现Stack Overflow的问题/答案为什么尝试块昂贵?,但它是用于。net的。
我们知道捕获异常的代价很高。但是,即使从未抛出异常,在Java中使用try-catch块的代价也很高吗?
我发现Stack Overflow的问题/答案为什么尝试块昂贵?,但它是用于。net的。
当前回答
我们来量一下,好吗?
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语句对性能没有可测量的影响。请随意测量更复杂的参数。
一般来说,我建议不要担心语言结构的性能成本,直到有证据表明代码中存在实际的性能问题。或者正如Donald Knuth所说:“过早的优化是万恶之源”。
其他回答
我们来量一下,好吗?
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语句对性能没有可测量的影响。请随意测量更复杂的参数。
一般来说,我建议不要担心语言结构的性能成本,直到有证据表明代码中存在实际的性能问题。或者正如Donald Knuth所说:“过早的优化是万恶之源”。
另一个微基准测试(来源)。
我创建了一个测试,在这个测试中,我根据异常百分比来测量尝试捕获和不尝试捕获的代码版本。10%百分比意味着10%的测试用例除以零用例。在一种情况下,它由try-catch块处理,在另一种情况下由条件操作符处理。这是我的结果表:
OS: Windows 8 6.2 x64
JVM: Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 23.25-b01
Percentage | Result (try/if, ns) 0% | 88/90 1% | 89/87 10% | 86/97 90% | 85/83
这表明这些案例之间没有显著差异。
要理解为什么不能执行优化,了解底层机制是有用的。我能找到的最简洁的例子是在http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html上用C宏实现的
#include <stdio.h>
#include <setjmp.h>
#define TRY do{ jmp_buf ex_buf__; switch( setjmp(ex_buf__) ){ case 0: while(1){
#define CATCH(x) break; case x:
#define FINALLY break; } default:
#define ETRY } }while(0)
#define THROW(x) longjmp(ex_buf__, x)
编译器通常很难确定一个跳转是否可以本地化到X, Y和Z,所以他们跳过优化,他们不能保证安全,但实现本身相当轻。
尝试/捕获可能会对性能产生一些影响。这是因为它阻止JVM进行一些优化。约书亚·布洛赫在《有效的Java》一书中说:
•将代码放置在try-catch块中会抑制现代JVM实现可能执行的某些优化。
我发现捕获NullPointException非常昂贵。对于1.2k操作,当我以同样的方式处理if(object==null)时,时间为200ms和12ms,这对我来说是很大的改进。