1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        5種字符串拼接方式的效率比拼,你用對了嗎?

        共 1068字,需瀏覽 3分鐘

         ·

        2022-01-22 19:08

        點擊上方藍色字體,選擇“標星公眾號”

        優(yōu)質文章,第一時間送達

        字符串拼接一般使用“+”,但是“+”不能滿足大批量數(shù)據(jù)的處理,Java中有以下五種方法處理字符串拼接,各有優(yōu)缺點,程序開發(fā)應選擇合適的方法實現(xiàn)。

        1. 加號 “+”
        2. String contact() 方法
        3. StringUtils.join() 方法
        4. StringBuffer append() 方法
        5. StringBuilder append() 方法

        經(jīng)過簡單的程序測試,從執(zhí)行100次到90萬次的時間開銷如下表:

        由此可以看出:

        1. 方法1 加號 “+” 拼接 和 方法2 String contact() 方法 適用于小數(shù)據(jù)量的操作,代碼簡潔方便,加號“+” 更符合我們的編碼和閱讀習慣;

        2. 方法3 StringUtils.join() 方法 適用于將ArrayList轉換成字符串,就算90萬條數(shù)據(jù)也只需68ms,可以省掉循環(huán)讀取ArrayList的代碼;

        3. 方法4 StringBuffer append() 方法 和 方法5 StringBuilder append() 方法 其實他們的本質是一樣的,都是繼承自AbstractStringBuilder,效率最高,大批量的數(shù)據(jù)處理最好選擇這兩種方法。

        4. 方法1 加號 “+” 拼接 和 方法2 String contact() 方法 的時間和空間成本都很高(分析在本文末尾),不能用來做批量數(shù)據(jù)的處理。

        源代碼,供參考

        package?cnblogs.twzheng.lab2;

        /**
        ?*?@author?Tan?Wenzheng
        ?*
        ?*/

        import?java.util.ArrayList;
        import?java.util.List;

        import?org.apache.commons.lang3.StringUtils;

        public?class?TestString?{

        ????private?static?final?int?max?=?100;

        ????public?void?testPlus()?{
        ????????System.out.println(">>>?testPlus()?<<<");

        ????????String?str?=?"";

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

        ????????for?(int?i?=?0;?i?????????????str?=?str?+?"a";
        ????????}

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

        ????????long?cost?=?end?-?start;

        ????????System.out.println("???{str?+?\"a\"}?cost="?+?cost?+?"?ms");
        ????}

        ????public?void?testConcat()?{
        ????????System.out.println(">>>?testConcat()?<<<");

        ????????String?str?=?"";

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

        ????????for?(int?i?=?0;?i?????????????str?=?str.concat("a");
        ????????}

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

        ????????long?cost?=?end?-?start;

        ????????System.out.println("???{str.concat(\"a\")}?cost="?+?cost?+?"?ms");
        ????}

        ????public?void?testJoin()?{
        ????????System.out.println(">>>?testJoin()?<<<");

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

        ????????List?list?=?new?ArrayList();

        ????????for?(int?i?=?0;?i?????????????list.add("a");
        ????????}

        ????????long?end1?=?System.currentTimeMillis();
        ????????long?cost1?=?end1?-?start;

        ????????StringUtils.join(list,?"");

        ????????long?end?=?System.currentTimeMillis();
        ????????long?cost?=?end?-?end1;

        ????????System.out.println("???{list.add(\"a\")}?cost1="?+?cost1?+?"?ms");
        ????????System.out.println("???{StringUtils.join(list,?\"\")}?cost="?+?cost
        ????????????????+?"?ms");
        ????}

        ????public?void?testStringBuffer()?{
        ????????System.out.println(">>>?testStringBuffer()?<<<");

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

        ????????StringBuffer?strBuffer?=?new?StringBuffer();

        ????????for?(int?i?=?0;?i?????????????strBuffer.append("a");
        ????????}
        ????????strBuffer.toString();

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

        ????????long?cost?=?end?-?start;

        ????????System.out.println("???{strBuffer.append(\"a\")}?cost="?+?cost?+?"?ms");
        ????}

        ????public?void?testStringBuilder()?{
        ????????System.out.println(">>>?testStringBuilder()?<<<");

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

        ????????StringBuilder?strBuilder?=?new?StringBuilder();

        ????????for?(int?i?=?0;?i?????????????strBuilder.append("a");
        ????????}
        ????????strBuilder.toString();

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

        ????????long?cost?=?end?-?start;

        ????????System.out
        ????????????????.println("???{strBuilder.append(\"a\")}?cost="?+?cost?+?"?ms");
        ????}
        }

        測試結果:

        1. 執(zhí)行100次, private static final int max = 100;
        >>>?testPlus()?<<<
        ???{str?+?"a"}?cost=0?ms
        >>>?testConcat()?<<<
        ???{str.concat("a")}?cost=0?ms
        >>>?testJoin()?<<<
        ???{list.add("a")}?cost1=0?ms
        ???{StringUtils.join(list,?"")}?cost=20?ms
        >>>?testStringBuffer()?<<<
        ???{strBuffer.append("a")}?cost=0?ms
        >>>?testStringBuilder()?<<<
        ???{strBuilder.append("a")}?cost=0?ms
        1. 執(zhí)行1000次, private static final int max = 1000;
        >>>?testPlus()?<<<
        ???{str?+?"a"}?cost=10?ms
        >>>?testConcat()?<<<
        ???{str.concat("a")}?cost=0?ms
        >>>?testJoin()?<<<
        ???{list.add("a")}?cost1=0?ms
        ???{StringUtils.join(list,?"")}?cost=20?ms
        >>>?testStringBuffer()?<<<
        ???{strBuffer.append("a")}?cost=0?ms
        >>>?testStringBuilder()?<<<
        ???{strBuilder.append("a")}?cost=0?ms
        1. 執(zhí)行1萬次, private static final int max = 10000;
        >>>?testPlus()?<<<
        ???{str?+?"a"}?cost=150?ms
        >>>?testConcat()?<<<
        ???{str.concat("a")}?cost=70?ms
        >>>?testJoin()?<<<
        ???{list.add("a")}?cost1=0?ms
        ???{StringUtils.join(list,?"")}?cost=30?ms
        >>>?testStringBuffer()?<<<
        ???{strBuffer.append("a")}?cost=0?ms
        >>>?testStringBuilder()?<<<
        ???{strBuilder.append("a")}?cost=0?ms
        1. 執(zhí)行10萬次, private static final int max = 100000;
        >>>?testPlus()?<<<
        ???{str?+?"a"}?cost=4198?ms
        >>>?testConcat()?<<<
        ???{str.concat("a")}?cost=1862?ms
        >>>?testJoin()?<<<
        ???{list.add("a")}?cost1=21?ms
        ???{StringUtils.join(list,?"")}?cost=49?ms
        >>>?testStringBuffer()?<<<
        ???{strBuffer.append("a")}?cost=10?ms
        >>>?testStringBuilder()?<<<
        ???{strBuilder.append("a")}?cost=10?ms
        1. 執(zhí)行20萬次, private static final int max = 200000;
        >>>?testPlus()?<<<
        ???{str?+?"a"}?cost=17196?ms
        >>>?testConcat()?<<<
        ???{str.concat("a")}?cost=7653?ms
        >>>?testJoin()?<<<
        ???{list.add("a")}?cost1=20?ms
        ???{StringUtils.join(list,?"")}?cost=51?ms
        >>>?testStringBuffer()?<<<
        ???{strBuffer.append("a")}?cost=20?ms
        >>>?testStringBuilder()?<<<
        ???{strBuilder.append("a")}?cost=16?ms
        1. 執(zhí)行50萬次, private static final int max = 500000;
        >>>?testPlus()?<<<
        ???{str?+?"a"}?cost=124693?ms
        >>>?testConcat()?<<<
        ???{str.concat("a")}?cost=49439?ms
        >>>?testJoin()?<<<
        ???{list.add("a")}?cost1=21?ms
        ???{StringUtils.join(list,?"")}?cost=50?ms
        >>>?testStringBuffer()?<<<
        ???{strBuffer.append("a")}?cost=20?ms
        >>>?testStringBuilder()?<<<
        ???{strBuilder.append("a")}?cost=10?ms
        1. 執(zhí)行90萬次, private static final int max = 900000;
        >>>?testPlus()?<<<
        ???{str?+?"a"}?cost=456739?ms
        >>>?testConcat()?<<<
        ???{str.concat("a")}?cost=186252?ms
        >>>?testJoin()?<<<
        ???{list.add("a")}?cost1=20?ms
        ???{StringUtils.join(list,?"")}?cost=68?ms
        >>>?testStringBuffer()?<<<
        ???{strBuffer.append("a")}?cost=30?ms
        >>>?testStringBuilder()?<<<
        ???{strBuilder.append("a")}?cost=24?ms

        查看源代碼,以及簡單分析

        String contactStringBuffer,StringBuilder 的源代碼都可以在Java庫里找到,有空可以研究研究。

        1.其實每次調用contact()方法就是一次數(shù)組的拷貝,雖然在內存中是處理都是原子性操作,速度非???,但是,最后的return語句會創(chuàng)建一個新String對象,限制了concat方法的速度。

        public?String?concat(String?str)?{
        ????????int?otherLen?=?str.length();
        ????????if?(otherLen?==?0)?{
        ????????????return?this;
        ????????}
        ????????int?len?=?value.length;
        ????????char?buf[]?=?Arrays.copyOf(value,?len?+?otherLen);
        ????????str.getChars(buf,?len);
        ????????return?new?String(buf,?true);
        ????}

        2.StringBuffer 和 StringBuilder 的append方法都繼承自AbstractStringBuilder,整個邏輯都只做字符數(shù)組的加長,拷貝,到最后也不會創(chuàng)建新的String對象,所以速度很快,完成拼接處理后在程序中用strBuffer.toString()來得到最終的字符串。

        /**
        ?????*?Appends?the?specified?string?to?this?character?sequence.
        ?????*?


        ?????*?The?characters?of?the?{@code?String}?argument?are?appended,?in
        ?????*?order,?increasing?the?length?of?this?sequence?by?the?length?of?the
        ?????*?argument.?If?{@code?str}?is?{@code?null},?then?the?four
        ?????*?characters?{@code?"null"}?are?appended.
        ?????*?


        ?????*?Let?n?be?the?length?of?this?character?sequence?just?prior?to
        ?????*?execution?of?the?{@code?append}?method.?Then?the?character?at
        ?????*?index?k?in?the?new?character?sequence?is?equal?to?the?character
        ?????*?at?index?k?in?the?old?character?sequence,?if?k?is?less
        ?????*?than?n;?otherwise,?it?is?equal?to?the?character?at?index
        ?????*?k-n?in?the?argument?{@code?str}.
        ?????*
        ?????*?@param???str???a?string.
        ?????*?@return??a?reference?to?this?object.
        ?????*/
        ????public?AbstractStringBuilder?append(String?str)?{
        ????????if?(str?==?null)?str?=?"null";
        ????????int?len?=?str.length();
        ????????ensureCapacityInternal(count?+?len);
        ????????str.getChars(0,?len,?value,?count);
        ????????count?+=?len;
        ????????return?this;
        ????}

        /**
        ?????*?This?method?has?the?same?contract?as?ensureCapacity,?but?is
        ?????*?never?synchronized.
        ?????*/

        ????private?void?ensureCapacityInternal(int?minimumCapacity)?{
        ????????//?overflow-conscious?code
        ????????if?(minimumCapacity?-?value.length?>?0)
        ????????????expandCapacity(minimumCapacity);
        ????}

        ????/**
        ?????*?This?implements?the?expansion?semantics?of?ensureCapacity?with?no
        ?????*?size?check?or?synchronization.
        ?????*/

        ????void?expandCapacity(int?minimumCapacity)?{
        ????????int?newCapacity?=?value.length?*?2?+?2;
        ????????if?(newCapacity?-?minimumCapacity?0)
        ????????????newCapacity?=?minimumCapacity;
        ????????if?(newCapacity?0)?{
        ????????????if?(minimumCapacity?0)?//?overflow
        ????????????????throw?new?OutOfMemoryError();
        ????????????newCapacity?=?Integer.MAX_VALUE;
        ????????}
        ????????value?=?Arrays.copyOf(value,?newCapacity);
        ????}

        3.字符串的加號“+” 方法, 雖然編譯器對其做了優(yōu)化,使用StringBuilder的append方法進行追加,但是每循環(huán)一次都會創(chuàng)建一個StringBuilder對象,且都會調用toString方法轉換成字符串,所以開銷很大。

        注:執(zhí)行一次字符串“+”,相當于 str = new StringBuilder(str).append("a").toString();

        4.本文開頭的地方統(tǒng)計了時間開銷,根據(jù)上述分析再想想空間的開銷。常說拿空間換時間,反過來是不是拿時間換到了空間呢,但是在這里,其實時間是消耗在了重復的不必要的工作上(生成新的對象,toString方法),所以對大批量數(shù)據(jù)做處理時,加號“+” 和 contact 方法絕對不能用,時間和空間成本都很高。

        來源:cnblogs.com/twzheng/p/5923642.html

        加鋒哥微信:?java1239??
        圍觀鋒哥朋友圈,每天推送Java干貨!

        瀏覽 51
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

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

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            在线免费看成人视频 | 精品成人一区二区三区 | 色欲网站在线网页 | 日韩三级在线 | 男人狂躁女人高潮视频 | 亚洲第一成人网址 | 成人视频网站在线 | 免费操比视频 | 色色视频高清无码 | 亚州色色999 |