Pertama -tama kita harus mengingat karakteristik tiga:
1. Definisi
Saat melihat API, Anda akan menemukan string, StringBuffer, dan StringBuilder semuanya mengimplementasikan antarmuka CharSequence. Meskipun mereka semua terkait dengan string, mekanisme pemrosesan mereka berbeda.
2. Gunakan skenario
Skenario Menggunakan Kelas String: Dalam skenario di mana string tidak sering berubah, kelas string dapat digunakan, seperti deklarasi konstanta dan sejumlah kecil operasi variabel.
Skenario Menggunakan Kelas StringBuffer: Ketika operasi string sering dilakukan (seperti splicing, substitusi, penghapusan, dll.) Dan berjalan di lingkungan multi-threaded, Anda dapat mempertimbangkan menggunakan StringBuffer, seperti XML Parsing, parsing parameter http dan enkapsulasi.
Skenario Menggunakan Kelas StringBuilder: Ketika operasi string sering dilakukan (seperti splicing, substitusi, dan penghapusan), dan berjalan di lingkungan satu utamanya, Anda dapat mempertimbangkan menggunakan StringBuilder, seperti perakitan pernyataan SQL, enkapsulasi JSON, dll.
AKU AKU AKU. Analisa
Sederhananya, perbedaan kinerja utama antara tipe string dan tipe StringBuffer sebenarnya bahwa string adalah objek yang tidak dapat diubah, jadi setiap kali Anda mengubah tipe string, sebenarnya setara dengan menghasilkan objek string baru dan kemudian mengarahkan pointer ke objek string baru. Oleh karena itu, yang terbaik adalah tidak menggunakan string untuk string yang sering mengubah konten, karena setiap pembuatan objek akan berdampak pada kinerja sistem, terutama ketika ada terlalu banyak objek yang dirujuk dalam memori, GC JVM akan mulai bekerja, yang pasti akan sangat lambat.
Jika Anda menggunakan kelas StringBuffer, hasilnya akan berbeda. Setiap kali hasilnya akan beroperasi pada objek StringBuffer itu sendiri, alih -alih menghasilkan objek baru dan kemudian mengubah referensi objek. Oleh karena itu, secara umum, kami sarankan menggunakan StringBuffer, terutama ketika objek string sering diubah. Dalam beberapa kasus khusus, splicing string dari objek string sebenarnya ditafsirkan oleh JVM sebagai penyambungan objek StringBuffer. Oleh karena itu, kecepatan objek string tidak lebih lambat dari objek StringBuffer pada saat ini. Terutama dalam pembuatan objek string berikut, efisiensi string jauh lebih cepat daripada StringBuffer:
String s1 = "Ini hanya" + "Simple" + "test"; StringBuffer SB = New StringBuilder ("Ini hanya A"). Tambahkan ("Sederhana"). Tambahkan ("tes");Anda akan terkejut menemukan bahwa kecepatan menghasilkan objek String S1 terlalu cepat, dan saat ini, StringBuffer tidak memiliki keuntungan dalam kecepatan. Bahkan, ini adalah trik JVM. Di mata JVM, ini
String s1 = "Ini hanya tes" + "sederhana" + ";
Sebenarnya:
String s1 = "Ini hanya tes sederhana";
Jadi tentu saja tidak membutuhkan banyak waktu. Tetapi apa yang harus Anda perhatikan di sini adalah bahwa jika string Anda berasal dari objek string lain, kecepatannya tidak secepat itu, misalnya:
String s2 = "Ini hanya"; string s3 = "sederhana"; string s4 = "test"; string s1 = s2 + s3 + s4;
Pada saat ini, JVM akan melakukannya secara teratur dengan cara aslinya.
4. Optimalisasi dan pemrosesan JVM yang mendalam
Apakah benar -benar ada biaya kinerja di atas? Penyambungan string sangat umum, apakah tidak ada optimasi pemrosesan khusus? Jawabannya adalah bahwa optimasi ini dilakukan saat menyusun .java menjadi bytecode di JVM.
Jika program Java ingin berjalan, itu akan memakan waktu dua periode, kompilasi waktu dan jalankan waktu. Pada waktu kompilasi, Java JVM (kompiler) mengubah file java menjadi bytecode. Saat runtime, Java Virtual Machine (JVM) menjalankan bytecode yang dihasilkan waktu kompilasi. Melalui dua periode ini, Java telah mencapai apa yang disebut kompilasi dan berjalan di mana-mana.
Mari kita bereksperimen dengan optimisasi apa yang dibuat selama periode kompilasi, dan kami membuat sepotong kode yang mungkin memiliki biaya kinerja.
concatenation kelas publik {public static void main (string [] args) {string username = "andy"; Usia string = "24"; String job = "pengembang"; Info string = nama pengguna + usia + pekerjaan; System.out.println (info); }}Kompilasi concatenation.java. Dapatkan concatenation.class
javac concatenation.java
Kemudian kami menggunakan JAVAP untuk mendekompilasi file concatenation.class yang dikompilasi. JAVAP -C Concatenation. Jika perintah JAVAP tidak ditemukan, silakan pertimbangkan untuk menambahkan direktori di mana JAVAP berada di variabel lingkungan atau menggunakan jalur lengkap JAVAP.
17: 22: 04 -androidyue ~/workspace_adt/string/src $ javap -c ConcatenationCompiled dari "concatenation.java" complateNation kelas publik {concatenation publik (); Kode: 0: Aload_0 1: Invokespecial #1 // Metode Java/Lang/Object. "<inin>" :() V 4: mengembalikan public static void main (java.lang.string []); Kode: 0: LDC #2 // String Andy 2: Store_1 3: LDC #3 // String 24 5: Store_2 6: LDC #4 // Pengembang String 8: Store_3 9: Baru #5 // Kelas Java/Lang/StringBuilder 12: Dup 13: Invokespecial #6 // Metode Java/Lang/Lang/Lang/String/DUP. Invokevirtual #7 // Metode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/lang/stringBuilder; 20: Aload_2 21: Invokevirtual #7 // Metode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/lang/stringBuilder; 24: Aload_3 25: Invokevirtual #7 // Metode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/lang/stringBuilder; 28: Invokevirtual #8 // Metode Java/Lang/StringBuilder.tostring :() ljava/lang/string; 31: Store 4 33: Getstatic #9 // Field Java/Lang/System.out: ljava/io/printstream; 36: Aload 4 38: Invokevirtual #10 // Metode Java/io/printStream.println: (ljava/lang/string;) v 41: return}Di antara mereka, LDC, toko, dll. Adalah instruksi java bytecode, mirip dengan instruksi perakitan. Komentar berikut menggunakan konten terkait Java untuk penjelasan. Kita dapat melihat bahwa ada banyak pembuat string di atasnya, tetapi kami menyebutnya dalam kode java tanpa tampilan. Ini adalah optimasi yang dibuat oleh Javajvm. Saat Javajvm menemukan splicing string, objek StringBuilder akan dibuat. Penyambungan di belakangnya sebenarnya memanggil metode append dari objek StringBuilder. Dengan cara ini, tidak akan ada masalah yang kita khawatirkan.
5. Mengandalkan optimasi JVM saja?
Karena JVM telah membantu kami mengoptimalkan, apakah cukup untuk hanya mengandalkan optimasi JVM? Tentu saja tidak.
Mari kita lihat sepotong kode yang belum dioptimalkan untuk kinerja rendah
public void implicitUseStringBuilder (string [] nilai) {string result = ""; untuk (int i = 0; i <values.length; i ++) {result += values [i]; } System.out.println (hasil);}Kompilasi dengan javac dan lihat dengan javap
public void implicitusestringBuilder (java.lang.string []); Code: 0: ldc #11 // String 2: store_2 3: iconst_0 4: istore_3 5: iload_3 6: aload_1 7: arraylength 8: if_icmpge 38 11: new #5 // class java/lang/StringBuilder 14: dup 15: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V 18: Aload_2 19: Invokevirtual #7 // Metode Java/Lang/StringBuilder.Append: (ljava/lang/string;) ljava/lang/stringBuilder; 22: aload_1 23: iload_3 24: aaload 25: Invokevirtual #7 // Metode java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringbuilder; 28: Invokevirtual #8 // Metode Java/Lang/StringBuilder.tostring :() ljava/lang/string; 31: Store_2 32: iinc 3, 1 35: goto 5 38: getstatic #9 // field java/lang/system.out: ljava/io/printStream; 41: Aload_2 42: Invokevirtual #10 // Metode Java/io/printStream.println: (ljava/lang/string;) v 45: return
Di antara mereka 8: IF_ICMPGE 38 dan 35: GOTO 5 membentuk loop. 8: IF_ICMPGE 38 berarti bahwa jika perbandingan integer dari tumpukan operan JVM lebih besar atau sama dengan (i <hasil yang berlawanan dari nilai.length), itu akan melompat ke baris 38 (System.out). 35: GOTO 5 berarti melompat langsung ke baris 5.
Tetapi ada hal yang sangat penting di sini bahwa pembuatan objek StringBuilder terjadi di antara loop, yang berarti berapa kali loop akan membuat beberapa objek StringBuilder, yang jelas tidak baik. Kode tingkat rendah telanjang.
Mengoptimalkannya sedikit untuk secara instan meningkatkan kualitas.
public void ExplicitUseStringBuilder (string [] nilai) {stringBuilder result = new stringBuilder (); untuk (int i = 0; i <values.length; i ++) {result.append (nilai [i]); }}Informasi Kompilasi yang sesuai
11: aload_1 12: arraylength 13: if_icmpge 30 16: aload_2 17: aload_1 18: iload_3 19: aaload 20: Invokevirtual #7 // Metode java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/lang/stringbu/langbu: ljava/lang; 23: Pop 24: Iinc 3, 1 27: GOTO 10 30: kembali
Seperti yang dapat dilihat dari atas, 13: IF_ICMPGE 30 dan 27: GOTO 10 membentuk loop loop, sedangkan 0: baru #5 berada di luar loop, jadi StringBuilder tidak dibuat beberapa kali.
Secara umum, kita perlu mencoba menghindari penciptaan pembuat string implisit atau eksplisit di badan loop. Oleh karena itu, mereka yang memahami bagaimana kode tersebut dikompilasi dan bagaimana ia dieksekusi secara internal memiliki tingkat kode yang relatif tinggi.
6. Kesimpulan
Dalam kebanyakan kasus StringBuffer> String
Java.lang.stringbuffer adalah urutan karakter variabel yang aman. Buffer string seperti string, tetapi tidak dapat dimodifikasi. Meskipun berisi urutan karakter tertentu kapan saja, panjang dan konten urutan dapat diubah dengan beberapa panggilan metode. Buffer string dapat digunakan dengan aman dalam program untuk multithreading. Dan metode ini dapat disinkronkan bila perlu, sehingga semua operasi pada contoh tertentu tampaknya terjadi dalam urutan serial yang konsisten dengan urutan panggilan metode yang dibuat oleh setiap utas yang terlibat.
Operasi utama pada StringBuffer adalah metode yang ditambahkan dan dimasukkan, yang dapat kelebihan beban untuk menerima semua jenis data. Setiap metode dapat secara efektif mengubah data yang diberikan menjadi string, dan kemudian menambahkan atau memasukkan karakter string itu ke dalam buffer string. Metode Append selalu menambahkan karakter ini ke akhir buffer; Metode insert menambahkan karakter pada titik yang ditentukan.
Misalnya, jika Z mengacu pada objek buffer string yang kontennya saat ini "mulai", metode ini memanggil z.append ("le") akan membuat buffer string berisi "mengejutkan" (terakumulasi); dan z.insert (4, "le") akan mengubah buffer string menjadi "bintang muda".
Dalam kebanyakan kasus StringBuilder> StringBuffer
java.lang.stringbuilder urutan karakter variabel baru di Java 5.0. Kelas ini menyediakan API yang kompatibel dengan StringBuffer, tetapi tidak dijamin akan disinkronkan, sehingga skenario penggunaannya berulir tunggal. Kelas ini dirancang untuk menjadi pengganti sederhana untuk StringBuffer, ketika buffer string digunakan oleh satu utas (ini umum). Jika memungkinkan, disarankan untuk mengambil kelas ini terlebih dahulu, karena lebih cepat daripada StringBuffer di sebagian besar implementasi. Metode penggunaan keduanya pada dasarnya sama.