Dengan asumsi String a dan b:
a += b
a = a.concat(b)
Di bawah tenda, mereka hal yang sama?
Berikut ini adalah concat decompiled sebagai referensi. I'd seperti untuk mampu mendekompilasi +
operator dan juga untuk melihat apa yang tidak.
public String concat(String s) {
int i = s.length();
if (i == 0) {
return this;
}
else {
char ac[] = new char[count + i];
getChars(0, count, ac, 0);
s.getChars(0, i, ac, count);
return new String(0, count + i, ac);
}
}
Tidak, tidak cukup.
Pertama, ada's sedikit perbedaan dalam semantik. Jika a
adalah null
, kemudian a.concat(b)
melempar NullPointerException
tapi a+=b
akan memperlakukan nilai asli dari a
seolah-olah null
. Selain itu, concat()
metode hanya menerima String
nilai sementara +
operator diam-diam akan mengkonversi argumen String (menggunakan toString()
metode untuk objek). Jadi concat()
metode ini lebih ketat dalam apa yang ia menerima.
Untuk melihat di bawah kap mesin, menulis kelas sederhana dengan a += b;
public class Concat {
String cat(String a, String b) {
a += b;
return a;
}
}
Sekarang membongkar dengan javap -c
(termasuk di Sun JDK). Anda harus melihat daftar termasuk:
java.lang.String cat(java.lang.String, java.lang.String);
Code:
0: new #2; //class java/lang/StringBuilder
3: dup
4: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
7: aload_1
8: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
11: aload_2
12: invokevirtual #4; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: invokevirtual #5; //Method java/lang/StringBuilder.toString:()Ljava/lang/ String;
18: astore_1
19: aload_1
20: areturn
Jadi, a += b
adalah setara dengan
a = new StringBuilder()
.append(a)
.append(b)
.toString();
The concat
metode harus lebih cepat. Namun, dengan lebih strings StringBuilder
metode yang menang, setidaknya dalam hal kinerja.
Kode sumber dari String
dan StringBuilder
(dan paket-pribadi kelas dasar) tersedia di src.zip Sun JDK. Anda dapat melihat bahwa anda sedang membangun sebuah array char (ukuran sesuai kebutuhan) dan kemudian membuangnya ketika anda membuat final String
. Dalam praktek alokasi memori yang sangat cepat.
Update: Sebagai Pawel Adamski catatan, kinerja telah berubah dalam waktu yang lebih baru HotSpot. javac
masih menghasilkan kode yang sama persis, tapi bytecode compiler menipu. Sederhana pengujian sepenuhnya gagal karena seluruh tubuh dari kode dibuang. Menjumlahkan Sistem.identityHashCode
(bukan String.kode hash
) menunjukkan StringBuffer
kode memiliki sedikit keuntungan. Dapat berubah ketika update berikutnya dilepaskan, atau jika anda menggunakan JVM. Dari @lukaseder, daftar HotSpot JVM intrinsics.
Niyaz adalah benar, tapi itu's juga diperhatikan bahwa khusus + operator dapat dikonversi menjadi sesuatu yang lebih efisien oleh compiler Java. Jawa memiliki StringBuilder kelas yang mewakili non-thread-safe, bisa berubah String. Ketika melakukan sekelompok penggabungan String, Java compiler diam-diam mengubah
String a = b + c + d;
ke
String a = new StringBuilder(b).append(c).append(d).toString();
yang besar untuk string adalah secara signifikan lebih efisien. Sejauh yang saya tahu, hal ini tidak terjadi ketika anda menggunakan metode concat.
Namun, concat metode ini lebih efisien ketika menggabungkan String kosong ke yang ada String. Dalam hal ini, JVM tidak perlu membuat objek String baru dan hanya dapat kembali yang sudah ada. Lihat concat dokumentasi untuk mengkonfirmasi hal ini.
Jadi jika anda're super-khawatir tentang efisiensi maka anda harus menggunakan metode concat ketika concatenating mungkin-String kosong, dan menggunakan + sebaliknya. Namun, perbedaan kinerja harus diabaikan dan anda mungkin tidak't pernah khawatir tentang hal ini.
Aku berlari tes serupa seperti @marcio tapi dengan loop berikut ini sebagai pengganti:
String c = a;
for (long i = 0; i < 100000L; i++) {
c = c.concat(b); // make sure javac cannot skip the loop
// using c += b for the alternative
}
Hanya untuk mengukur baik, saya melemparkan di StringBuilder.append()
juga. Masing-masing tes dijalankan 10 kali, dengan 100k repetisi untuk masing-masing berjalan. Berikut ini adalah hasil:
StringBuilder
menang telak. Waktu jam hasilnya adalah 0 untuk paling berjalan, dan terpanjang mengambil 16ms.a += b
membutuhkan waktu sekitar 40000ms (40-an) untuk masing-masing berjalan.concat
hanya membutuhkan 10000ms (10s) per lari.Aku ingin't decompiled kelas untuk melihat internal atau jalankan melalui profiler belum, tapi saya menduga a += b
menghabiskan banyak waktu untuk membuat objek baru dari StringBuilder
dan kemudian mengkonversi mereka kembali ke String
.
Kebanyakan jawaban di sini adalah dari tahun 2008. Terlihat bahwa hal-hal telah berubah dari waktu ke waktu. Saya paling terbaru tolok ukur dibuat dengan JMH menunjukkan bahwa di pulau Jawa 8 +
adalah sekitar dua kali lebih cepat dari concat
.
Patokan saya:
@Warmup(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 200, timeUnit = TimeUnit.MILLISECONDS)
public class StringConcatenation {
@org.openjdk.jmh.annotations.State(Scope.Thread)
public static class State2 {
public String a = "abc";
public String b = "xyz";
}
@org.openjdk.jmh.annotations.State(Scope.Thread)
public static class State3 {
public String a = "abc";
public String b = "xyz";
public String c = "123";
}
@org.openjdk.jmh.annotations.State(Scope.Thread)
public static class State4 {
public String a = "abc";
public String b = "xyz";
public String c = "123";
public String d = "!@#";
}
@Benchmark
public void plus_2(State2 state, Blackhole blackhole) {
blackhole.consume(state.a+state.b);
}
@Benchmark
public void plus_3(State3 state, Blackhole blackhole) {
blackhole.consume(state.a+state.b+state.c);
}
@Benchmark
public void plus_4(State4 state, Blackhole blackhole) {
blackhole.consume(state.a+state.b+state.c+state.d);
}
@Benchmark
public void stringbuilder_2(State2 state, Blackhole blackhole) {
blackhole.consume(new StringBuilder().append(state.a).append(state.b).toString());
}
@Benchmark
public void stringbuilder_3(State3 state, Blackhole blackhole) {
blackhole.consume(new StringBuilder().append(state.a).append(state.b).append(state.c).toString());
}
@Benchmark
public void stringbuilder_4(State4 state, Blackhole blackhole) {
blackhole.consume(new StringBuilder().append(state.a).append(state.b).append(state.c).append(state.d).toString());
}
@Benchmark
public void concat_2(State2 state, Blackhole blackhole) {
blackhole.consume(state.a.concat(state.b));
}
@Benchmark
public void concat_3(State3 state, Blackhole blackhole) {
blackhole.consume(state.a.concat(state.b.concat(state.c)));
}
@Benchmark
public void concat_4(State4 state, Blackhole blackhole) {
blackhole.consume(state.a.concat(state.b.concat(state.c.concat(state.d))));
}
}
Hasil:
Benchmark Mode Cnt Score Error Units
StringConcatenation.concat_2 thrpt 50 24908871.258 ± 1011269.986 ops/s
StringConcatenation.concat_3 thrpt 50 14228193.918 ± 466892.616 ops/s
StringConcatenation.concat_4 thrpt 50 9845069.776 ± 350532.591 ops/s
StringConcatenation.plus_2 thrpt 50 38999662.292 ± 8107397.316 ops/s
StringConcatenation.plus_3 thrpt 50 34985722.222 ± 5442660.250 ops/s
StringConcatenation.plus_4 thrpt 50 31910376.337 ± 2861001.162 ops/s
StringConcatenation.stringbuilder_2 thrpt 50 40472888.230 ± 9011210.632 ops/s
StringConcatenation.stringbuilder_3 thrpt 50 33902151.616 ± 5449026.680 ops/s
StringConcatenation.stringbuilder_4 thrpt 50 29220479.267 ± 3435315.681 ops/s
Tom benar dalam menggambarkan apa + operator tidak. Menciptakan sementara StringBuilder
, menambahkan bagian-bagian, dan selesai dengan toString()
.
Namun, semua jawaban sejauh ini mengabaikan efek dari HotSpot runtime optimasi. Secara khusus, sementara ini operasi diakui sebagai pola-pola umum dan diganti dengan yang lebih efisien kode mesin pada saat run-time.
@marcio: Anda've menciptakan micro-patokan; dengan modern JVM's ini bukan cara yang valid untuk profil kode.
Alasan run-time optimization penting adalah bahwa banyak dari perbedaan-perbedaan ini dalam kode-bahkan termasuk objek-ciptaan-adalah benar-benar berbeda sekali HotSpot akan terjadi. Satu-satunya cara untuk tahu pasti adalah profil kode di situ.
Akhirnya, semua metode ini sebenarnya sangat cepat. Ini mungkin menjadi kasus dini optimasi. Jika anda memiliki kode yang merangkai senar banyak cara untuk mendapatkan kecepatan maksimum yang mungkin tidak ada hubungannya dengan operator yang anda pilih dan bukan algoritma anda're menggunakan!
Bagaimana tentang beberapa pengujian sederhana? Yang digunakan kode di bawah ini:
long start = System.currentTimeMillis();
String a = "a";
String b = "b";
for (int i = 0; i < 10000000; i++) { //ten million times
String c = a.concat(b);
}
long end = System.currentTimeMillis();
System.out.println(end - start);
"b"
versi dilaksanakan di 2500ms.A.concat(b)
dieksekusi di 1200ms.Diuji beberapa kali. The concat()
versi eksekusi mengambil setengah dari waktu rata-rata.
Hasil ini mengejutkan saya karena concat()
metode selalu menciptakan sebuah string baru (kembali "new String(hasil)
". It's juga diketahui bahwa:
String a = new String("a") // more than 20 times slower than String a = "a"
Mengapa tidak't compiler mampu mengoptimalkan string penciptaan di "b" kode, mengetahui itu selalu menghasilkan string yang sama? Itu bisa menghindari string baru penciptaan. Jika anda don't percaya dengan pernyataan di atas, menguji diri anda.
Pada dasarnya, ada dua perbedaan penting antara + dan concat
metode.
Misalnya:
String s = 10 + "Hello";
Dalam kasus ini, output yang harus 10Hello.
String s = "aku"; String s1 = s.concat("am").concat("baik").concat("anak"); Sistem.keluar.println(s1);
Dalam kasus di atas, anda harus menyediakan dua string wajib.
Kasus 1: Misalkan saya concat string yang sama dengan concat operator dengan cara ini
String s="aku"; String s1=s.concat("am").concat("baik").concat("anak"); Sistem.keluar.println(s1);
Dalam kasus ini jumlah dari benda-benda yang diciptakan di kolam renang 7 seperti ini:
Saya am baik anak laki-laki Iam Iamgood Iamgoodboy
Kasus 2:
Sekarang saya akan concatinate string yang sama melalui + operator
String s="aku"+"am"+"baik"+"anak"; Sistem.keluar.println(s);
Dalam kasus di atas total jumlah objek yang dibuat hanya 5.
Sebenarnya ketika kita concatinate string melalui + operator maka mempertahankan StringBuffer class untuk melakukan tugas yang sama sebagai berikut:-
StringBuffer sb = new StringBuffer("aku"); sb.append("am"); sb.append("baik"); sb.append("anak"); Sistem.keluar.println(sb);
Dengan cara ini akan membuat hanya lima objek.
Jadi orang-orang ini adalah perbedaan dasar antara + dan concat metode. Menikmati :)
Demi kelengkapan, saya ingin menambahkan bahwa definisi '+' operator dapat ditemukan di JLS SE8 15.18.1:
Jika hanya satu ekspresi operan bertipe String, maka string konversi (§5.1.11) dilakukan pada operan untuk menghasilkan string pada waktu berjalan.
hasil dari rangkaian string adalah referensi ke objek String yang merupakan rangkaian dari dua operand string. Karakter dari sisi kiri operan mendahului karakter dari kanan operan dalam string baru dibuat.
String objek yang baru dibuat (§12.5) kecuali ekspresi yang ekspresi konstan (§15.28).
Tentang pelaksanaan JLS kata berikut ini:
implementasi dapat memilih untuk melakukan konversi dan rangkaian dalam satu langkah untuk menghindari menciptakan dan kemudian membuang menengah String object. Untuk meningkatkan kinerja diulang string rangkaian, Java compiler dapat menggunakan StringBuffer class atau teknik yang sama untuk mengurangi jumlah menengah objek String yang dibuat oleh evaluasi dari sebuah ekspresi.
Untuk tipe primitif, implementasi juga dapat mengoptimalkan diri kreasi dari bungkus objek dengan mengubah langsung dari primitif untuk tipe string.
Jadi dilihat dari 'Java compiler dapat menggunakan StringBuffer class atau teknik yang sama untuk mengurangi', berbeda penyusun dapat menghasilkan berbeda byte-code.
Dengan + operator dapat bekerja antara string dan string, char, integer, double atau float tipe data nilai. Itu hanya mengubah nilai ke string representasi sebelum rangkaian.
The concat operator hanya dapat dilakukan pada dan dengan string. Cek untuk tipe data kompatibilitas dan melempar kesalahan, jika mereka don't pertandingan.
Kecuali ini, kode yang anda berikan apakah hal yang sama.
Saya don't pikir begitu.
a.concat(b)
ini diimplementasikan dalam String dan saya pikir pelaksanaan didn't banyak berubah sejak awal java mesin. The +
pelaksanaan operasi tergantung pada versi Java dan compiler. Saat ini, +
ini diimplementasikan dengan menggunakan StringBuffer
untuk membuat operasi secepat mungkin. Mungkin di masa depan, hal ini akan berubah. Dalam versi sebelumnya dari jawa +
operasi pada String jauh lebih lambat karena menghasilkan hasil antara.
Saya kira bahwa +=
ini diimplementasikan dengan menggunakan +
dan demikian pula dioptimalkan.
Ketika menggunakan +, kecepatan menurun sebagai string's suhu udara meningkat, tapi ketika menggunakan concat, kecepatan lebih stabil, dan pilihan terbaik adalah menggunakan StringBuilder kelas yang memiliki kecepatan stabil dalam rangka untuk melakukan itu.
Saya kira anda bisa mengerti mengapa. Tapi benar-benar cara terbaik untuk menciptakan panjang string adalah menggunakan StringBuilder() dan append(), baik kecepatan akan diterima.