<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)里使用 + 拼接字符串?明天不用來上班了!

          共 566字,需瀏覽 2分鐘

           ·

          2021-12-12 22:36


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

          引言

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

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

          測試用例

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

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

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

          第一組:

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

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

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

          /**
          ?*?循環(huán)內(nèi)?使用?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)拼接一個(gè)字符串,循環(huán)結(jié)束后使用字符串,使用后由垃圾回收器回收。也是分別使用 String 和 StringBuilder 拼接

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

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

          /**
          ?*?多次循環(huán)拼接成一個(gè)字符串?用?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);
          ????}
          }

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

          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?+?"次平均時(shí)間:"?+?time?+?"?ms");
          ?
          ????????time?=?executeSometime(2,?num);
          ????????System.out.println("StringBuilder拼接?"+?CYCLE_NUM_BIGGER?+"?次,"?+?num?+?"次平均時(shí)間:"?+?time?+?"?ms");
          ?
          ????????time?=?executeSometime(3,?num);
          ????????System.out.println("String拼接單個(gè)字符串?"+?CYCLE_NUM_LOWER?+"?次,"?+?num?+?"次平均時(shí)間:"?+?time?+?"?ms");
          ?
          ????????time?=?executeSometime(4,?num);
          ????????System.out.println("StringBuilder拼接單個(gè)字符串?"+?CYCLE_NUM_LOWER?+"?次,"?+?num?+?"次平均時(shí)間:"?+?time?+?"?ms");
          ?
          ????}
          }??

          測試結(jié)果

          測試結(jié)果如下

          結(jié)果分析

          第一組

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

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

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

          第二組

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

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

          擴(kuò)展

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

          /**
          ?*?循環(huán)內(nèi)?使用?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)開始的時(shí)候清空 StringBuilder 的內(nèi)容然后拼接。這種寫法無論使用?sb.setLength(0);?還是?sb.delete(0, sb.length());?效率都比直接在循環(huán)內(nèi)使用?String / StringBuilder慢。奈何才疏學(xué)淺我一直想不明白為什么他慢。我猜測是 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());
          ????}
          }

          但是結(jié)果是 cleanStringBuider 更快。讓我摸不著頭腦

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

          結(jié)論

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

          對于多次循環(huán)內(nèi)拼接一個(gè)字符串的需求:StringBuilder 很快,因?yàn)槠浔苊饬?n 次 new 對象、銷毀對象的操作,n - 1 次將 StringBuilder 轉(zhuǎn)換成 String 的操作

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


          推薦閱讀:

          世界的真實(shí)格局分析,地球人類社會底層運(yùn)行原理

          不是你需要中臺,而是一名合格的架構(gòu)師(附各大廠中臺建設(shè)PPT)

          企業(yè)IT技術(shù)架構(gòu)規(guī)劃方案

          論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?

          華為干部與人才發(fā)展手冊(附PPT)

          企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!

          【中臺實(shí)踐】華為大數(shù)據(jù)中臺架構(gòu)分享.pdf

          華為的數(shù)字化轉(zhuǎn)型方法論

          華為如何實(shí)施數(shù)字化轉(zhuǎn)型(附PPT)

          超詳細(xì)280頁Docker實(shí)戰(zhàn)文檔!開放下載

          華為大數(shù)據(jù)解決方案(PPT)

          瀏覽 16
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  免费操网站久久久久 | 成人久久久久久无码 | 欧洲精品99毛片免费高清观看 | 无套中出丰满人妻无码91热 | 欧美日韩中文在线观看 |