java - 是否指定异常?

标签 java performance exception try-catch

我有一个小性能问题,在使用 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/

相关文章:

java - Java 中线程 "AWT-EventQueue-0"中的异常帮助

java - 我如何知道小程序是在浏览器中运行还是从 Eclipse 调用

Java JTextPane 性能低下

php - 以已知顺序对数组重新排序的最有效方法

python - 从异常中获取回溯而不重新引发它们

java - 方法覆盖和继承与异常

java - 自定义 Spring 身份验证中的角色访问

java - 改变 Java 数组

java - 字符串越界异常

javascript - Angular 2 : Enhance the performance of scroll event with a big ngFor List