哈喽,亲爱的小伙伴们,技术学磊哥,进步没得说!欢迎来到新一期的性能解读系列,我是磊哥。
今天给大家带来的是关于 try-catch 应该放在循环体外,还是放在循环体内的文章,我们将从性能和业务场景分析这两个方面来回答此问题。
很多人对 try-catch 有一定的误解,比如我们经常会把它(try-catch)和“低性能”直接画上等号,但对 try-catch 的本质(是什么)却缺少着最基础的了解,因此我们也会在本篇中对 try-catch 的本质进行相关的探索。
小贴士:我会尽量用代码和评测结果来证明问题,但由于本身认知的局限,如有不当之处,请读者朋友们在评论区指出。
性能评测
话不多说,我们直接来开始今天的测试,本文我们依旧使用 Oracle 官方提供的 JMH(Java Microbenchmark Harness,JAVA 微基准测试套件)来进行测试。
首先在 pom.xml 文件中添加 JMH 框架,配置如下:
<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core --> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>{version}</version> </dependency>
完整测试代码如下:
import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit; /** * try - catch 性能测试 */ @BenchmarkMode(Mode.AverageTime) // 测试完成时间 @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS) // 预热 1 轮,每次 1s @Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) // 测试 5 轮,每次 3s @Fork(1) // fork 1 个线程 @State(Scope.Benchmark) @Threads(100) public class TryCatchPerformanceTest { private static final int forSize = 1000; // 循环次数 public static void main(String[] args) throws RunnerException { // 启动基准测试 Options opt = new OptionsBuilder() .include(TryCatchPerformanceTest.class.getSimpleName()) // 要导入的测试类 .build(); new Runner(opt).run(); // 执行测试 } @Benchmark public int innerForeach() { int count = 0; for (int i = 0; i < forSize; i++) { try { if (i == forSize) { throw new Exception("new Exception"); } count++; } catch (Exception e) { e.printStackTrace(); } } return count; } @Benchmark public int outerForeach() { int count = 0; try { for (int i = 0; i < forSize; i++) { if (i == forSize) { throw new Exception("new Exception"); } count++; } } catch (Exception e) { e.printStackTrace(); } return count; } }
以上代码的测试结果为:
从以上结果可以看出,程序在循环 1000 次的情况下,单次平均执行时间为:
- 循环内包含 try-catch 的平均执行时间是 635 纳秒 ±75 纳秒,也就是 635 纳秒上下误差是 75 纳秒;
- 循环外包含 try-catch 的平均执行时间是 630 纳秒,上下误差 38 纳秒。
也就是说,在没有发生异常的情况下,除去误差值,我们得到的结论是:try-catch 无论是在 for
循环内还是 for
循环外,它们的性能相同,几乎没有任何差别。