当前位置: 首页 > 科技观察

【Java】循环内变量声明和循环外变量声明用哪个?

时间:2023-03-16 14:38:35 科技观察

介绍最近在刷知乎的时候看到一个很有意思的问题。变量声明在循环内还是循环外?有人认为应该定义循环。在体外,不应在循环体中定义。很多java代码优化建议都有这样的建议:不要在循环中不断创建对象引用,例如:for(inti=1;i<=count;i++){Objectobj=newObject();}这种做法会导致countinmemory有Object对象引用,如果计数很大,会消耗内存。建议改为:Objectobj=null;for(inti=0;i<=count;i++){obj=newObject();}这种情况下,内存中只有一个Object对象引用,每一个newObject()时,Object对象引用指向了不同的Object,但内存中只有一份,大大节省了内存空间。这个建议应该出现在很多公司的代码规范中。接下来我们分析一下变量声明在循环体内,变量声明循环在循环外的情况。效率对比首先我们看一下写在循环内和查询循环外的效率对比。测试代码如下:/***@author:公众号【javafinance】*@Date:*@Description:*/@BenchmarkMode(Mode.AverageTime)//测试完成时间@OutputTimeUnit(TimeUnit.NANOSECONDS)@Warmup(iterations=2)//2轮预热,每次1s@Measurement(iterations=5)//5轮测试,每次1s@Fork(1)//fork1线程@State(Scope.Thread)publicclassForEachBenchMark{publicstaticvoidmain(String[]args)throwsRunnerException{Optionsopt=newOptionsBuilder().include(ForEachBenchMark.class.getSimpleName()).result("result.json").resultFormat(ResultFormatType.JSON).build();newRunner(opt).run();}@Param(value={"10","50","100"})privateintlength;/***在循环外创建对象*@paramblackhole*/@BenchmarkpublicvoidoutsideLoop(Blackholeblackhole){Objectobject=null;for(inti=0;iinsideLoop(){Listlist=newArrayList<>();intn=0;for(;;){if(n>count){break;}Objecto=newObject();list.add(o);}Objectb=2;returnlist;}}publicclassOutsideTest{publicstaticintcount=100;publicListoutsideLoop(){Listlist=newArrayList<>();Objecto=null;intn=0;for(;;){if(n>count){break;}o=newObject();list.add(o);}Objectb=2;returnlist;}这两个编译字节码几乎一样,只是在循环外(OutsideTest)的常量池中多了一个Objecto=null变量,LocalVariableTable略有不同。如果变量在循环中,则它们共享一个变量槽(o和b变量)outsideLoop在栈帧中定义了4个槽,而intsideLoop只定义了3个槽。在outsideLoop中,变量o和b分别占据不同的槽位。在intsideloop中,变量o和b重用一个槽。因此,outsideLoop的栈帧比intsideLoop多占用一块内存。执行以下命令找到字节码中的LocalVariableTable。javac-gOutsideTest.javajavap-vOutsideTest.classLocalVariableTable:StartLengthSlotNameSignature2883oLjava/lang/Object;0460thisLcom/workit/autoconfigure/autoconfigure/controller/InsideTest;8381listLjava/util/List;10362nI4423bLjava/lang/Object;LocalVariableTable:StartLengthSlotNameSignature0490thisLcom/workit/autoconfigure/autoconfigure/控制器/OutsideTest;8411listLjava/util/List;10392oLjava/lang/Object;12373nI4724bLjava/lang/Object;这是一个更极端的情况,其中存在1索特的差距。如果上面的代码Objectb=2;它不会存在Solt被重复使用。总体看来,内存和效率都差不多。从“最小化局部变量作用域”的原则出发,变量声明更适合放在循环体中,这样代码可读性更强。本文转载自微信♂“java财经”,可通过以下二维码关注获取。转载本文请联系爪哇财经公众号。