<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>

          還在 for 循環(huán)里使用 + 拼接字符串?明天不用來上班了!

          共 600字,需瀏覽 2分鐘

           ·

          2021-12-29 16:25

          點擊關注上方“Stephen”,

          設為“置頂或星標”,第一時間送達干貨

          來源:cnblogs.com/keatsCoder/p/13212289.html

          引言

          都說 StringBuilder 在處理字符串拼接上效率要強于 String,但有時候我們的理解可能會存在一定的偏差。最近我在測試數(shù)據(jù)導入效率的時候就發(fā)現(xiàn)我以前對 StringBuilder 的部分理解是錯誤的。

          后來我通過實踐測試 + 找原理 的方式搞清楚了這塊的邏輯?,F(xiàn)在將過程分享給大家

          測試用例

          我們的代碼在循環(huán)中拼接字符串一般有兩種情況

          • 第一種就是每次循環(huán)將對象中的幾個字段拼接成一個新字段,再賦值給對象
          • 第二種操作是在循環(huán)外創(chuàng)建一個字符串對象,每次循環(huán)向該字符串拼接新的內容。循環(huán)結束后得到拼接好的字符串

          對于這兩種情況,我創(chuàng)建了兩個對照組

          第一組:

          在每次 For 循環(huán)中拼接字符串,即拼即用、用完即毀。分別使用 String 和 StringBuilder 拼接

          /**
          ?*?循環(huán)內?String?拼接字符串,一次循環(huán)后銷毀
          ?*/

          public?static?void?useString(){
          ????for?(int?i?=?0;?i?????????String?str?=?str1?+?i?+?str2?+?i?+?str3?+?i?+?str4?;
          ????}
          }

          /**
          ?*?循環(huán)內?使用?StringBuilder?拼接字符串,一次循環(huán)后銷毀
          ?*/

          public?static?void?useStringBuilder(){
          ????for?(int?i?=?0;?i?????????StringBuilder?sb?=?new?StringBuilder();
          ????????String?s?=?sb.append(str1).append(i).append(str2).append(i).append(str3).append(i).append(str4).toString();
          ????}
          }

          第二組:

          多次 For 循環(huán)拼接一個字符串,循環(huán)結束后使用字符串,使用后由垃圾回收器回收。也是分別使用 String 和 StringBuilder 拼接

          /**
          ?*?多次循環(huán)拼接成一個字符串?用?String
          ?*/

          public?static?void?useStringSpliceOneStr?(){
          ????String?str?=?"";
          ????for?(int?i?=?0;?i?????????str?+=?str1?+?str2?+?str3?+?str4?+?i;
          ????}
          }

          /**
          ?*?多次循環(huán)拼接成一個字符串?用?StringBuilder
          ?*/

          public?static?void?useStringBuilderSpliceOneStr(){
          ????StringBuilder?sb?=?new?StringBuilder();
          ????for?(int?i?=?0;?i?????????sb.append(str1).append(str2).append(str3).append(str4).append(i);
          ????}
          }

          為了保證測試質量,在每個測試項目進行前。線程休息 2s,之后空跑 5 次熱身。最后執(zhí)行 5 次求平均時間的方式計算時間

          public?static?int?executeSometime(int?kind,?int?num)?throws?InterruptedException?{
          ????Thread.sleep(2000);
          ????int?sum?=?0;
          ????for?(int?i?=?0;?i?5;?i++)?{
          ????????long?begin?=?System.currentTimeMillis();

          ????????switch?(kind){
          ????????????case?1:
          ????????????????useString();
          ????????????????break;
          ????????????case?2:
          ????????????????useStringBuilder();
          ????????????????break;
          ????????????case?3:
          ????????????????useStringSpliceOneStr();
          ????????????????break;
          ????????????case?4:
          ????????????????useStringBuilderSpliceOneStr();
          ????????????????break;
          ????????????default:
          ????????????????return?0;
          ????????}

          ????????long?end?=?System.currentTimeMillis();

          ????????if(i?>?5){
          ????????????sum?+=?(end?-?begin);
          ????????}
          ????}
          ????return?sum?/?num;
          }

          主方法

          public?class?StringTest?{
          ????public?static?final?int?CYCLE_NUM_BIGGER?=?10_000_000;
          ????public?static?final?int?CYCLE_NUM_LOWER?=?10_000;
          ????public?static?final?String?str1?=?"張三";
          ????public?static?final?String?str2?=?"李四";
          ????public?static?final?String?str3?=?"王五";
          ????public?static?final?String?str4?=?"趙六";
          ?
          ?
          ????public?static?void?main(String[]?args)?throws?InterruptedException?{
          ????????int?time?=?0;
          ????????int?num?=?5;
          ?
          ????????time?=?executeSometime(1,?num);
          ????????System.out.println("String拼接?"+?CYCLE_NUM_BIGGER?+"?次,"?+?num?+?"次平均時間:"?+?time?+?"?ms");
          ?
          ????????time?=?executeSometime(2,?num);
          ????????System.out.println("StringBuilder拼接?"+?CYCLE_NUM_BIGGER?+"?次,"?+?num?+?"次平均時間:"?+?time?+?"?ms");
          ?
          ????????time?=?executeSometime(3,?num);
          ????????System.out.println("String拼接單個字符串?"+?CYCLE_NUM_LOWER?+"?次,"?+?num?+?"次平均時間:"?+?time?+?"?ms");
          ?
          ????????time?=?executeSometime(4,?num);
          ????????System.out.println("StringBuilder拼接單個字符串?"+?CYCLE_NUM_LOWER?+"?次,"?+?num?+?"次平均時間:"?+?time?+?"?ms");
          ?
          ????}
          }??

          測試結果

          測試結果如下

          結果分析

          第一組

          10_000_000 次循環(huán)拼接,在循環(huán)內使用 String 和 StringBuilder 的效率是一樣的!為什么呢?

          使用?javap -c StringTest.class?反編譯查看兩個方法編譯后的文件:

          可以發(fā)現(xiàn) String 方法拼接字符串編譯器優(yōu)化后使用的就是 StringBuilder、因此用例1 和用例2 的效率是一樣的。

          第二組

          第二組的結果就是大家喜聞樂見的了,由于 10_000_000 次循環(huán)String 拼接實在太慢所以我采用了 10_000 次拼接來分析。

          分析用例3:雖然編譯器會對 String 拼接做優(yōu)化,但是它每次在循環(huán)內創(chuàng)建 StringBuilder 對象,在循環(huán)內銷毀。下次循環(huán)他有創(chuàng)建。相比較用例4在循環(huán)外創(chuàng)建,多了 n 次 new 對象、銷毀對象的操作、n - 1 次將 StringBuilder 轉換成 String 的操作 。效率低也是理所應當了。

          擴展

          第一組的測試還有一種寫法:

          /**
          ?*?循環(huán)內?使用?StringBuilder?拼接字符串,一次循環(huán)后銷毀
          ?*/

          public?static?void?useStringBuilderOut(){
          ????StringBuilder?sb?=?new?StringBuilder();
          ????for?(int?i?=?0;?i?//????????????sb.setLength(0);
          ????????sb.delete(0,?sb.length());
          ????????String?s?=?sb.append(str1).append(i).append(str2).append(i).append(str3).append(i).append(str4).toString();
          ????}
          }

          循環(huán)外創(chuàng)建 StringBuilder 每次循環(huán)開始的時候清空 StringBuilder 的內容然后拼接。這種寫法無論使用?sb.setLength(0);?還是?sb.delete(0, sb.length());?效率都比直接在循環(huán)內使用?String / StringBuilder慢。奈何才疏學淺我一直想不明白為什么他慢。我猜測是 new 對象的速度比重置長度慢,于是這樣測試了以下:

          public?static?void?createStringBuider()?{
          ????for?(int?i?=?0;?i?????????StringBuilder?sb?=?new?StringBuilder();
          ????}
          }

          public?static?void?cleanStringBuider()?{
          ????StringBuilder?sb?=?new?StringBuilder();
          ????for?(int?i?=?0;?i?????????sb.delete(0,?sb.length());
          ????}
          }

          但是結果是 cleanStringBuider 更快。讓我摸不著頭腦

          如果有大神看到希望可以幫忙分析分析

          結論

          編譯器會將 String 拼接優(yōu)化成使用 StringBuilder,但是還是有一些缺陷的。主要體現(xiàn)在循環(huán)內使用字符串拼接,編譯器不會創(chuàng)建單個 StringBuilder 以復用

          對于多次循環(huán)內拼接一個字符串的需求:StringBuilder 很快,因為其避免了 n 次 new 對象、銷毀對象的操作,n - 1 次將 StringBuilder 轉換成 String 的操作

          StringBuilder 拼接不適用于循環(huán)內每次拼接即用的操作方式。因為編譯器優(yōu)化后的 String 拼接也是使用 StringBuilder 兩者的效率一樣。后者寫起來還方便...

          END


          喜歡就三連



          點擊"閱讀原文"可跳轉至我的博客。



          關注 Stephen,一起學習,一起成長。

          瀏覽 28
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  中文字幕第5页 | www.欧美在线观看 | www…黄色在线免费观看 x8x8拨牐拨牐精品视频 | 无码欧美XXXXX | 嫩草91|