<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【Java】變量聲明在循環(huán)體內(nèi)還是循環(huán)體外你用哪一個(gè)?

          共 10543字,需瀏覽 22分鐘

           ·

          2021-03-11 04:49


          ????關(guān)注后回復(fù) “進(jìn)群” ,拉你進(jìn)程序員交流群????
          作者丨java金融
          來(lái)源丨java金融

          引言

          最近刷知乎的時(shí)候看到一個(gè)比較有意思的問題,變量聲明在循環(huán)體內(nèi)還是循環(huán)體外?這個(gè)問題有人認(rèn)為應(yīng)該定義循環(huán)體外,不應(yīng)該定義在循環(huán)體內(nèi)。很多java代碼優(yōu)化建議都有這么一條建議:循環(huán)內(nèi)不要不斷創(chuàng)建對(duì)象引用 例如:

          for (int i = 1; i <= count; i++){
              Object obj = new Object();
          }

          這種做法會(huì)導(dǎo)致內(nèi)存中有countObject對(duì)象引用存在,count很大的話,就耗費(fèi)內(nèi)存了,建議為改為:

          Object obj = null;
          for (int i = 0; i <= count; i++) {
              obj = new Object();
          }

          這樣的話,內(nèi)存中只有一份Object對(duì)象引用,每次new Object()的時(shí)候,Object對(duì)象引用指向不同的Object罷了,但是內(nèi)存中只有一份,這樣就大大節(jié)省了內(nèi)存空間了。這條建議應(yīng)該也出現(xiàn)過在很多公司的代碼規(guī)范上了吧。下面我們就來(lái)分析下變量聲明在循環(huán)體內(nèi)和變量聲明循環(huán)體外的情況。

          效率對(duì)比

          首先我們先來(lái)看看寫在循環(huán)體內(nèi)和詢環(huán)體外的效率比對(duì),測(cè)試代碼如下:

          /**
           * @author: 公眾號(hào)【java金融】
           * @Date
           * @Description:
           */


          @BenchmarkMode(Mode.AverageTime) // 測(cè)試完成時(shí)間
          @OutputTimeUnit(TimeUnit.NANOSECONDS)
          @Warmup(iterations = 2// 預(yù)熱 2 輪,每次 1s
          @Measurement(iterations = 5// 測(cè)試 5 輪,每次 1s
          @Fork(1// fork 1 個(gè)線程
          @State(Scope.Thread)
          public class ForEachBenchMark {


              public static void main(String[] args) throws RunnerException {
                  Options opt = new OptionsBuilder()
                          .include(ForEachBenchMark.class.getSimpleName())
                          .result("result.json")
                          .resultFormat(ResultFormatType.JSON).build()
          ;
                  new Runner(opt).run();
              }

              @Param(value = {"10""50""100"})
              private int length;


              /**
               * 循環(huán)體外創(chuàng)建對(duì)象
               * @param blackhole
               */

              @Benchmark
              public void outsideLoop(Blackhole blackhole) {
                  Object object = null;
                  for (int i = 0; i < length; i++) {
                      object = new Object();
                      blackhole.consume(object);
                  }


              }

              /**
               * 循環(huán)體內(nèi)創(chuàng)建對(duì)象
               * @param blackhole
               */

              @Benchmark
              public void insideLoop(Blackhole blackhole) {
                  for (int i = 0; i < length; i++) {
                      Object object = new Object();
                      blackhole.consume(object);

                  }

              }
          }

          測(cè)試結(jié)果如下:

          Benchmark                     (length)  Mode  Cnt    Score    Error  Units
          ForEachBenchMark.insideLoop         10  avgt    5   58.629 ±  8.857  ns/op
          ForEachBenchMark.insideLoop         50  avgt    5  293.726 ±  1.856  ns/op
          ForEachBenchMark.insideLoop        100  avgt    5  587.185 ± 40.424  ns/op
          ForEachBenchMark.outsideLoop        10  avgt    5   59.563 ±  5.057  ns/op
          ForEachBenchMark.outsideLoop        50  avgt    5  305.829 ± 27.476  ns/op
          ForEachBenchMark.outsideLoop       100  avgt    5  584.853 ± 20.289  ns/op

          我們可以發(fā)現(xiàn)不管在循環(huán)外創(chuàng)建對(duì)象和循環(huán)內(nèi)創(chuàng)建對(duì)象時(shí)間幾乎都是一樣的。

          字節(jié)碼對(duì)比

          下面我們準(zhǔn)備兩個(gè)測(cè)試類

          public class InsideTest {
              public static int count = 100;
              public List<Object> insideLoop() {
                  List<Object> list = new ArrayList<>();
                  int n = 0;
                  for (; ; ) {
                      if (n > count) {
                        break;
                      }
                      Object o = new Object();
                      list.add(o);
                  }
                  Object b = 2;
                  return list;
              }
          }
          public class OutsideTest {
              public static int count = 100;
          public List<Object> outsideLoop() {
                  List<Object> list = new ArrayList<>();
                 Object o = null;
                 int n = 0;
                 for (; ; ) {
                     if (n > count) {
                         break;
                     }
                      o = new Object();
                      list.add(o);
                  }
                  Object b = 2;
                  return list;
              }

          這兩個(gè)編譯后字節(jié)碼幾乎一模一樣,除了循環(huán)體外(OutsideTest )常量池多了一個(gè)Object o = null變量還有的話就是LocalVariableTable有點(diǎn)區(qū)別,變量在循環(huán)體內(nèi)的話公用了一個(gè)變量槽(o和b變量) outsideLoop在stack frame中定義了4個(gè)slot, 而intsideLoop只定義了3個(gè)slot 在outsideLoop中,變量o和b分別占用了不同的slot,在intsideLoop中,變量o和b復(fù)用一個(gè)slot。所以outsideLoop的stack frame比intsideLoop多占用1個(gè)solt內(nèi)存。執(zhí)行以下命令就可以找到字節(jié)碼中的LocalVariableTable。

          javac -g  OutsideTest.java
          javap -v  OutsideTest.class
             LocalVariableTable:
                  Start  Length  Slot  Name   Signature
                     28       8     3     o   Ljava/lang/Object;
                      0      46     0  this   Lcom/workit/autoconfigure/autoconfigure/controller/InsideTest;
                      8      38     1  list   Ljava/util/List;
                     10      36     2     n   I
                     44       2     3     b   Ljava/lang/Object;
            LocalVariableTable:
                  Start  Length  Slot  Name   Signature
                      0      49     0  this   Lcom/workit/autoconfigure/autoconfigure/controller/OutsideTest;
                      8      41     1  list   Ljava/util/List;
                     10      39     2     o   Ljava/lang/Object;
                     12      37     3     n   I
                     47       2     4     b   Ljava/lang/Object;

          這是比較極端的情況下有1個(gè)solt的差距,如果把上述的代碼 Object b = 2;就不會(huì)存在solt復(fù)用了。

          總結(jié)

          整體看下來(lái)貌似內(nèi)存和效率都差不多。從“「局部變量作用域最小化」”原則上來(lái)說,變量聲明在循環(huán)體內(nèi)更合適一點(diǎn),這樣代碼的閱讀性更好。

          結(jié)束

          • 由于自己才疏學(xué)淺,難免會(huì)有紕漏,假如你發(fā)現(xiàn)了錯(cuò)誤的地方,還望留言給我指出來(lái),我會(huì)對(duì)其加以修正。
          • 如果你覺得文章還不錯(cuò),你的轉(zhuǎn)發(fā)、分享、贊賞、點(diǎn)贊、留言就是對(duì)我最大的鼓勵(lì)。
          • 感謝您的閱讀,十分歡迎并感謝您的關(guān)注。巨人肩膀 https://www.zhihu.com/question/31751468

          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來(lái),可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

          點(diǎn)擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

          在看點(diǎn)這里好文分享給更多人↓↓

          瀏覽 33
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人午夜视频在线观看 | 久久亚洲热 | 国产一纹黄片 | 欧美性猛交XXXXX乱大交3免费 | 色五月丁香亚洲 |