Misalkan ada sebuah string, kita akan melakukan banyak operasi penyambungan loop pada string ini, menggunakan "+" akan mendapatkan performa paling rendah. Namun seberapa buruk kinerja ini? Apa hasilnya jika kita juga memasukkan StringBuffer, StringBuilder atau String.concat() ke dalam pengujian kinerja? Artikel ini akan memberikan jawaban atas pertanyaan-pertanyaan tersebut!
Kita akan menggunakan Per4j untuk menghitung kinerja, karena alat ini dapat memberi kita serangkaian indikator kinerja yang lengkap, seperti waktu minimum dan maksimum yang dibutuhkan, deviasi standar periode waktu statistik, dll. Pada kode pengujian, untuk mendapatkan nilai deviasi standar yang akurat, kita akan melakukan pengujian 20 penyambungan "*" sebanyak 50.000 kali. Berikut adalah metode yang akan kita gunakan untuk menggabungkan string:
Copy kode kodenya sebagai berikut:
Operator Penggabungan (+)
Metode concat string concat(String str)
Metode penambahan StringBuffer tambahkan (String str)
Metode penambahan StringBuilder tambahkan (String str)
Terakhir, kita akan melihat bytecode untuk melihat bagaimana sebenarnya metode ini dijalankan. Sekarang, mari kita mulai dengan membuat kelas kita. Perhatikan bahwa untuk menghitung kinerja setiap loop, setiap kode pengujian dalam kode tersebut perlu dibungkus dengan perpustakaan Per4J. Pertama kita tentukan jumlah iterasi
Copy kode kodenya sebagai berikut:
int akhir statis pribadi OUTER_ITERATION=20;
int akhir statis pribadi INNER_ITERATION=50000;
Selanjutnya, kita akan menggunakan 4 metode di atas untuk mengimplementasikan kode pengujian kita.
Copy kode kodenya sebagai berikut:
String addTestStr = "";
String concatTestStr = "";
StringBuffer concatTestSb = null;
StringBuilder concatTestSbu = null;
untuk (int innerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringAddConcat");
tambahkanTestStr = "";
untuk (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
tambahkanTestStr += "*";
stopWatch.stop();
}
untuk (int innerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringConcat");
concatTestStr = "";
untuk (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestStr.concat("*");
stopWatch.stop();
}
untuk (int innerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBufferConcat");
concatTestSb = StringBuffer baru();
untuk (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSb.append("*");
stopWatch.stop();
}
untuk (int innerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBuilderConcat");
concatTestSbu = StringBuilder baru();
untuk (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
concatTestSbu.append("*");
stopWatch.stop();
}
Selanjutnya jalankan program untuk menghasilkan metrik kinerja. Lingkungan operasi saya adalah sistem operasi Windows 7 64-bit, mesin JVM (7-ea) 32-bit dengan memori 4GB dan CPU dual-core Quad 2.00GHz.
Ternyata sempurna seperti yang kita bayangkan. Satu-satunya hal yang menarik adalah mengapa String.concat juga sangat bagus. Kita semua tahu bahwa String adalah kelas konstan (kelas yang tidak akan berubah setelah inisialisasi), jadi mengapa kinerja concat lebih baik? (Catatan Penerjemah: Faktanya, ada masalah dengan kode pengujian penulis asli. Kode pengujian untuk metode concat() harus ditulis sebagai concatTestStr=concatTestStr.concat(“*”).) Untuk menjawab ini pertanyaan, kita harus melihat dekompilasi concat. Bytecode keluar. Paket download artikel ini berisi semua bytecode, tapi sekarang mari kita lihat cuplikan kode concat ini:
Copy kode kodenya sebagai berikut:
46: baru #6; //kelas java/lang/StringBuilder
49: bodoh
50: invokespecial #7; //Metode java/lang/StringBuilder."<init>":()V
53: memuat_1
54: pemanggilan virtual #8; //Metode java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
57: ldc #9; //String *
59: pemanggilan virtual #8; //Metode java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
62: pemanggilan virtual #10; //Metode java/lang/StringBuilder.toString:()
Ljava/lang/String;
65: toko_1
66: termasuk 7, 1
69: pergi ke 38
Kode ini adalah bytecode dari String.concat(). Dari kode ini, kita dapat melihat dengan jelas bahwa metode concat() menggunakan StringBuilder. Performa concat() seharusnya sama bagusnya dengan StringBuilder, namun karena adanya tambahan Creating StringBuilder dan melakukan operasi .append(str).append(str).toString() akan mempengaruhi kinerja concate, jadi StringBuilder dan String Waktu cancate adalah 1,8 dan 3,3.
Oleh karena itu, bahkan ketika melakukan penggabungan yang paling sederhana, jika kita tidak ingin membuat instance StringBuffer atau StringBuilder, kita harus menggunakan concat. Tetapi untuk operasi penyambungan string dalam jumlah besar, kita sebaiknya tidak menggunakan concat (Catatan Penerjemah: Karena fungsi kode pengujian tidak sepenuhnya setara, waktu pemrosesan rata-rata concat dalam kode pengujian yang diganti adalah 1650,9 milidetik. Hasil ini ada di komentar teks asli. ), karena concat akan mengurangi kinerja program Anda dan menghabiskan CPU Anda. Oleh karena itu, untuk mendapatkan performa tertinggi tanpa mempertimbangkan keamanan thread dan sinkronisasi, kita harus mencoba menggunakan StringBuilder.