StringBuilder vs Java හි toString () හි String concatenation


936

toString()පහත දැක්වෙන ක්‍රියාත්මක කිරීම් 2 ට අනුව, වඩාත් සුදුසු වන්නේ:

public String toString(){
    return "{a:"+ a + ", b:" + b + ", c: " + c +"}";
}

හෝ

public String toString(){
    StringBuilder sb = new StringBuilder(100);
    return sb.append("{a:").append(a)
          .append(", b:").append(b)
          .append(", c:").append(c)
          .append("}")
          .toString();
}

?

වැදගත්ම දෙය නම්, අපට ඇත්තේ දේපල 3 ක් පමණක් බැවින් එය වෙනසක් සිදු නොවනු ඇත, නමුත් ඔබ +කොන්කට් සිට මාරු වන්නේ කුමන අවස්ථාවේදීද StringBuilder?


41
ඔබ StringBuilder වෙත මාරු වන්නේ කුමන අවස්ථාවේදීද? එය මතකයට හෝ ක්‍රියාකාරීත්වයට බලපාන විට. නැතහොත් එය විය හැකි විට. ඔබ මෙය කරන්නේ එක් වරක් නූල් කිහිපයක් සඳහා පමණක් නම්, කරදර නොවන්න. නමුත් ඔබ එය නැවත නැවතත් කිරීමට යන්නේ නම්, ඔබ StringBuilder භාවිතා කරන විට මැනිය හැකි වෙනසක් දැකිය යුතුය.
ewall

පරාමිතියේ 100 හි මධ්‍යන්‍යය කුමක්ද?
අසිෆ් මුෂ්තාක්

2
NUnKnown 100 යනු StringBuilder හි ආරම්භක ප්‍රමාණයයි
අනුක්‍රමික නොවන

senonsequitor ඉතින් උපරිම අක්ෂර 100 ක් වේවිද?
අසීෆ් මුෂ්තාක්

10
@ ආරම්භක ප්‍රමාණය පමණක් නොදන්නා අතර, ඔබ ගනුදෙනු කරන නූලෙහි ආසන්න ප්‍රමාණය ඔබ දන්නේ නම්, ඔබට පෙර ප්‍රමාණය StringBuilderකොපමණ ප්‍රමාණයක් වෙන් කළ යුතු දැයි ඔබට කිව හැකිය , එසේ නොමැති නම්, එය අවකාශයෙන් ඉවතට ගියහොත්, එය නිර්මාණය කිරීමෙන් ප්‍රමාණය මෙන් දෙගුණයක් කළ යුතුය. නව char[]අරාව පසුව දත්ත පිටපත් කරන්න - එය මිල අධිකය. ප්‍රමාණය ලබා දීමෙන් ඔබට වංචා කළ හැකි අතර පසුව මෙම අරාව නිර්මාණය කිරීම අවශ්‍ය නොවේ - එබැවින් ඔබේ නූලට ඩොලර් 100 ක් දිග වනු ඇතැයි ඔබ සිතන්නේ නම්, ඔබට StringBuilder එක එම ප්‍රමාණයට සැකසිය හැකි අතර එය කිසි විටෙකත් අභ්‍යන්තරව පුළුල් වීමට අවශ්‍ය නොවේ.
අනුක්‍රමික නොවන

Answers:


975

අනුවාදය 1 වඩාත් සුදුසු වන්නේ එය කෙටි වන නිසා සහ සම්පාදකයා ඇත්ත වශයෙන්ම එය 2 වන අනුවාදය බවට පත් කරනු ඇත - කාර්ය සාධන වෙනසක් නැත.

වැදගත්ම දෙය නම් අපට ඇත්තේ දේපල 3 ක් පමණක් වන අතර එය වෙනසක් සිදු නොවනු ඇත, නමුත් ඔබ කොන්කට් සිට තනන්නා වෙත මාරු වන්නේ කුමන අවස්ථාවේදීද?

ඔබ ලූපයක් සමඟ සමපාත වන මොහොතේ - සාමාන්‍යයෙන් එය සම්පාදකයාට තනිවම ආදේශ කළ නොහැක StringBuilder.


19
එය සත්‍ය නමුත් භාෂා සඳහනෙහි මෙය විකල්පයක් බව ද සඳහන් වේ. ඇත්ත වශයෙන්ම, මම JRE 1.6.0_15 සමඟ සරල පරීක්ෂණයක් කළ අතර, දිරාපත් වූ පන්තියේ කිසිදු සම්පාදක ප්‍රශස්තිකරණයක් මා දුටුවේ නැත.
bruno conde

38
මම ප්‍රශ්නයෙන් කේතය උත්සාහ කළෙමි (JDK 1.6.0_16 මත සම්පාදනය කර ඇත) සහ අපේක්ෂිත පරිදි ප්‍රශස්තිකරණය සොයා ගතිමි. මට විශ්වාසයි සියලුම නවීන සම්පාදකයින් එය කරනු ඇත.
මයිකල් බොර්ග්වර්ඩ්

22
ඔබ හරි. බයිට් කේතය දෙස බලන විට මට පැහැදිලිවම ස්ට්‍රිංබිල්ඩර් ප්‍රශස්තිකරණය දැකිය හැකිය. මම ඩෙකොම්පයිලර් භාවිතා කරමින් සිටි අතර, සමහර විට එය නැවත කොන්කට් බවට පරිවර්තනය වේ. +1
un නෝ කොන්ඩේ

81
මිය ගිය අශ්වයෙකුට පහර දීමට නොව, පිරිවිතරයේ ඇති වචන නම්: To increase the performance of repeated string concatenation, a Java compiler _may_ use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.එහි ඇති ප්‍රධාන වචනය විය හැකිය . මෙය නිල වශයෙන් විකල්පයක් බැවින් (බොහෝ දුරට ක්‍රියාත්මක වුවද) අප අපවම ආරක්ෂා කර ගත යුතු නොවේද?
ලූකස්

95
Uc ලූකස්: නැහැ, අපි එසේ නොකළ යුතුයි. සම්පාදකයා එම ප්‍රශස්තිකරණය සිදු නොකිරීමට තීරණය කරන්නේ නම්, එය එය වටින්නේ නැති නිසා ය. නඩු වලින් 99% ක්ම, කුමන ප්‍රශස්තිකරණය වටිනවාද යන්න සම්පාදකයා හොඳින් දනී, එබැවින් රීතියක් ලෙස dev මැදිහත් නොවිය යුතුය. ඇත්ත වශයෙන්ම, ඔබේ තත්ත්වය හැක අනෙක් 1% වැටෙන, නමුත් එම පමණක් මිණුම් සලකුණු (ප්රවේශම්) විසින් පරීක්ෂා කළ හැක.
sleske

260

වැදගත්ම දෙය නම්, ඔබ එක තැනක එක තැනක ලිවීම හෝ කාලයත් සමඟ එය රැස් කිරීමද යන්නයි.

ඔබ දුන් උදාහරණය සඳහා, පැහැදිලිවම StringBuilder භාවිතා කිරීමේ තේරුමක් නැත. (ඔබේ පළමු අවස්ථාව සඳහා සම්පාදනය කළ කේතය දෙස බලන්න.)

නමුත් ඔබ ලූපයක් තුළ නූලක් සාදන්නේ නම්, StringBuilder භාවිතා කරන්න.

පැහැදිලි කිරීම සඳහා, දැවැන්ත අරාවෙහි නූල් දහස් ගණනක් අඩංගු යැයි උපකල්පනය කරමින්, මේ වගේ කේතය:

...
String result = "";
for (String s : hugeArray) {
    result = result + s;
}

සාපේක්ෂව ඉතා කාලය හා මතකය නාස්තියකි:

...
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
    sb.append(s);
}
String result = sb.toString();

3
ඔව්, සංගීත වස්තුව නැවත නැවත නිර්මාණය කිරීමට StringBuilder හට අවශ්‍ය නොවේ.
ඔල්ගා

129
දම්මිත් මම වැඩ කරන විශාල නූලක් පරීක්ෂා කිරීම සඳහා එම 2 ශ්‍රිත භාවිතා කළෙමි. 6.51min vs 11secs
user1722791

1
ඔබටත් භාවිතා කළ හැකි ආකාරය result += s;අනුව (පළමු උදාහරණයේ)
RAnders00

1
මෙම ප්‍රකාශයෙන් කොපමණ වස්තුවක් නිර්මාණය වේද? "{a:"+ a + ", b:" + b + ", c: " + c +"}";
අසිෆ් මුෂ්තාක්

1
වැනි දෙයක් ගැන කුමක් කිව හැකිද: නූල් str = (a == null)? null: a '+ (b == null)? null: b '+ (c == null)? c: c '+ ...; ? එමඟින් ප්‍රශස්තිකරණය සිදුවීම වලක්වනු ඇත්ද?
amitfr

77

බොහෝ අවස්ථාවන්හීදී, ප්‍රවේශයන් දෙක අතර සත්‍ය වෙනසක් ඔබට නොපෙනේ, නමුත් මෙවැනි නරකම තත්වයක් තැනීම පහසුය:

public class Main
{
    public static void main(String[] args)
    {
        long now = System.currentTimeMillis();
        slow();
        System.out.println("slow elapsed " + (System.currentTimeMillis() - now) + " ms");

        now = System.currentTimeMillis();
        fast();
        System.out.println("fast elapsed " + (System.currentTimeMillis() - now) + " ms");
    }

    private static void fast()
    {
        StringBuilder s = new StringBuilder();
        for(int i=0;i<100000;i++)
            s.append("*");      
    }

    private static void slow()
    {
        String s = "";
        for(int i=0;i<100000;i++)
            s+="*";
    }
}

ප්‍රතිදානය:

slow elapsed 11741 ms
fast elapsed 7 ms

ගැටළුව වන්නේ + = නූලකට එකතු කිරීම නව නූලක් ප්‍රතිනිර්මාණය කිරීමයි, එබැවින් ඔබේ නූල්වල දිගට රේඛීය යමක් වැය වේ (දෙකේම එකතුව).

ඉතින් - ඔබේ ප්‍රශ්නයට:

දෙවන ප්‍රවේශය වේගවත් වනු ඇත, නමුත් එය කියවිය නොහැකි හා නඩත්තු කිරීමට අපහසුය. මම කී පරිදි, ඔබේ විශේෂිත අවස්ථාවෙහිදී ඔබට වෙනස නොපෙනේ.


.Concat () ගැන අමතක නොකරන්න. මුල් පෝස්ට් උදාහරණය වැනි කෙටි නූල් භාවිතා කරන විට ගතවන කාලය එම්එස් 10 සිට 18 දක්වා ඕනෑම තැනක තිබිය යුතු යැයි මම සිතමි.
ඩ්‍රූ

9
ඔබ නිවැරදියි +=, මුල් උදාහරණය අනුක්‍රමය +, සම්පාදකයා තනි string.concatඇමතුමකට පරිවර්තනය කරයි . ඔබගේ ප්‍රති results ල අදාළ නොවේ.
බ්ලින්ඩි

1
L බ්ලින්ඩි සහ ඩ්‍රූ: - ඔබ දෙදෙනාම නිවැරදිය.
perilbrain

3
ඔහුගේ ටෝස්ට්‍රිං () ලූපයකින් නොකියන බව ඔබ දන්නවාද?
ඔම්රි යාදන්

වේගය පරීක්ෂා කිරීම සඳහා මම මෙම උදාහරණය උත්සාහ කර ඇත්තෙමි. එබැවින් මගේ ප්‍රති results ල: මන්දගාමී 29672 ms; වේගයෙන් ගතවූ 15 එම්.එස්. එබැවින් පිළිතුර පැහැදිලිය. නමුත් එය පුනරාවර්තන 100 ක් නම් - කාලය සමාන වේ - 0 එම්එස්. පුනරාවර්තන 500 ක් නම් - 16 එම්එස් සහ 0 එම්එස්. සහ යනාදි.
අර්නස්ටාස් ග ru ඩිස්

75

මම කැමතියි:

String.format( "{a: %s, b: %s, c: %s}", a, b, c );

... එය කෙටි හා කියවිය හැකි බැවිනි.

මම ඇත නැත වේගය සඳහා මෙම උපරිම ඵල ඔබ ඉතා ඉහළ නැවත ගණන් සමග පුඩුවක් ඇතුළත එය භාවිතා නොකරයි නම් සහ කාර්ය සාධනය වෙනස මැන ඇත.

මම එකඟ වෙමි, ඔබට පරාමිතීන් විශාල ප්‍රමාණයක් ප්‍රතිදානය කිරීමට සිදුවුවහොත්, මෙම පෝරමය ව්‍යාකූල විය හැකිය (එක් අදහස් දැක්වීමක් මෙන්). මෙම අවස්ථාවේ දී මම වඩාත් කියවිය හැකි ආකෘතියකට මාරු වන්නෙමි (සමහර විට ToachetringBuilder of apache-commons - matt b හි පිළිතුරෙන් ගත්) භාවිතා කර නැවත කාර්ය සාධනය නොසලකා හරිනු ඇත.


65
එය සැබවින්ම දිගු, වැඩි සංකේත අඩංගු වන අතර විචල්‍යයන් පෙළක් අනුපිළිවෙලින් බැහැරව ඇත.
ටොම් හෝවින් -

4
ඉතින් ඔබ කියන්නේ එය අනෙක් ප්‍රවේශයන්ට වඩා කියවිය නොහැකි බවයි.
ටැංජන්ස්

3
මම මෙය ලිවීමට කැමැත්තක් දක්වන්නේ, වැඩි විචල්‍යයන් එකතු කිරීම පහසු නිසා, නමුත් එය වඩා කියවිය හැකි යැයි මට විශ්වාස නැත - විශේෂයෙන් තර්ක ගණන විශාල වන විට. ඔබට විවිධ වේලාවන්හි බිටු එකතු කිරීමට අවශ්‍ය අවස්ථාවන් සඳහාද එය ක්‍රියා නොකරයි.
ඇලෙක්ස් ෆයින්මන්

78
කියවීමට අපහසු බව පෙනේ (මට). දැන් මට {...} සහ පරාමිතීන් අතර නැවත නැවතත් පරිලෝකනය කළ යුතුය.
ස්ටීව් කුඕ

10
මම මෙම පෝරමයට වඩා කැමතියි, මන්ද එක් පරාමිතියක් නම් එය ආරක්ෂිතයිnull
rds

28

උපග්‍රන්ථය හෝ + භාවිතා කළ යුතුද යන්න පිළිබඳව මගේ ලොක්කා සමඟ ගැටුමක් ඇති විය .ඔවුන් උපග්‍රන්ථය භාවිතා කරන විට (නව වස්තුවක් නිර්මාණය කරන සෑම අවස්ථාවකම ඔවුන් පවසන පරිදි මට තවමත් හඳුනාගත නොහැක). ඒ නිසා මම ආර් & ඩී ටිකක් කරන්න හිතුවා. මම මයිකල් බොර්ග්වාර්ඩ් පැහැදිලි කිරීමට ආදරය කළත් අනාගතයේදී යමෙකුට දැන ගැනීමට අවශ්‍ය නම් පැහැදිලි කිරීමක් පෙන්වීමට අවශ්‍ය විය.

/**
 *
 * @author Perilbrain
 */
public class Appc {
    public Appc() {
        String x = "no name";
        x += "I have Added a name" + "We May need few more names" + Appc.this;
        x.concat(x);
        // x+=x.toString(); --It creates new StringBuilder object before concatenation so avoid if possible
        //System.out.println(x);
    }

    public void Sb() {
        StringBuilder sbb = new StringBuilder("no name");
        sbb.append("I have Added a name");
        sbb.append("We May need few more names");
        sbb.append(Appc.this);
        sbb.append(sbb.toString());
        // System.out.println(sbb.toString());
    }
}

ඉහත පංතිය විසුරුවා හැරීම එලෙසම පැමිණේ

 .method public <init>()V //public Appc()
  .limit stack 2
  .limit locals 2
met001_begin:                                  ; DATA XREF: met001_slot000i
  .line 12
    aload_0 ; met001_slot000
    invokespecial java/lang/Object.<init>()V
  .line 13
    ldc "no name"
    astore_1 ; met001_slot001
  .line 14

met001_7:                                      ; DATA XREF: met001_slot001i
    new java/lang/StringBuilder //1st object of SB
    dup
    invokespecial java/lang/StringBuilder.<init>()V
    aload_1 ; met001_slot001
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    ldc "I have Added a nameWe May need few more names"
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    aload_0 ; met001_slot000
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lan\
g/StringBuilder;
    invokevirtual java/lang/StringBuilder.toString()Ljava/lang/String;
    astore_1 ; met001_slot001
  .line 15
    aload_1 ; met001_slot001
    aload_1 ; met001_slot001
    invokevirtual java/lang/String.concat(Ljava/lang/String;)Ljava/lang/Strin\
g;
    pop
  .line 18
    return //no more SB created
met001_end:                                    ; DATA XREF: met001_slot000i ...

; ===========================================================================

;met001_slot000                                ; DATA XREF: <init>r ...
    .var 0 is this LAppc; from met001_begin to met001_end
;met001_slot001                                ; DATA XREF: <init>+6w ...
    .var 1 is x Ljava/lang/String; from met001_7 to met001_end
  .end method
;44-1=44
; ---------------------------------------------------------------------------


; Segment type: Pure code
  .method public Sb()V //public void Sb
  .limit stack 3
  .limit locals 2
met002_begin:                                  ; DATA XREF: met002_slot000i
  .line 21
    new java/lang/StringBuilder
    dup
    ldc "no name"
    invokespecial java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    astore_1 ; met002_slot001
  .line 22

met002_10:                                     ; DATA XREF: met002_slot001i
    aload_1 ; met002_slot001
    ldc "I have Added a name"
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    pop
  .line 23
    aload_1 ; met002_slot001
    ldc "We May need few more names"
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    pop
  .line 24
    aload_1 ; met002_slot001
    aload_0 ; met002_slot000
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/Object;)Ljava/lan\
g/StringBuilder;
    pop
  .line 25
    aload_1 ; met002_slot001
    aload_1 ; met002_slot001
    invokevirtual java/lang/StringBuilder.toString()Ljava/lang/String;
    invokevirtual java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lan\
g/StringBuilder;
    pop
  .line 28
    return
met002_end:                                    ; DATA XREF: met002_slot000i ...


;met002_slot000                                ; DATA XREF: Sb+25r
    .var 0 is this LAppc; from met002_begin to met002_end
;met002_slot001                                ; DATA XREF: Sb+9w ...
    .var 1 is sbb Ljava/lang/StringBuilder; from met002_10 to met002_end
  .end method
;96-49=48
; ---------------------------------------------------------------------------

ඉහත කේත දෙකෙන් ඔබට පෙනෙන්නේ මයිකල් නිවැරදි බවය. සෑම අවස්ථාවකම එක් එස්බී වස්තුවක් පමණක් නිර්මාණය වේ.


27

ජාවා 1.5 සිට, "+" සහ StringBuilder.append () සමඟ සරල එක පේළියක් එකම බයිට් කේතයක් ජනනය කරයි.

එබැවින් කේත කියවීමේ හැකියාව සඳහා "+" භාවිතා කරන්න.

2 ව්‍යතිරේක:

  • බහු තෙරපුම් පරිසරය: StringBuffer
  • ලූපවල සම්මුතිය: StringBuilder / StringBuffer

22

ජාවා (1.8) හි නවතම අනුවාදය භාවිතා කිරීම, විසුරුවා හැරීම ( javap -c) මඟින් සම්පාදකයා විසින් හඳුන්වා දුන් ප්‍රශස්තිකරණය පෙන්වයි. +එසේම sb.append()සමාන කේතයක් ජනනය කරනු ඇත. කෙසේ වෙතත්, අප භාවිතා කරන්නේ නම් හැසිරීම පරීක්ෂා කිරීම වටී+ for for loop එකක කිරීම වටී.

A සඳහා ලූපයක් භාවිතා කරමින් නූල් එකතු කිරීම

ජාවා:

public String myCatPlus(String[] vals) {
    String result = "";
    for (String val : vals) {
        result = result + val;
    }
    return result;
}

බයිට් කේතය :( forලූප් උපුටා ගැනීම)

12: iload         5
14: iload         4
16: if_icmpge     51
19: aload_3
20: iload         5
22: aaload
23: astore        6
25: new           #3                  // class java/lang/StringBuilder
28: dup
29: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
32: aload_2
33: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: aload         6
38: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
41: invokevirtual #6                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
44: astore_2
45: iinc          5, 1
48: goto          12

Stringbuilder.append භාවිතයෙන් නූල් එකතු කිරීම

ජාවා:

public String myCatSb(String[] vals) {
    StringBuilder sb = new StringBuilder();
    for(String val : vals) {
        sb.append(val);
    }
    return sb.toString();
}

බයිට්කෝඩෝ :( forලූප් උපුටා ගැනීම)

17: iload         5
19: iload         4
21: if_icmpge     43
24: aload_3
25: iload         5
27: aaload
28: astore        6
30: aload_2
31: aload         6
33: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
36: pop
37: iinc          5, 1
40: goto          17
43: aload_2

ටිකක් තියෙනවා වෙනස කැපී පෙනෙන නමුත්. පළමු අවස්ථාවේ දී, +භාවිතා කළ තැන, StringBuilderලූප් පුනරාවර්තනය සඳහා එක් එක් සඳහා නව නිර්මාණය කර ඇති අතර ජනනය කරන ලද ප්‍රති result ලය toString()ඇමතුමක් කිරීමෙන් ගබඩා වේ (29 සිට 41 දක්වා). එබැවින් ඔබ +ක්‍රියාකරු forලූපය භාවිතා කරන අතරතුර ඇත්ත වශයෙන්ම අවශ්‍ය නොවන අතරමැදි නූල් ජනනය කරයි.


1
මෙය ඔරකල් ජේඩීකේ හෝ ඕපන් ජේඩීකේ ද?
ක්‍රිස්ටෝෆ් රූසි

12

ජාවා 9 හි 1 අනුවාදය වේගවත් විය යුත්තේ එය invokedynamicඇමතුමකට පරිවර්තනය වන බැවිනි . වැඩි විස්තර JEP-280 හි සොයාගත හැකිය :

මෙහි අදහස නම්, සමස්ත ස්ට්‍රිංබිල්ඩර් ඇපෙන්ඩ් නැටුම java.lang.invoke.StringConcatFactory වෙත සරල ඉන්වොයිනමික් ඇමතුමක් මගින් ප්‍රතිස්ථාපනය කිරීමයි.


10

පහත උදාහරණය බලන්න:

static final int MAX_ITERATIONS = 50000;
static final int CALC_AVG_EVERY = 10000;

public static void main(String[] args) {
    printBytecodeVersion();
    printJavaVersion();
    case1();//str.concat
    case2();//+=
    case3();//StringBuilder
}

static void case1() {
    System.out.println("[str1.concat(str2)]");
    List<Long> savedTimes = new ArrayList();
    long startTimeAll = System.currentTimeMillis();
    String str = "";
    for (int i = 0; i < MAX_ITERATIONS; i++) {
        long startTime = System.currentTimeMillis();
        str = str.concat(UUID.randomUUID() + "---");
        saveTime(savedTimes, startTime);
    }
    System.out.println("Created string of length:" + str.length() + " in " + (System.currentTimeMillis() - startTimeAll) + " ms");
}

static void case2() {
    System.out.println("[str1+=str2]");
    List<Long> savedTimes = new ArrayList();
    long startTimeAll = System.currentTimeMillis();
    String str = "";
    for (int i = 0; i < MAX_ITERATIONS; i++) {
        long startTime = System.currentTimeMillis();
        str += UUID.randomUUID() + "---";
        saveTime(savedTimes, startTime);
    }
    System.out.println("Created string of length:" + str.length() + " in " + (System.currentTimeMillis() - startTimeAll) + " ms");
}

static void case3() {
    System.out.println("[str1.append(str2)]");
    List<Long> savedTimes = new ArrayList();
    long startTimeAll = System.currentTimeMillis();
    StringBuilder str = new StringBuilder("");
    for (int i = 0; i < MAX_ITERATIONS; i++) {
        long startTime = System.currentTimeMillis();
        str.append(UUID.randomUUID() + "---");
        saveTime(savedTimes, startTime);
    }
    System.out.println("Created string of length:" + str.length() + " in " + (System.currentTimeMillis() - startTimeAll) + " ms");

}

static void saveTime(List<Long> executionTimes, long startTime) {
    executionTimes.add(System.currentTimeMillis() - startTime);
    if (executionTimes.size() % CALC_AVG_EVERY == 0) {
        out.println("average time for " + executionTimes.size() + " concatenations: "
                + NumberFormat.getInstance().format(executionTimes.stream().mapToLong(Long::longValue).average().orElseGet(() -> 0))
                + " ms avg");
        executionTimes.clear();
    }
}

ප්‍රතිදානය:

java bytecode version: 8
java.version: 1.8.0_144
[str1.concat (str2)] සංක්ෂිප්ත
10000 සඳහා සාමාන්‍ය කාලය: 0.096 ms
සාමාන්‍ය 10000 සඳහා
සාමාන්‍ය කාලය: 0.185 ms
සාමාන්‍ය 10000 සඳහා සාමාන්‍ය කාලය: 0.327 ms සාමාන්‍ය සාමාන්‍ය කාලය සංක්ෂිප්ත
10000 සඳහා සාමාන්‍ය කාලය : 0.501 ms සාමාන්‍ය කාලය : 0.656 ms සාමාන්‍යය
දිග තීරුව: 1950000 17745 ms
[str1 + = str2]
10000 සම්මුති සඳහා සාමාන්‍ය කාලය: 0.21 ms
සාමාන්‍ය 10000 සඳහා සාමාන්‍ය කාලය: 0.652 ms සාමාන්‍ය සාමාන්‍ය කාලය සංක්ෂිප්ත 10000: 2.302 ms avg නිර්මාණය කරන ලද දිග නූල්: 1950000 60279 ms
සාමාන්‍ය සාමාන්‍ය කාලය 10000 concatenations: සාමාන්යය 1,129 ms
concatenations 10000 සඳහා සාමාන්ය කාලය: 1,727 ms සාමාන්යය


[str1.append (str2)] සංක්ෂිප්ත
10000 සඳහා සාමාන්‍ය කාලය: සංක්ෂිප්ත 10000 සඳහා සාමාන්‍ය සාමාන්‍ය කාලය: 0.002 ms
සාමාන්‍ය 10000 සඳහා
සාමාන්‍ය කාලය: 0.002 ms
සාමාන්‍ය 10000 සඳහා සාමාන්‍ය කාලය: 0.002 ms
සාමාන්‍ය 10000 සඳහා සාමාන්‍ය කාලය: සාමාන්යය ms 0,002
දිග නිර්මාණය සොයමු: දී 1950000 100 ms

නූල් දිග වැඩි වන විට, සංයුක්ත කාලයද වැඩි වේ.
කොහෙද බව ය StringBuilderඅනිවාර්යයෙන්ම අවශ්ය වේ.
ඔබ දකින පරිදි, සම්මුතිය:UUID.randomUUID()+"---" කාලය සැබවින්ම බලපාන්නේ නැත.

PS: මම හිතන්නේ නැහැ ජාවා හි StringBuilder භාවිතා කරන්නේ කවදාද යන්න මෙහි අනුපිටපතක් කියා.
මෙම ප්‍රශ්නය toString()බොහෝ විට දැවැන්ත නූල්වල සංක්ෂිප්තයන් සිදු නොකෙරේ.


2019 යාවත්කාලීන කිරීම

java8කාලයේ සිට , දේවල් ටිකක් වෙනස් වී ඇත. දැන් (java13), සංක්ෂිප්ත කාලය +=ප්‍රායෝගිකව සමාන බව පෙනේ str.concat(). කෙසේ වෙතත් StringBuilderසංයුක්ත කාලය තවමත් නියත ය . (ඉහත වාචික ප්‍රතිදානය එකතු කිරීම සඳහා ඉහත මුල් පෝස්ට් තරමක් සංස්කරණය කරන ලදි)

java bytecode version: 13
java.version: 13.0.1
[str1.concat (str2)] සංක්ෂිප්ත
10000 සඳහා සාමාන්‍ය කාලය: 0.047 ms
සාමාන්‍ය 10000 සඳහා සාමාන්‍ය කාලය: 0.1 ms
සාමාන්‍ය 10000 සඳහා සාමාන්‍ය කාලය: 0.17 ms
සාමාන්‍ය සාමාන්‍ය කාලය
සංක්ෂිප්ත 10000 සඳහා සාමාන්‍ය කාලය : 0.255 ms සාමාන්‍යය : 0.336 ms සාමාන්‍යය
දිග දිග: 1950000 9147 ms
[str1 + = str2]
10000 සම්මුති සඳහා සාමාන්‍ය කාලය: 0.037 ms
සාමාන්‍ය 10000 සඳහා සාමාන්‍ය කාලය: 0.097 ms
සාමාන්‍ය සාමාන්‍ය කාලය සංක්ෂිප්ත 10000: සංක්ෂිප්ත
10000 සඳහා සාමාන්‍ය කාලය 0.249 ms : 0.298 ms සාමාන්‍ය
සාමාන්‍ය සාමාන්‍ය කාලය සංක්ෂිප්ත 10000: 0.326 ms avg
නිර්මාණය කරන ලද දිග නූල්: 1950000 10191 ms
[str1.append (str2)] සංක්ෂිප්ත
10000 සඳහා සාමාන්‍ය කාලය: සංක්ෂිප්ත 10000 සඳහා සාමාන්‍ය සාමාන්‍ය කාලය: 0.001 ms
සාමාන්‍ය 10000 සඳහා
සාමාන්‍ය කාලය: 0.001 ms
සාමාන්‍ය 10000 සඳහා සාමාන්‍ය කාලය: 0.001 ms
සාමාන්‍ය 10000 සඳහා සාමාන්‍ය කාලය: 0.001 ms
avg දිග නිර්මාණය කරන ලද නූල්: 1950000 43 ms

bytecode:8/java.version:13සංසන්දනය කිරීම හා සසඳන විට හොඳ කාර්යසාධන ප්‍රතිලාභයක් තිබීම වටීbytecode:8/java.version:8


මෙය පිළිගත් පිළිතුර විය යුතුය .. එය කොන්ක්‍රීට් හෝ ස්ට්‍රිංබිල්ඩර් තේරීම තීරණය කරන නූල් ප්‍රවාහයේ ප්‍රමාණය මත රඳා පවතී
user1428716

14 user1428716 FYI: java13දැන් වෙනස් වී ඇති ප්‍රති results ල සමඟ පිළිතුර යාවත්කාලීන කරන ලදි . නමුත් මම හිතන්නේ ප්‍රධාන නිගමනය එලෙසම පවතී.
මැරිනෝස්

9

කාර්ය සාධන හේතූන් මත, +=( Stringසංයුක්තකරණය) භාවිතය අධෛර්යමත් කරනු ලැබේ. හේතුව: ජාවා Stringවෙනස් කළ නොහැකි ය, නව සම්මුතියක් සිදු කරන සෑම අවස්ථාවකම නව Stringඑකක් නිර්මාණය වේ (නව එකක් දැනටමත් සංගීත සංචිතයේ ඇති පැරණි ඒවාට වඩා වෙනස් ඇඟිලි සලකුණක් ඇත ). නව නූල් සෑදීම GC මත පීඩනය යෙදෙන අතර වැඩසටහන මන්දගාමී කරයි: වස්තු නිර්මාණය මිල අධිකය.

පහත කේතය එකවර වඩාත් ප්‍රායෝගික හා පැහැදිලි කළ යුතුය.

public static void main(String[] args) 
{
    // warming up
    for(int i = 0; i < 100; i++)
        RandomStringUtils.randomAlphanumeric(1024);
    final StringBuilder appender = new StringBuilder();
    for(int i = 0; i < 100; i++)
        appender.append(RandomStringUtils.randomAlphanumeric(i));

    // testing
    for(int i = 1; i <= 10000; i*=10)
        test(i);
}

public static void test(final int howMany) 
{
    List<String> samples = new ArrayList<>(howMany);
    for(int i = 0; i < howMany; i++)
        samples.add(RandomStringUtils.randomAlphabetic(128));

    final StringBuilder builder = new StringBuilder();
    long start = System.nanoTime();
    for(String sample: samples)
        builder.append(sample);
    builder.toString();
    long elapsed = System.nanoTime() - start;
    System.out.printf("builder - %d - elapsed: %dus\n", howMany, elapsed / 1000);

    String accumulator = "";
    start = System.nanoTime();
    for(String sample: samples)
        accumulator += sample;
    elapsed = System.nanoTime() - start;
    System.out.printf("concatenation - %d - elapsed: %dus\n", howMany, elapsed / (int) 1e3);

    start = System.nanoTime();
    String newOne = null;
    for(String sample: samples)
        newOne = new String(sample);
    elapsed = System.nanoTime() - start;
    System.out.printf("creation - %d - elapsed: %dus\n\n", howMany, elapsed / 1000);
}

ධාවනය සඳහා ප්‍රති Results ල පහත වාර්තා වේ.

builder - 1 - elapsed: 132us
concatenation - 1 - elapsed: 4us
creation - 1 - elapsed: 5us

builder - 10 - elapsed: 9us
concatenation - 10 - elapsed: 26us
creation - 10 - elapsed: 5us

builder - 100 - elapsed: 77us
concatenation - 100 - elapsed: 1669us
creation - 100 - elapsed: 43us

builder - 1000 - elapsed: 511us
concatenation - 1000 - elapsed: 111504us
creation - 1000 - elapsed: 282us

builder - 10000 - elapsed: 3364us 
concatenation - 10000 - elapsed: 5709793us
creation - 10000 - elapsed: 972us

සංක්ෂිප්ත 1 ක් සඳහා ප්‍රති results ල සලකා නොගැනීම (JIT තවමත් එහි කාර්යය ඉටු කර නැත), සම්මුති 10 ක් සඳහා වුවද කාර්ය සාධන ද penalty ුවම අදාළ වේ; සම්මුතීන් දහස් ගණනක් සඳහා, වෙනස අති විශාලය.

මෙම ඉතා ඉක්මන් අත්හදා බැලීමෙන් උගත හැකි පාඩම් (ඉහත කේතය සමඟ පහසුවෙන් ප්‍රතිනිෂ්පාදනය කළ හැකිය): +=සම්මුති කිහිපයක් අවශ්‍ය වන ඉතා මූලික අවස්ථාවන්හිදී පවා, නූල් එකිනෙක ගැටගැසීමට කිසි විටෙකත් භාවිතා නොකරන්න (පැවසූ පරිදි, නව නූල් සෑදීම කෙසේ හෝ මිල අධික වන අතර පීඩනය යෙදේ GC).


7

Apache Commons-Lang හි ToStringBuilder පන්තියක් ඇති අතර එය භාවිතා කිරීමට පහසුය. එය උපග්‍රන්ථය-තර්කනය හැසිරවීම මෙන්ම ඔබේ ටෝස්ට්‍රිං පෙනුම අවශ්‍ය ආකාරය හැඩතල ගැන්වීම යන දෙකෙහිම හොඳ කාර්යයක් කරයි.

public void toString() {
     ToStringBuilder tsb =  new ToStringBuilder(this);
     tsb.append("a", a);
     tsb.append("b", b)
     return tsb.toString();
}

පෙනෙන ප්‍රතිදානය නැවත ලබා දෙනු com.blah.YourClass@abc1321f[a=whatever, b=foo]ඇත.

හෝ දම්වැල් භාවිතයෙන් වඩාත් ensed නීභවනය වූ ආකාරයකින්:

public void toString() {
     return new ToStringBuilder(this).append("a", a).append("b", b").toString();
}

නැතහොත් පන්තියේ සෑම ක්ෂේත්‍රයක්ම ඇතුළත් කිරීමට පරාවර්තනය භාවිතා කිරීමට ඔබට අවශ්‍ය නම්:

public String toString() {
    return ToStringBuilder.reflectionToString(this);
}

ඔබට අවශ්‍ය නම් ToString හි ශෛලිය රිසිකරණය කළ හැකිය.


4

ToString ක්‍රමය ඔබට හැකි තරම් කියවිය හැකි පරිදි සකසන්න!

මගේ පොතේ මේ සඳහා ඇති එකම ව්‍යතිරේකය වන්නේ එය සැලකිය යුතු සම්පත් ප්‍රමාණයක් පරිභෝජනය කරන බව මට ඔප්පු කළ හැකි නම් :) (ඔව්, මෙයින් අදහස් කරන්නේ පැතිකඩයි)

ජාවා 5 සංස්කාරකය ජාවා හි පෙර සංස්කරණවල භාවිතා කළ අතින් ලියන ලද “ස්ට්‍රිං බෆර්” ප්‍රවේශයට වඩා වේගවත් කේතයක් ජනනය කරන බව සලකන්න. ඔබ මෙය "+" භාවිතා කරන්නේ නම් සහ අනාගත වැඩිදියුණු කිරීම් නොමිලේ ලැබේ.


3

වර්තමාන සම්පාදකයින් සමඟ StringBuilder භාවිතා කිරීම තවමත් අවශ්‍යද යන්න පිළිබඳව යම් විවාදයක් පවතින බව පෙනේ. ඉතින් මම හිතුවා මගේ ශත 2 ක අත්දැකීම් දෙන්නම් කියලා.

මට JDBCප්‍රති k ල 10k වාර්තා කට්ටලයක් ඇත (ඔව්, මට ඒවා සියල්ලම එක කණ්ඩායමකින් අවශ්‍යයි.) + ක්‍රියාකරු භාවිතා කිරීම මගේ යන්ත්‍රය සමඟ විනාඩි 5 ක් පමණ ගත වේ Java 1.8. භාවිතා stringBuilder.append("")කිරීම එකම විමසුම සඳහා තත්පරයකට වඩා අඩු කාලයක් ගතවේ.

එබැවින් වෙනස අති විශාලය. ලූපයක් ඇතුළත StringBuilderවඩා වේගවත් ය.


2
මම හිතන්නේ විවාදය ලූප වලින් පිටත භාවිතා කිරීම ගැන ය. මම හිතන්නේ ඔබට එය ලූපයක් තුළ භාවිතා කිරීමට අවශ්‍ය සම්මුතියක් තිබේ.
ජෝර්දානය

2

කාර්ය සාධනය අනුව '+' භාවිතා කිරීම නූල් සංයුක්ත කිරීම මිල අධික වන්නේ එය ජාවා තුළ නූල් වෙනස් කළ නොහැකි බැවින් එය සම්පූර්ණයෙන්ම නව පිටපතක් සෑදිය යුතු බැවිනි. සම්මුතිය නිතර නිතර සිදුවන්නේ නම් මෙය විශේෂ කාර්යභාරයක් ඉටු කරයි, උදා: ලූපයක් තුළ. මම එවැනි දෙයක් කිරීමට උත්සාහ කරන විට මගේ IDEA යෝජනා කරන්නේ පහත දැක්වේ:

රූප විස්තරය මෙහි ඇතුළත් කරන්න

සාමාන්‍ය රීති:

  • තනි නූල් පැවරුමක් තුළ, String concatenation භාවිතා කිරීම හොඳයි.
  • අක්ෂර දත්ත විශාල ප්‍රමාණයක් සෑදීමට ඔබ ලූප නම්, StringBuffer සඳහා යන්න.
  • නූල් මත + = භාවිතා කිරීම සැමවිටම ස්ට්‍රිං බෆරයක් භාවිතා කිරීමට වඩා අඩු කාර්යක්ෂමතාවයක් ඇති කරයි, එබැවින් එය අනතුරු ඇඟවීමේ සීනු නාද කළ යුතුය - නමුත් සමහර අවස්ථාවල කියවීමේ හැකියාව සමඟ සසඳන විට ලබාගත් ප්‍රශස්තිකරණය නොසැලකිලිමත් වනු ඇත, එබැවින් ඔබේ සාමාන්‍ය බුද්ධිය භාවිතා කරන්න.

මෙන්න මේ මාතෘකාව වටා ලස්සන ජෝන් ස්කීට් බ්ලොග් අඩවියක් .


2
ඔබට බහු නූල් වලින් සමමුහුර්ත ප්‍රවේශය අවශ්‍ය නම් මිස ඔබ කිසි විටෙකත් StringBuffer භාවිතා නොකළ යුතුය. එසේ නොමැතිනම් සමමුහුර්ත කර නැති හා අඩු පොදු කාර්යයක් ඇති StringBuilder ට වැඩි කැමැත්තක් දක්වන්න.
අර්කි ඩර් ලූනි

1

මට පෙන්වා දිය හැකිද, ඔබ එකතුවක් හරහා නැවත ස්ට්‍රිංබිල්ඩර් භාවිතා කිරීමට යන්නේ නම්, ඔබට Apache Commons Lang සහ StringUtils.join () පරීක්ෂා කිරීමට අවශ්‍ය විය හැකිය. (විවිධ රසයන්ගෙන්) ?

නොසලකා කාර්ය සාධනය, එය ඔබ StringBuilders නිර්මාණය කිරීමට ඇති හා ඒ හා සමාන බව පෙනේ දේ සඳහා වළළු සඳහා කරමු මිලියනයෙන් කාලය.


1

මෙන්න මම ජාවා 8 හි පරීක්ෂා කළ දේ

  • String concatenation භාවිතා කිරීම
  • StringBuilder භාවිතා කිරීම

    long time1 = System.currentTimeMillis();
    usingStringConcatenation(100000);
    System.out.println("usingStringConcatenation " + (System.currentTimeMillis() - time1) + " ms");
    
    time1 = System.currentTimeMillis();
    usingStringBuilder(100000);
    System.out.println("usingStringBuilder " + (System.currentTimeMillis() - time1) + " ms");
    
    
    private static void usingStringBuilder(int n)
    {
        StringBuilder str = new StringBuilder();
        for(int i=0;i<n;i++)
            str.append("myBigString");    
    }
    
    private static void usingStringConcatenation(int n)
    {
        String str = "";
        for(int i=0;i<n;i++)
            str+="myBigString";
    }

ඔබ නූල් විශාල සංඛ්‍යාවක් සඳහා නූල් සම්මුතියක් භාවිතා කරන්නේ නම් එය ඇත්තෙන්ම බියකරු සිහිනයකි.

usingStringConcatenation 29321 ms
usingStringBuilder 2 ms

0

මම හිතන්නේ අපි StringBuilder append ප්‍රවේශය සමඟ යා යුතුයි. හේතුව:

  1. String concatenate සෑම අවස්ථාවකම නව නූල් වස්තුවක් නිර්මාණය කරයි (String වෙනස් කළ නොහැකි වස්තුවක් බැවින්), එබැවින් එය වස්තු 3 ක් නිර්මාණය කරයි.

  2. String builder සමඟ එක් වස්තුවක් පමණක් නිර්මාණය වනු ඇත [StringBuilder විකෘති වේ] තවද තවත් නූල් එයට එකතු වේ.


මෙම පිළිතුර පහත් කොට සලකන්නේ ඇයි? docs.oracle.com/javase/8/docs/api/java/util/stream/… - විකෘති අඩු කිරීම
user1428716

-4

ඒ වගේ සරල නූල් සඳහා මම භාවිතා කිරීමට කැමතියි

"string".concat("string").concat("string");

අනුපිළිවෙලින්, මම කියන්නේ නූල් තැනීමේ වඩාත් කැමති ක්‍රමය වන්නේ StringBuilder, String # concat (), පසුව අධික ලෙස පටවන ලද + ක්‍රියාකරු භාවිතා කිරීමයි. StringBuilder යනු + ක්‍රියාකරු භාවිතා කරන ආකාරයටම විශාල නූල් වැඩ කිරීමේදී සැලකිය යුතු කාර්ය සාධනය වැඩි කිරීමකි. .Concat () භාවිතා කිරීමේ එක් ගැටළුවක් නම් එයට NullPointerException විසි කළ හැකිය.


10
කොන්ක්‍රීට් () භාවිතා කිරීම '+' ට වඩා නරක ලෙස ක්‍රියා කිරීමට ඉඩ ඇති හෙයින් ජේඑල්එස් විසින් '+' ස්ට්‍රිංබිල්ඩරයක් බවට පරිවර්තනය කිරීමට ඉඩ ලබා දෙන අතර බොහෝ දුරට ජේවීඑම් සියල්ලම එසේ කරයි හෝ වඩා කාර්යක්ෂම විකල්පයක් භාවිතා කරයි - එය සත්‍යයක් නොවේ. ඔබේ උදාහරණයේ අවම වශයෙන් එක් සම්පූර්ණ අතරමැදි නූලක්වත් නිර්මාණය කර ඉවත දැමිය යුතුය.
ලෝරන්ස් ඩොල්
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.