当前位置: 首页 > 知识库问答 >
问题:

是否指定异常?

戚学文
2023-03-14

我有一个小的性能问题,当使用try-catch子句时,最好指定可以获得的确切异常,或者只使用exception它更好?例子:

try {
    whatever
} catch (NullPointerException ex) {
    whatever
}

或者如果你不介意什么样的例外:

try {
    whatever
} catch (Exception ex) {
    whatever
}

因为我知道你可以使用不同的异常来触发不同的效果,但我只是要求性能。

共有3个答案

公孙新觉
2023-03-14

在这种情况下,两者都不是。try/catch比较昂贵,应该节约使用。手动检查null比捕获NullPointerException更好。

柴文林
2023-03-14

我建议这里的正确答案是根据编程原因使用适当的异常处理,而不是性能。如果(忽略性能)捕获一个NullPointerExcsion会更合适,那么就这样做。

例外情况应该是例外情况。它们应该很少发生,因此异常处理中的性能应该不如正确性重要。

如果您的应用程序定期预测这种情况,那么它应该通过某种机制来处理,而不是异常。如果您担心性能,这一点尤其正确,因为抛出异常总是代价高昂的。

段干博明
2023-03-14

根据我的测试,性能没有显著差异。

每次运行都会尝试每个场景中的1000万次,然后以纳秒和舍入秒为单位比较运行时间。这实际上与我最初的假设相反,因为我认为捕捉一个可丢弃的会显示出显著的改善。

我也开始意识到这部分可能是由于优化器的影响,因此我创建了一个更复杂的示例,其中包括下面的伪随机数,认为这将减轻优化器对代码的任何潜在影响。

(我不会教你如何正确使用cat块,因为这个问题是关于性能的,而不是最佳实践。)

下面有很多数据!

运行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。通过尝试一个整数。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)");

    }

}

 类似资料:
  • 异常指定可以由指定函数抛出一列异常: int g( float h ) throw (a, b, c) { // function body } 可以限制从函数抛出的异常类型。函数声明中可以指定异常类型作为异常指定(也称为抛出表,throw list)。异常指定列出可抛出的异常。函数可以抛出指定异常或派生类型。尽管这样好像保证不会抛出其他异常类型,但其实也可以抛出其他异常类型。如果抛出异常指定中没

  • 问题内容: 我在实体中有一个懒惰的访存类型集合。我正在使用Spring Data(JpaRepository)来访问实体。 我想要服务类和当前实现中的两个功能如下: 获取父级时,“子级”应为null } 提取父项时,应填写“子项”: } 从RestController返回“父”实体时,将引发以下异常: org.springframework.http.converter.HttpMessageNo

  • 问题内容: 该事务是否会回滚,或者是否还需要在批注中包含RuntimeException.class? 问题答案: 无需包括在列表中。即使您不提及它,它也会处理。 我已经尝试了jdbcTemplate:-

  • 是否有方法在ConfigMap中指定值?当我尝试指定端口号时,我得到以下错误。

  • 问题内容: AFAIK,您无需在onclick中指定协议: 坏 好 今天,我在GoogleAnallytics上注意到他们正在使用它: 这个例子是完全错误的,还是有理由指定除?以外的其他内容? 问题答案: 这里的一些响应声称“javascript:”前缀是“过去的遗留物”,这意味着浏览器有意对它进行了特殊处理,以实现向后兼容。是否有确凿的证据证明是这种情况(有人检查过源代码)吗? 对我来说,它的意

  • 检查当前进程的参数是否包含指定的标志。 使用 Array.every() 和 Array.includes() 来检查 process.argv 是否包含所有指定的标志。 使用正则表达式来测试指定的标志是否以 - 或 -- 作为前缀并相应地添加前缀。 const hasFlags = (...flags) => flags.every(flag => process.argv.includes