18 Pertanyaan: StringBuilder vs Rangkaian string di toString () di Jawa

pertanyaan dibuat di Fri, Sep 9, 2016 12:00 AM

Dengan 2 toString() implementasi di bawah ini, mana yang lebih disukai:

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

atau

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

?

Lebih penting lagi, mengingat kami hanya memiliki 3 properti mungkin tidak membuat perbedaan, tetapi pada titik apa Anda akan beralih dari + concat ke StringBuilder?

    
851
  1. Pada titik apa Anda beralih ke StringBuilder? Ketika itu mempengaruhi memori atau kinerja. Atau kapan mungkin. Jika Anda benar-benar hanya melakukan ini sekali saja, jangan khawatir. Tetapi jika Anda akan melakukannya berulang kali, Anda akan melihat perbedaan yang terukur saat menggunakan StringBuilder.
    2009-10-07 15: 48: 30Z
  2. apa arti dari 100 dalam parameter?
    2016-03-14 11: 50: 17Z
  3. @ UnKnown 100 adalah ukuran awal dari StringBuilder
    2016-03-15 13: 33: 52Z
  4. @ nonsequitor Jadi karakter maksimumnya adalah 100?
    2016-03-15 15: 00: 59Z
  5. @ Tidak diketahui tidak hanya ukuran awal, jika Anda tahu perkiraan ukuran string yang Anda hadapi maka Anda dapat memberi tahu StringBuilder berapa banyak ukuran yang dialokasikan di muka jika tidak , jika kehabisan ruang, harus menggandakan ukuran dengan membuat array char[] baru kemudian menyalin data lebih - yang mahal. Anda dapat menipu dengan memberikan ukuran dan kemudian tidak perlu untuk pembuatan array ini - jadi jika Anda berpikir string Anda akan ~ 100 char panjangnya maka Anda dapat mengatur StringBuilder ke ukuran itu dan itu tidak akan pernah perlu diperluas secara internal.
    2016-03-15 15: 28: 35Z
18 Jawaban                              18                         

Versi 1 lebih disukai karena lebih pendek dan kompiler sebenarnya akan mengubahnya menjadi versi 2 - tidak ada perbedaan kinerja apa pun.

  

Yang lebih penting mengingat kami hanya memiliki 3   properti itu mungkin tidak membuat   perbedaan, tetapi pada titik apa Anda   beralih dari concat ke builder?

Pada titik di mana Anda berada dalam satu lingkaran - saat itulah kompilator tidak dapat menggantikan StringBuilder dengan sendirinya.

    
886
2016-08-09 14: 18: 56Z
  1. Itu benar tetapi referensi bahasa juga menyatakan bahwa ini opsional. Sebenarnya, saya hanya melakukan tes sederhana dengan JRE 1.6.0_15 dan saya tidak melihat optimasi kompiler di kelas yang didekompilasi.
    2009-10-07 16: 07: 19Z
  2. Saya Baru saja mencoba kode dari pertanyaan (dikompilasi pada JDK 1.6.0_16) dan menemukan optimasi seperti yang diharapkan. Saya cukup yakin semua kompiler modern akan melakukannya.
    2009-10-07 16: 12: 00Z
  3. Anda benar. Melihat bytecode saya dapat dengan jelas melihat optimasi StringBuilder. Saya menggunakan decompiler dan, entah bagaimana, itu mengubah kembali ke concat. +1
    2009-10-07 16: 30: 21Z
  4. Bukan untuk mengalahkan kuda mati, tetapi kata-kata dalam spesifikasi adalah: 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. Kata kuncinya adalah boleh . Mengingat ini secara resmi opsional (walaupun kemungkinan besar dilaksanakan) apakah kita tidak melindungi diri kita sendiri?
    2012-08-14 15: 57: 41Z
  5. @ Lucas: Tidak, seharusnya tidak. Jika kompiler memutuskan untuk tidak pelakukan optimasi itu, itu karena itu tidak layak. Dalam 99% kasus, kompiler lebih tahu optimasi mana yang sepadan, sehingga sebagai aturan praktis dev tidak boleh ikut campur. Tentu saja, situasi Anda mungkin termasuk dalam 1% lainnya, tetapi itu hanya dapat diperiksa dengan pembandingan (hati-hati).
    2012-08-24 09: 33: 32Z

Kuncinya adalah apakah Anda menulis satu rangkaian tunggal di satu tempat atau mengumpulkannya dari waktu ke waktu.

Untuk contoh yang Anda berikan, tidak ada gunanya secara eksplisit menggunakan StringBuilder. (Lihatlah kode yang dikompilasi untuk kasus pertama Anda.)

Tetapi jika Anda sedang membangun string mis. di dalam loop, gunakan StringBuilder.

Untuk mengklarifikasi, dengan anggapan bahwa hugeArray berisi ribuan string, kode seperti ini:

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

sangat boros waktu dan memori dibandingkan dengan:

 
...
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
    sb.append(s);
}
String result = sb.toString();
    
229
2009-10-07 15: 47: 43Z
  1. Ya, StringBuilder tidak perlu membuat ulang objek String berulang-ulang.
    2013-09-03 10: 15: 09Z
  2. Sialan, saya menggunakan 2 fungsi itu untuk menguji string besar yang sedang saya kerjakan. 6.51min vs 11secs
    2013-10-12 15: 56: 43Z
  3. Ngomong-ngomong Anda juga bisa menggunakan result += s; (dalam contoh pertama)
    2015-05-28 13: 39: 15Z
  4. berapa banyak objek yang akan dibuat oleh pernyataan ini? "{a:"+ a + ", b:" + b + ", c: " + c +"}";
    2016-03-14 12: 18: 26Z
  5. Bagaimana dengan sesuatu seperti: String str = (a == null)? null: a '+ (b == null)? null: b '+ (c == null)? c: c '+ ...; ? Apakah itu akan mencegah pengoptimalan terjadi?
    2016-07-31 22: 09: 54Z

Saya lebih suka:

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

... karena pendek dan mudah dibaca.

Saya akan tidak mengoptimalkan ini untuk kecepatan kecuali jika Anda menggunakannya di dalam loop dengan jumlah pengulangan yang sangat tinggi dan telah mengukur perbedaan kinerja.

Saya setuju, bahwa jika Anda harus mengeluarkan banyak parameter, formulir ini dapat membingungkan (seperti salah satu komentar katakan). Dalam hal ini saya akan beralih ke formulir yang lebih mudah dibaca (mungkin menggunakan ToStringBuilder dari apache-commons - diambil dari jawaban matt b) dan abaikan kinerja lagi.

    
71
2012-11-26 23: 32: 26Z
  1. Ini sebenarnya lebih panjang, mengandung lebih banyak simbol dan memiliki variabel teks yang tidak sesuai urutan.
    2009-10-07 16: 11: 57Z
  2. Jadi, menurut Anda, apakah itu kurang dapat dibaca daripada salah satu dari pendekatan lain?
    2009-10-07 16: 16: 59Z
  3. Saya lebih suka menulis ini, karena lebih mudah untuk menambahkan lebih banyak variabel, tapi saya tidak yakin itu lebih mudah dibaca - terutama karena jumlah argumen semakin besar. Ini juga tidak berfungsi saat Anda perlu menambahkan bit di waktu yang berbeda.
    2009-10-07 16: 25: 26Z
  4. Tampaknya lebih sulit untuk dibaca (untuk saya). Sekarang saya harus memindai bolak-balik antara {...} dan parameternya.
    2009-10-07 18: 59: 09Z
  5. Saya lebih suka formulir ini, karena aman jika salah satu parameternya null
    2013-01-22 16: 13: 09Z

Dalam kebanyakan kasus, Anda tidak akan melihat perbedaan aktual antara kedua pendekatan, tetapi mudah untuk membuat skenario kasus terburuk seperti ini:

 
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+="*";
    }
}

Outputnya adalah:

 
slow elapsed 11741 ms
fast elapsed 7 ms

Masalahnya adalah bahwa untuk + = menambahkan ke string merekonstruksi string baru, sehingga harganya sesuatu yang linier dengan panjang string Anda (jumlah keduanya).

Jadi - untuk pertanyaan Anda:

Pendekatan kedua akan lebih cepat, tapi itu kurang mudah dibaca dan sulit dipertahankan. Seperti yang saya katakan, dalam kasus spesifik Anda, Anda mungkin tidak akan melihat perbedaannya.

    
67
2010-02-12 09: 38: 51Z
  1. Jangan lupa .concat (). Saya menduga waktu yang telah berlalu untuk berada di mana saja dari 10 hingga 18 ms sehingga diabaikan ketika menggunakan string pendek seperti contoh posting asli.
    2009-10-07 16: 15: 20Z
  2. Meskipun Anda benar tentang +=, contoh aslinya adalah urutan +, yang diubah oleh kompiler menjadi panggilan string.concat tunggal. Hasil Anda tidak berlaku.
    2010-06-28 19: 21: 18Z
  3. @ Blindy & Droo: - Anda berdua benar. Menggunakan .concate dalam skenario seperti itu adalah solusi terbaik, karena + = membuat objek baru setiap kali loop rutin dijalankan.
    2011-12-21 20: 55: 40Z
  4. apakah Anda tahu bahwa toString () tidak dipanggil dalam satu lingkaran?
    2013-03-05 02: 18: 03Z
  5. Saya sudah mencoba contoh ini untuk menguji kecepatan. Jadi hasil saya adalah: lambat berlalu 29.672 ms; cepat berlalu 15 ms. Jadi jawabannya sudah jelas. Tetapi jika itu akan menjadi 100 iterasi - waktu adalah sama - 0 ms. Jika 500 iterasi - 16 ms dan 0 ms. Dan seterusnya.
    2013-08-27 14: 38: 16Z

Saya juga pernah berbenturan dengan bos saya pada kenyataan apakah akan menggunakan append atau +. Karena mereka menggunakan Append (saya masih tidak bisa mencari tahu seperti yang mereka katakan setiap kali sebuah objek baru dibuat). Jadi saya berpikir untuk melakukan R & D. Meskipun saya suka penjelasan Michael Borgwardt tetapi hanya ingin menunjukkan penjelasan jika seseorang benar-benar perlu tahu di masa depan.

 
/**
 *
 * @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());
    }
}

dan pembongkaran kelas di atas keluar sebagai

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

Dari dua kode di atas, Anda dapat melihat Michael benar. Dalam setiap kasus hanya satu objek SB yang dibuat.

    
27
2016-11-03 23: 51: 10Z

Sejak Java 1.5, gabungkan satu baris sederhana dengan "+" dan StringBuilder.append () menghasilkan bytecode yang persis sama.

Jadi, agar kode mudah dibaca, gunakan "+".

2 pengecualian:

  • lingkungan multithreaded: StringBuffer
  • rangkaian dalam loop: StringBuilder /StringBuffer
24
2012-11-15 09: 54: 36Z

Menggunakan Java versi terbaru (1.8) pembongkaran (javap -c) menunjukkan optimisasi yang diperkenalkan oleh kompiler. + juga sb.append() akan menghasilkan kode yang sangat mirip. Namun, akan bermanfaat untuk memeriksa perilaku jika kita menggunakan + dalam perulangan for.

Menambahkan string menggunakan + dalam lingkaran for

Java:

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

ByteCode :( for kutipan loop)

 
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

Menambahkan string menggunakan stringbuilder.append

Java:

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

ByteCdoe :( for kutipan loop)

 
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

Namun ada sedikit perbedaan mencolok . Dalam kasus pertama, di mana +telah digunakan, StringBuilder baru dibuat untuk masing-masing untuk iterasi loop dan hasil yang dihasilkan disimpan dengan melakukan panggilan toString() (29 hingga 41). Jadi Anda menghasilkan String menengah yang benar-benar tidak Anda perlukan saat menggunakan + operator di for loop.

    
22
2015-05-26 08: 12: 10Z
  1. Apakah ini Oracle JDK atau OpenJDK?
    2016-08-18 09: 23: 44Z

Di Java 9 versi 1 harus lebih cepat karena dikonversi ke invokedynamic panggilan. Detail lebih lanjut dapat ditemukan di JEP-280 :

  

Idenya adalah untuk mengganti seluruh tarian append StringBuilder dengan panggilan invokedynamic sederhana ke java.lang.invoke.StringConcatFactory, yang akan menerima nilai-nilai yang memerlukan penggabungan.

    
9
2017-04-03 00: 53: 52Z

Apache Commons-Lang memiliki Kelas ToStringBuilder yang sangat mudah digunakan. Itu melakukan pekerjaan yang bagus untuk menangani logika append serta memformat bagaimana Anda ingin toString Anda terlihat.

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

Akan mengembalikan output yang terlihat seperti com.blah.YourClass@abc1321f[a=whatever, b=foo].

Atau dalam bentuk yang lebih ringkas menggunakan chaining:

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

Atau jika Anda ingin menggunakan refleksi untuk memasukkan setiap bidang kelas:

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

Anda juga dapat menyesuaikan gaya ToString jika Anda mau.

    
7
2010-06-09 16: 57: 01Z

Untuk alasan kinerja, penggunaan += (String gabungan) tidak disarankan. Alasannya adalah: Java String tidak dapat diubah, setiap kali penggabungan baru dilakukan, String baru dibuat (yang baru memiliki sidik jari yang berbeda dari yang lebih lama sudah di kolam String ). Membuat string baru memberi tekanan pada GC dan memperlambat program: pembuatan objek itu mahal.

Kode di bawah ini harus membuatnya lebih praktis dan jelas sekaligus.

 
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);
}

Hasil untuk lari dilaporkan di bawah ini.

 
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

Tidak mempertimbangkan hasil untuk 1 concatenation (JIT belum melakukan tugasnya), bahkan untuk 10 concatenation, penalti performa relevan; untuk ribuan penggabungan, perbedaannya sangat besar.

Pelajaran yang didapat dari percobaan yang sangat cepat ini (mudah direproduksi dengan kode di atas): jangan pernah menggunakan += untuk menyatukan string, bahkan dalam kasus yang sangat mendasar di mana diperlukan beberapa rangkaian (seperti dikatakan, membuat string baru tetap mahal dan memberi tekanan pada GC).

    
7
2016-06-18 20: 14: 33Z

Jadikan metode toString dapat dibaca sebanyak mungkin!

Satu-satunya pengecualian untuk ini dalam buku saya adalah jika Anda dapat membuktikan kepada saya bahwa ia menghabiskan sumber daya yang signifikan :) (Ya, ini berarti membuat profil)

Juga perhatikan bahwa kompiler Java 5 menghasilkan kode lebih cepat daripada pendekatan "StringBuffer" tulisan tangan yang digunakan dalam versi Java yang lebih lama. Jika Anda menggunakan "+" ini, peningkatan di masa mendatang akan datang secara gratis.

    
4
2009-10-07 19: 05: 23Z

Tampaknya ada beberapa perdebatan apakah menggunakan StringBuilder masih diperlukan dengan kompiler saat ini. Jadi saya pikir saya akan memberikan 2 sen pengalaman saya.

Saya memiliki JDBC hasil rekaman 10k(ya, saya membutuhkan semuanya dalam satu batch.) Menggunakan + operator memakan waktu sekitar 5 menit pada mesin saya dengan Java 1.8. Menggunakan stringBuilder.append("") membutuhkan waktu kurang dari satu detik untuk kueri yang sama.

Jadi perbedaannya sangat besar. Di dalam lingkaran StringBuilder jauh lebih cepat.

    
3
2017-04-24 09: 45: 38Z
  1. Saya pikir perdebatannya adalah tentang menggunakannya di luar loop. Saya pikir ada konsensus yang Anda butuhkan untuk menggunakannya di dalam satu loop.
    2017-05-26 18: 20: 54Z

Lihat contoh di bawah ini:

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

static void case1() {
    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() {
    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() {
    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();
        }
}

Output:

  

waktu rata-rata untuk 10.000 konatasi: 0,096 ms rata-rata
  waktu rata-rata untuk 10.000 pertemuan: 0.185 ms rata-rata
  waktu rata-rata untuk 10.000 rangkuman: 0,327 ms rata-rata
  waktu rata-rata untuk 10.000 pertemuan: 0,501 ms rata-rata
  waktu rata-rata untuk 10.000 pertemuan: 0.656 ms rata-rata
  Panjang string yang dibuat: 1950000 di 17745 ms
  waktu rata-rata untuk 10.000 pertemuan: 0.21 ms rata-rata
  waktu rata-rata untuk 10.000 gabungan: 0.652 ms rata-rata
  waktu rata-rata untuk 10.000 pertemuan: 1.129 ms rata-rata
  waktu rata-rata untuk 10.000 konatasi: 1,727 ms rata-rata
  waktu rata-rata untuk 10.000 rangkaian: 2.302 ms rata-rata
  Panjang string yang dibuat: 1950000 di 60279 ms
  waktu rata-rata untuk 10.000 rangkuman: 0,002 ms rata-rata
  waktu rata-rata untuk 10.000 rangkuman: 0,002 ms rata-rata
  waktu rata-rata untuk 10.000 rangkuman: 0,002 ms rata-rata
  waktu rata-rata untuk 10.000 rangkuman: 0,002 ms rata-rata
  waktu rata-rata untuk 10.000 rangkuman: 0,002 ms rata-rata
  Panjang string yang dibuat: 1950000 dalam 100 ms

Seiring bertambahnya panjang string, begitu juga waktu penggabungan.
Di situlah StringBuilder benar-benar dibutuhkan.
Seperti yang Anda lihat, rangkaian: UUID.randomUUID()+"---", tidak terlalu memengaruhi waktu.

PS: Saya tidak berpikir Kapan menggunakan StringBuilder di Java benar-benar merupakan duplikat dari ini.
Pertanyaan ini berbicara tentang toString() yang sebagian besar tidak melakukan rangkaian string besar.

    
2
2018-03-14 11: 58: 22Z

Rangkaian string yang bijak berkinerja baik menggunakan '+' lebih mahal karena harus membuat salinan baru String karena String tidak dapat diubah di java. Ini memainkan peran tertentu jika penggabungan sangat sering, misalnya: di dalam lingkaran. Berikut ini yang disarankan oleh IDEA saya ketika saya berupaya melakukan hal seperti itu:

 masukkan deskripsi gambar di sini

Aturan Umum:

  • Dalam penugasan string tunggal, menggunakan penggabungan string baik-baik saja.
  • Jika Anda mengulang untuk membuat blok besar data karakter, gunakan StringBuffer.
  • Menggunakan + = pada sebuah String akan selalu kurang efisien daripada menggunakan StringBuffer, jadi itu harus membunyikan lonceng peringatan - tetapi dalam kasus-kasus tertentu optimasi yang didapat akan diabaikan dibandingkan dengan masalah keterbacaan, jadi gunakan akal sehat Anda.

Berikut ini adalah blog Jon Skeet yang bagus tentang topik ini.

    
2
2018-06-04 06: 58: 46Z
  1. Anda tidak boleh menggunakan StringBuffer kecuali Anda benar-benar membutuhkan akses yang disinkronkan dari banyak utas. Kalau tidak, pilih StringBuilder yang tidak disinkronkan dan karenanya memiliki overhead yang lebih sedikit.
    2019-05-27 09: 30: 38Z

Dapatkah saya menunjukkan bahwa jika Anda akan beralih ke koleksi dan menggunakan StringBuilder, Anda mungkin ingin memeriksa Apache Commons Lang dan StringUtils.join () (dalam berbagai rasa)?

Terlepas dari kinerjanya, itu akan menghemat Anda karena harus membuat StringBuilders dan untuk perulangan untuk apa yang tampaknya seperti waktu sejuta .

    
1
2009-10-07 16: 02: 37Z

Saya membandingkan empat pendekatan berbeda untuk membandingkan kinerja. Saya sebenarnya tidak tahu apa yang terjadi pada gc, tetapi yang penting bagi saya adalah waktu. Kompiler adalah faktor penting di sini. Saya menggunakan jdk1.8.0_45 di bawah platform window8.1.

 
concatWithPlusOperator = 8
concatWithBuilder = 130
concatWithConcat = 127
concatStringFormat = 3737
concatWithBuilder2 = 46


 
public class StringConcatenationBenchmark {

private static final int MAX_LOOP_COUNT = 1000000;

public static void main(String[] args) {

    int loopCount = 0;
    long t1 = System.currentTimeMillis();
    while (loopCount < MAX_LOOP_COUNT) {
        concatWithPlusOperator();
        loopCount++;
    }
    long t2 = System.currentTimeMillis();
    System.out.println("concatWithPlusOperator = " + (t2 - t1));

    long t3 = System.currentTimeMillis();
    loopCount = 0;
    while (loopCount < MAX_LOOP_COUNT) {
        concatWithBuilder();
        loopCount++;
    }
    long t4 = System.currentTimeMillis();
    System.out.println("concatWithBuilder = " + (t4 - t3));

    long t5 = System.currentTimeMillis();
    loopCount = 0;
    while (loopCount < MAX_LOOP_COUNT) {
        concatWithConcat();
        loopCount++;
    }
    long t6 = System.currentTimeMillis();
    System.out.println("concatWithConcat = " + (t6 - t5));

    long t7 = System.currentTimeMillis();
    loopCount = 0;
    while (loopCount < MAX_LOOP_COUNT) {
        concatStringFormat();
        loopCount++;
    }
    long t8 = System.currentTimeMillis();
    System.out.println("concatStringFormat = " + (t8 - t7));

    long t9 = System.currentTimeMillis();
    loopCount = 0;
    while (loopCount < MAX_LOOP_COUNT) {
        concatWithBuilder2();
        loopCount++;
    }
    long t10 = System.currentTimeMillis();
    System.out.println("concatWithBuilder2 = " + (t10 - t9));
}

private static void concatStringFormat() {
    String s = String.format("%s %s %s %s ", "String", "String", "String", "String");
}

private static void concatWithConcat() {
    String s = "String".concat("String").concat("String").concat("String");
}

private static void concatWithBuilder() {
    StringBuilder builder=new StringBuilder("String");
    builder.append("String").append("String").append("String");
    String s = builder.toString();
}

private static void concatWithBuilder2() {
    String s = new StringBuilder("String").append("String").append("String").append("String").toString();
}

private static void concatWithPlusOperator() {
    String s = "String" + "String" + "String" + "String";
}
}
    
1
2016-09-09 19: 06: 23Z
  1. "String" + "String" dikonversi oleh kompiler menjadi "StringString" - valid untuk String literal atau, lebih tepatnya, string yang merupakan nilai ekspresi konstan - jadi concatWithPlusOperator tidak melakukan penggabungan, periksa ByteCode. Cobalah dengan String s = "String"; s = s + s + s + s; atau lebih ...
    2017-05-17 20: 20: 09Z

Saya pikir kita harus menggunakan pendekatan append StringBuilder. Alasannya adalah

  1. String concatenate akan membuat objek string baru setiap kali (Karena String adalah objek yang tidak dapat diubah), maka String akan membuat 3 objek.

  2. Dengan pembuat String, hanya satu objek yang akan dibuat [StringBuilder dapat dihapus] dan string selanjutnya akan ditambahkan padanya.

- 2
2017-07-25 00: 42: 38Z

Untuk string sederhana seperti itu, saya lebih suka menggunakan

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

Agar, saya akan mengatakan metode yang lebih disukai untuk membangun sebuah string menggunakan StringBuilder, String # concat (), kemudian operator + yang kelebihan beban. StringBuilder adalah peningkatan kinerja yang signifikan ketika bekerja string besar seperti menggunakan operator + adalah penurunan besar dalam kinerja (penurunan eksponensial besar karena ukuran String meningkat). Satu masalah dengan menggunakan .concat () adalah ia dapat melempar NullPointerExceptions.

    
- 4
2009-10-07 16: 11: 39Z
  1. Menggunakan concat () cenderung berkinerja lebih buruk daripada '+' karena JLS memungkinkan '+' untuk dikonversi ke StringBuilder, dan kemungkinan besar semua JVM melakukannya atau gunakan alternatif yang lebih efisien - hal yang sama tidak mungkin benar untuk concat yang harus membuat dan membuang setidaknya satu string perantara lengkap dalam contoh Anda.
    2009-10-07 17: 27: 38Z
sumber ditempatkan sini