因为在 try 块中可以抛出异常(在try块的任何一行!异步抛出一些异常,例如在Thread上调用 stop (不推荐使用),甚至OutOfMemoryError几乎可以在任何地方发生)然而它可以被捕获并且代码在之后以相同的方法继续执行,更难以推断可以进行的优化,因此它们不太可能发生 . (有人必须对编译器进行编程才能完成它们,推理并保证其正确性等等 . 注意这样的事情.'d be a big pain for something meant to be '例外') But again, in practice you won'吨 .
2
让我们衡量吧,好吗?
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 put它:"premature optimization is the root of all evil" .
7 回答
try
几乎没有任何费用 . 代码的元数据不是在运行时设置try
的工作,而是在编译时构造,这样当抛出异常时,它现在执行一个相对昂贵的操作,即向上移动堆栈并查看是否存在任何try
块 grab 这个例外 . 从外行人的角度来看,try
可能也是免费的 . 它重新抛出数百或数千例外,你仍然不会注意到成本 .try
有一些与之相关的小费用 . Java无法对try
块中的代码进行一些优化 . 例如,Java通常会在方法中重新排列指令以使其运行得更快 - 但Java还需要保证如果抛出异常,就会观察到方法的执行,就好像它的语句一样,在源代码中执行,执行按顺序排队 .因为在
try
块中可以抛出异常(在try块的任何一行!异步抛出一些异常,例如在Thread上调用stop
(不推荐使用),甚至OutOfMemoryError几乎可以在任何地方发生)然而它可以被捕获并且代码在之后以相同的方法继续执行,更难以推断可以进行的优化,因此它们不太可能发生 . (有人必须对编译器进行编程才能完成它们,推理并保证其正确性等等 . 注意这样的事情.'d be a big pain for something meant to be '例外') But again, in practice you won'吨 .让我们衡量吧,好吗?
在我的电脑上,这打印如下:
至少在这个简单的例子中,try语句对性能没有可测量的影响 . 随意测量更复杂的 .
一般来说,在您有代码中存在实际性能问题的证据之前,我建议您不要担心语言结构的性能成本 . 或者作为Donald Knuth put它:"premature optimization is the root of all evil" .
try
/catch
可能会对性能产生一些影响 . 这是因为它阻止JVM进行一些优化 . Joshua Bloch在"Effective Java,"中说了以下内容:是的,正如其他人所说的那样,
try
块阻止了围绕它的{}
字符的一些优化 . 特别是,优化器必须假设在块内的任何点都可能发生异常,因此无法保证语句可以执行 .例如:
如果没有
try
,则计算分配给x
的值可以保存为"common subexpression"并重新分配给y
. 但由于try
无法保证第一个表达式得到评估,因此必须重新计算表达式 . 这在"straight-line"代码中通常不是很大,但在循环中可能很重要 .但应注意,这仅适用于JITCed代码 . javac只进行了大量的优化,字节码解释器输入/离开
try
块的成本为零 . (没有生成字节码来标记块边界 . )并为了最好的:
输出:
javap输出:
没有“GOTO” .
又一个微基准标记(source) .
我创建了一个测试,在其中我根据异常百分比测量try-catch和no-try-catch代码版本 . 10%的百分比意味着10%的测试案例除以零案例 . 在一种情况下,它由try-catch块处理,而另一种情况由条件运算符处理 . 这是我的结果表:
其中说这些案件之间没有显着差异 .
要理解无法执行优化的原因,了解底层机制很有用 . 我能找到的最简洁的例子是在C宏中实现的:http://www.di.unipi.it/~nids/docs/longjump_try_trow_catch.html
编译器通常很难确定跳转是否可以本地化为X,Y和Z,因此它们会跳过优化他们无法保证安全,但实施本身相当轻松 .
我发现捕获NullPointException非常昂贵 . 对于1.2k操作,时间是200ms和12ms,当我用
if(object==null)
以相同的方式对它进行处理时,这对我来说是相当大的改进 .