我有一个小性能问题,在使用 try catch 子句时,最好指定您可以获得的确切异常,或者只使用异常更好? 示例:
try {
whatever
} catch (NullPointerException ex) {
whatever
}
或者如果您不介意哪种异常:
try {
whatever
} catch (Exception ex) {
whatever
}
因为我知道你可以使用不同的异常来触发不同的效果,但我只是要求性能。
最佳答案
根据我的测试,性能没有显着差异。
每次运行都会尝试每种场景的一千万次,然后比较以纳秒为单位的运行时间以及四舍五入的秒数。这实际上与我最初的假设相反,因为我认为捕获 Throwable
会显示出显着的改进。
我也开始意识到这部分可能是由于优化器的影响,所以我创建了一个更复杂的示例,其中包括下面的伪随机数,认为这将减轻优化器的任何潜在影响代码。
(我不会向您讲授如何正确使用 catch
block ,因为问题专门针对性能,而不是最佳实践。)
大量数据低于此点!
运行 1 结果:
Exception: 7196141955 (7.196s)
NumberFormatException: 7736401837 (7.736s)
Throwable: 6818656505 (6.819s)
运行 2 结果:
Exception: 7262897545 (7.263s)
NumberFormatException: 7056116050 (7.056s)
Throwable: 7108232206 (7.108s)
运行 3 结果:
Exception: 7088967045 (7.089s)
NumberFormatException: 7020495455 (7.020s)
Throwable: 7192925684 (7.193s)
运行 4 结果:
Exception: 6916917328 (6.917s)
NumberFormatException: 7690084994 (7.690s)
Throwable: 6906011513 (6.906s)
运行 5 结果:
Exception: 7247571874 (7.248s)
NumberFormatException: 6818511040 (6.819s)
Throwable: 6813286603 (6.813s)
代码
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Test {
private static final int TRIALS = 10000000;
private static final int NANOS_IN_SECOND = 1000000000;
private static final int DECIMAL_PRECISION = 3;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP;
public static void main(String[] args) {
long firstStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
throw new NumberFormatException();
}
catch(Exception e) {
}
}
long firstEnd = System.nanoTime();
long secondStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
throw new NumberFormatException();
}
catch(NumberFormatException e) {
}
}
long secondEnd = System.nanoTime();
long thirdStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
throw new NumberFormatException();
}
catch(Throwable e) {
}
}
long thirdEnd = System.nanoTime();
long exception = firstEnd - firstStart;
long numberFormatException = secondEnd - secondStart;
long throwable = thirdEnd - thirdStart;
BigDecimal exceptionSeconds = new BigDecimal((double)exception / (double)NANOS_IN_SECOND);
BigDecimal numberFormatExceptionSeconds = new BigDecimal((double)numberFormatException / (double)NANOS_IN_SECOND);
BigDecimal throwableSeconds = new BigDecimal((double)throwable / (double)NANOS_IN_SECOND);
exceptionSeconds = exceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
numberFormatExceptionSeconds = numberFormatExceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
throwableSeconds = throwableSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
System.out.println("Exception: " + exception + " (" + exceptionSeconds + "s)");
System.out.println("NumberFormatException: " + numberFormatException + " (" + numberFormatExceptionSeconds + "s)");
System.out.println("Throwable: " + throwable + " (" + throwableSeconds + "s)");
}
}
更复杂的伪随机代码
我创建这个是为了确保优化器不会简单地“忽略”整个抛出/捕获过程,因为它意识到代码块将始终流向 catch
。通过在随机选择的 String
(但总是无效的)上尝试 Integer.parseInt()
,这意味着编译器直到运行时才能知道给定的运行是否通过 for()
循环是否有效。
正如第一个实验所预期的那样,三种场景之间没有显着差异。
运行 1 结果:
Exception: 10988431371 (10.988s)
NumberFormatException: 11360698958 (11.361s)
Throwable: 10539041505 (10.539s)
运行 2 结果:
Exception: 12468860076 (12.469s)
NumberFormatException: 11852429194 (11.852s)
Throwable: 11859547560 (11.860s)
运行 3 结果:
Exception: 10618082779 (10.618s)
NumberFormatException: 10718252324 (10.718s)
Throwable: 10327709072 (10.328s)
运行 4 结果:
Exception: 11031135405 (11.031s)
NumberFormatException: 10689877480 (10.690s)
Throwable: 10668345685 (10.668s)
运行 5 结果:
Exception: 11513727192 (11.514s)
NumberFormatException: 11581826079 (11.582s)
Throwable: 12488301109 (12.488s)
代码
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;
public class Test {
private static final int TRIALS = 10000000;
private static final int NANOS_IN_SECOND = 1000000000;
private static final int DECIMAL_PRECISION = 3;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP;
private static final String[] TEST_STRINGS = {
"lawl",
"rofl",
"trololo",
"foo",
"bar"
};
private static final Random RANDOM = new Random();
public static void main(String[] args) {
long firstStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
Integer.parseInt(TEST_STRINGS[RANDOM.nextInt(TEST_STRINGS.length)]);
}
catch(Exception e) {
}
}
long firstEnd = System.nanoTime();
long secondStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
Integer.parseInt(TEST_STRINGS[RANDOM.nextInt(TEST_STRINGS.length)]);
}
catch(NumberFormatException e) {
}
}
long secondEnd = System.nanoTime();
long thirdStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
Integer.parseInt(TEST_STRINGS[RANDOM.nextInt(TEST_STRINGS.length)]);
}
catch(Throwable e) {
}
}
long thirdEnd = System.nanoTime();
long exception = firstEnd - firstStart;
long numberFormatException = secondEnd - secondStart;
long throwable = thirdEnd - thirdStart;
BigDecimal exceptionSeconds = new BigDecimal((double)exception / (double)NANOS_IN_SECOND);
BigDecimal numberFormatExceptionSeconds = new BigDecimal((double)numberFormatException / (double)NANOS_IN_SECOND);
BigDecimal throwableSeconds = new BigDecimal((double)throwable / (double)NANOS_IN_SECOND);
exceptionSeconds = exceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
numberFormatExceptionSeconds = numberFormatExceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
throwableSeconds = throwableSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
System.out.println("Exception: " + exception + " (" + exceptionSeconds + "s)");
System.out.println("NumberFormatException: " + numberFormatException + " (" + numberFormatExceptionSeconds + "s)");
System.out.println("Throwable: " + throwable + " (" + throwableSeconds + "s)");
}
}
关于java - 是否指定异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17152088/