今天给大家带来的是一篇关于try-catch应该放在循环外还是循环内的文章。我们将从性能和业务场景分析两个方面来回答这个问题。很多人对try-catch存在一定的误解。比如我们经常把它(try-catch)等同于“低性能”,但是对于try-catch的本质(what)却缺乏最基本的理解,所以本文我们也将探究一下try-catch的本质。性能评测不多说,直接开始今天的测试。在本文中,我们仍然使用Oracle官方提供的JMH(JavaMicrobenchmarkHarness,JAVA微基准测试套件)进行测试。首先在pom.xml文件中添加JMH框架,配置如下:org.openjdk。jmhjmh-core{version}完整测试代码如下:importorg.openjdk.jmh.annotations.*;importorg.openjdk.jmh。runner.Runner;importorg.openjdk.jmh.runner.RunnerException;importorg.openjdk.jmh.runner.options.Options;importorg.openjdk.jmh.runner.options.OptionsBuilder;importjava.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)//fork1个线程@State(Scope.Benchmark)@Threads(100)publicclassTryCatchPerformanceTest{privatestaticfinalintforSize=1000;//循环次数publicstaticvoidmain(String[]args)throwsRunnerException{//启动基准选项opt=newOptionsBuilder().include(TryCatchPerformanceTest.class.getSimpleName())//要导入的测试类.build();newRunner(opt).run();//执行测试}??@BenchmarkpublicintinnerForeach(){intcount=0;for(inti=0;i":()V4:returnpublicstaticvoidmain(java.lang.String[]);Code:0:iconst_01:istore_12:new#2//classjava/lang/Exception5:dup6:ldc#3//StringnewException8:invokespecial#4//Methodjava/lang/Exception."":(Ljava/lang/String;)v11:athrow12:astore_113:aload_114:invokevirtual#5//Methodjava/lang/Exception.printStackTrace:()V17:returnExceptiontable:fromtotargettype01212Classjava/lang/Exception}从上面的字节码我们可以看出有一个异常表:Exceptiontable:fromtotargettype01212Classjava/lang/Exception参数说明:from:meanstry-catch的起始地址;to:表示try-catch的结束地址;target:表示异常处理的起始位;type:表示异常类的名称。首先判断错误数据是否在fromtototo范围内,如果是,则从targetflag开始执行,如果没有错误,直接goto返回。也就是说,如果代码没有出错,性能几乎不受影响,正常代码的执行逻辑是一样的。业务情况分析try-catch在循环内和循环外的表现虽然差不多,但是他们代码的业务含义是完全不同的。例如下面的代码:publicclassAppTest{publicstaticvoidmain(String[]args){System.out.println("循环内执行结果:"+innerForeach());System.out.println("循环外执行结果:"+outerForeach());}//方法一publicstaticininnerForeach(){intcount=0;for(inti=0;i<6;i++){try{if(i==3){thrownewException("newException");}count++;}catch(Exceptione){e.printStackTrace();}}returncount;}//方法二publicstaticintouterForeach(){intcount=0;try{for(inti=0;i<6;i++){if(i==3){thrownewException("newException");}count++;}}catch(Exceptione){e.printStackTrace();}returncount;}}的执行结果上面的程序是:java.lang.Exception:newExceptionatcom.example.AppTest.innerForeach(AppTest.java:15)atcom.example.AppTest.main(AppTest.java:5)java.lang.Exception:newExceptionatcom.example.AppTest.outerForeach(AppTest.java:31)atcom.example.AppTest.main(AppTest.java:6)循环内执行结果:5循环外执行结果:3OK可以看出try-循环体中的catch可以在异常发生后继续执行循环;而循环外的try-catch会在异常发生后终止循环。因此,我们在决定try-catch放在循环内还是循环外时,并不取决于性能(因为性能差不多),而应该取决于具体的业务场景。比如我们需要处理一批数据,无论这组数据有什么问题,都不能影响其他组的正常执行。这时候我们可以把try-catch放在循环体中;而当我们需要计算一组数据的总值时,只要一组数据出现错误,我们就需要终止执行并抛出异常。这时候我们需要将try-catch放在循环外去执行。小结在这篇文章中,我们测试了try-catch放在循环内和循环外的性能,发现当循环多次重复时,两者的性能几乎是一样的。然后我们分析字节码,发现只有在异常发生的时候,才会对照异常表进行异常处理,而正常情况下,try-catch的执行是可以忽略的。但是,在循环内或循环外使用try-catch对于程序的执行结果是完全不同的。所以我们应该从实际业务出发来决定try-catch应该存放在哪里,而不是性能方面的考虑。