Apa perbedaan utama antara StringBuffer
dan StringBuilder
? Apakah ada masalah kinerja saat memutuskan salah satu dari ini?
Apa perbedaan utama antara StringBuffer
dan StringBuilder
? Apakah ada masalah kinerja saat memutuskan salah satu dari ini?
Jawaban:
StringBuffer
disinkronkan, StringBuilder
tidak.
StringBuilder
lebih cepat daripada StringBuffer
karena tidaksynchronized
.
Berikut ini adalah tes benchmark sederhana:
public class Main {
public static void main(String[] args) {
int N = 77777777;
long t;
{
StringBuffer sb = new StringBuffer();
t = System.currentTimeMillis();
for (int i = N; i --> 0 ;) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
{
StringBuilder sb = new StringBuilder();
t = System.currentTimeMillis();
for (int i = N; i > 0 ; i--) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
}
}
Sebuah uji coba memberikan angka 2241 ms
untuk StringBuffer
vs 753 ms
untuk StringBuilder
.
--> 0
dalam satu lingkaran. Butuh waktu sejenak bagi saya untuk menyadari apa artinya itu. Apakah ini sesuatu yang sebenarnya digunakan dalam praktik alih-alih ...; i > 0; i--
sintaks yang biasa ?
i -->
benar-benar mengganggu sintaksis ... Saya pikir itu panah pada awalnya karena komentar tentang seni ASCII.
main()
Juga, patokan Anda tidak adil. Tidak ada pemanasan.
Pada dasarnya, StringBuffer
metode disinkronkan sementara StringBuilder
tidak.
Operasi "hampir" sama, tetapi menggunakan metode yang disinkronkan dalam satu utas terlalu banyak.
Cukup banyak tentang itu.
Kutipan dari StringBuilder API :
Kelas ini [StringBuilder] menyediakan API yang kompatibel dengan StringBuffer, tetapi tanpa jaminan sinkronisasi . Kelas ini dirancang untuk digunakan sebagai pengganti drop-in untuk StringBuffer di tempat-tempat di mana buffer string sedang digunakan oleh utas tunggal (seperti umumnya casing). Jika memungkinkan, disarankan agar kelas ini digunakan dalam preferensi untuk StringBuffer karena akan lebih cepat di sebagian besar implementasi.
Jadi itu dibuat untuk menggantikannya.
Hal yang sama terjadi dengan Vector
dan ArrayList
.
Hashtable
dan HashMap
.
Tetapi perlu untuk mendapatkan perbedaan yang jelas dengan bantuan contoh?
StringBuffer atau StringBuilder
Cukup gunakan StringBuilder
kecuali Anda benar-benar mencoba berbagi buffer di antara utas. StringBuilder
adalah adik laki-laki yang tidak disinkronkan (kurang overhead = lebih efisien) dari StringBuffer
kelas yang disinkronkan asli .
StringBuffer
datang dulu. Sun prihatin dengan kebenaran dalam semua kondisi, jadi mereka membuatnya disinkronkan agar benang aman untuk berjaga-jaga.
StringBuilder
datang kemudian. Sebagian besar penggunaan StringBuffer
adalah utas tunggal dan tidak perlu membayar biaya sinkronisasi.
Karena StringBuilder
merupakan pengganti drop-in untukStringBuffer
tanpa sinkronisasi, tidak akan ada perbedaan antara contoh apa pun.
Jika Anda sedang mencoba untuk berbagi antara benang, Anda dapat menggunakan StringBuffer
, tapi mempertimbangkan apakah tingkat yang lebih tinggi sinkronisasi diperlukan, misalnya mungkin bukan menggunakan StringBuffer, Anda harus melakukan sinkronisasi metode yang menggunakan StringBuilder.
Pertama mari kita lihat kesamaan : Baik StringBuilder dan StringBuffer bisa berubah. Itu berarti Anda dapat mengubah kontennya, dengan di lokasi yang sama.
Perbedaan : StringBuffer bisa berubah dan disinkronkan juga. Sedangkan StringBuilder bisa berubah tetapi tidak disinkronkan secara default.
Arti disinkronkan (sinkronisasi) : Ketika beberapa hal disinkronkan, maka beberapa utas dapat mengakses, dan memodifikasinya tanpa masalah atau efek samping. StringBuffer disinkronkan, sehingga Anda dapat menggunakannya dengan banyak utas tanpa masalah.
Yang mana yang harus digunakan kapan? StringBuilder: Ketika Anda membutuhkan sebuah string, yang dapat dimodifikasi, dan hanya satu utas yang mengakses dan memodifikasinya. StringBuffer: Ketika Anda membutuhkan sebuah string, yang dapat dimodifikasi, dan beberapa utas mengakses dan memodifikasinya.
Catatan : Jangan gunakan StringBuffer secara tidak perlu, yaitu, jangan menggunakannya jika hanya satu utas yang memodifikasi dan mengaksesnya karena memiliki banyak kode penguncian dan pembukaan kunci untuk sinkronisasi yang tidak perlu menghabiskan waktu CPU. Jangan gunakan kunci kecuali jika diperlukan.
Dalam utas tunggal, StringBuffer tidak secara signifikan lebih lambat dari StringBuilder , berkat optimisasi JVM. Dan dalam multithreading, Anda tidak dapat menggunakan StringBuilder dengan aman.
Ini tes saya (bukan benchmark, hanya tes):
public static void main(String[] args) {
String withString ="";
long t0 = System.currentTimeMillis();
for (int i = 0 ; i < 100000; i++){
withString+="some string";
}
System.out.println("strings:" + (System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuffer buf = new StringBuffer();
for (int i = 0 ; i < 100000; i++){
buf.append("some string");
}
System.out.println("Buffers : "+(System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuilder building = new StringBuilder();
for (int i = 0 ; i < 100000; i++){
building.append("some string");
}
System.out.println("Builder : "+(System.currentTimeMillis() - t0));
}
Hasil:
string: 319740
Buffer: 23
Builder: 7!
Jadi Builder lebih cepat daripada Buffer, dan WAY lebih cepat daripada string strings. Sekarang mari kita gunakan Pelaksana untuk banyak utas:
public class StringsPerf {
public static void main(String[] args) {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
//With Buffer
StringBuffer buffer = new StringBuffer();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(buffer));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Buffer : "+ AppendableRunnable.time);
//With Builder
AppendableRunnable.time = 0;
executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(builder));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Builder: "+ AppendableRunnable.time);
}
static void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // code reduced from Official Javadoc for Executors
try {
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (Exception e) {}
}
}
class AppendableRunnable<T extends Appendable> implements Runnable {
static long time = 0;
T appendable;
public AppendableRunnable(T appendable){
this.appendable = appendable;
}
@Override
public void run(){
long t0 = System.currentTimeMillis();
for (int j = 0 ; j < 10000 ; j++){
try {
appendable.append("some string");
} catch (IOException e) {}
}
time+=(System.currentTimeMillis() - t0);
}
}
Sekarang StringBuffers mengambil 157 ms untuk 100000 penambahan. Ini bukan tes yang sama, tetapi dibandingkan dengan 37 ms sebelumnya, Anda dapat dengan aman menganggap bahwa menambahkan StringBuffers lebih lambat dengan penggunaan multithreading . Alasannya adalah bahwa JIT / hotspot / compiler / something membuat optimisasi ketika mendeteksi bahwa tidak perlu memeriksa kunci.
Tetapi dengan StringBuilder, Anda memiliki java.lang.ArrayIndexOutOfBoundsException , karena utas bersamaan mencoba menambahkan sesuatu yang seharusnya tidak ada.
Kesimpulannya adalah Anda tidak perlu mengejar StringBuffers. Dan di mana Anda memiliki utas, pikirkan tentang apa yang mereka lakukan, sebelum mencoba untuk mendapatkan beberapa nanodetik.
withString+="some string"+i+" ; ";
tidak setara dengan dua loop lainnya dan karenanya bukan perbandingan yang adil.
StringBuilder diperkenalkan di Java 1.5 sehingga tidak akan bekerja dengan JVM sebelumnya.
Dari Javadocs :
Kelas StringBuilder menyediakan API yang kompatibel dengan StringBuffer, tetapi tanpa jaminan sinkronisasi. Kelas ini dirancang untuk digunakan sebagai pengganti drop-in untuk StringBuffer di tempat-tempat di mana buffer string sedang digunakan oleh utas tunggal (seperti umumnya casing). Jika memungkinkan, disarankan agar kelas ini digunakan dalam preferensi untuk StringBuffer karena akan lebih cepat di sebagian besar implementasi.
StringBuilder
.
Pertanyaan Yang Cukup Bagus
Inilah perbedaannya, saya perhatikan:
StringBuffer: -
StringBuffer is synchronized
StringBuffer is thread-safe
StringBuffer is slow (try to write a sample program and execute it, it will take more time than StringBuilder)
StringBuilder: -
StringBuilder is not synchronized
StringBuilder is not thread-safe
StringBuilder performance is better than StringBuffer.
Hal yang biasa :-
Keduanya memiliki metode yang sama dengan tanda tangan yang sama. Keduanya bisa berubah.
StringBuffer
StringBuilder
StringBuffer
tanpa perubahan lainnyaappend
dua kali, atau append
dan toString
tidak aman.
StringBuilder
dan StringBuffer
hampir sama. Perbedaannya adalah yang StringBuffer
disinkronkan dan StringBuilder
tidak. Meskipun, StringBuilder
lebih cepat daripada StringBuffer
, perbedaan kinerja sangat sedikit. StringBuilder
adalah pengganti SUN dari StringBuffer
. Itu hanya menghindari sinkronisasi dari semua metode publik. Daripada itu, fungsi mereka sama.
Contoh penggunaan yang baik:
Jika teks Anda akan berubah dan digunakan oleh banyak utas, maka lebih baik digunakan StringBuffer
. Jika teks Anda akan berubah tetapi digunakan oleh utas tunggal, maka gunakan StringBuilder
.
StringBuffer
StringBuffer bisa berubah artinya seseorang dapat mengubah nilai objek. Objek yang dibuat melalui StringBuffer disimpan di heap. StringBuffer memiliki metode yang sama dengan StringBuilder, tetapi setiap metode di StringBuffer disinkronkan yaitu StringBuffer aman untuk thread.
karena ini tidak memungkinkan dua utas untuk secara bersamaan mengakses metode yang sama. Setiap metode dapat diakses oleh satu utas sekaligus.
Tetapi menjadi thread aman juga memiliki kelemahan karena kinerja hit StringBuffer karena properti thread aman. Dengan demikian StringBuilder lebih cepat daripada StringBuffer saat memanggil metode yang sama dari setiap kelas.
Nilai StringBuffer dapat diubah, itu berarti dapat ditetapkan ke nilai baru. Saat ini pertanyaan wawancara yang paling umum, perbedaan antara kelas-kelas di atas. String Buffer dapat dikonversi ke string dengan menggunakan metode toString ().
StringBuffer demo1 = new StringBuffer(“Hello”) ;
// The above object stored in heap and its value can be changed .
demo1=new StringBuffer(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuffer
StringBuilder
StringBuilder sama dengan StringBuffer, yaitu ia menyimpan objek di heap dan juga dapat dimodifikasi. Perbedaan utama antara StringBuffer dan StringBuilder adalah bahwa StringBuilder juga tidak aman. StringBuilder cepat karena tidak aman untuk thread.
StringBuilder demo2= new StringBuilder(“Hello”);
// The above object too is stored in the heap and its value can be modified
demo2=new StringBuilder(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuilder
String
adalah kekal.
StringBuffer
adalah bisa berubah dan disinkronkan.
StringBuilder
juga bisa berubah tetapi tidak disinkronkan.
The javadoc menjelaskan perbedaan:
Kelas ini menyediakan API yang kompatibel dengan StringBuffer, tetapi tanpa jaminan sinkronisasi. Kelas ini dirancang untuk digunakan sebagai pengganti drop-in untuk StringBuffer di tempat-tempat di mana buffer string sedang digunakan oleh utas tunggal (seperti umumnya casing). Jika memungkinkan, disarankan agar kelas ini digunakan dalam preferensi untuk StringBuffer karena akan lebih cepat di sebagian besar implementasi.
StringBuilder
(diperkenalkan di Java 5) identik dengan StringBuffer
, kecuali metodenya tidak disinkronkan. Ini berarti memiliki kinerja yang lebih baik daripada yang terakhir, tetapi kekurangannya adalah tidak aman.
Baca tutorial untuk lebih jelasnya.
Sebuah program sederhana yang menggambarkan perbedaan antara StringBuffer dan StringBuilder:
/**
* Run this program a couple of times. We see that the StringBuilder does not
* give us reliable results because its methods are not thread-safe as compared
* to StringBuffer.
*
* For example, the single append in StringBuffer is thread-safe, i.e.
* only one thread can call append() at any time and would finish writing
* back to memory one at a time. In contrast, the append() in the StringBuilder
* class can be called concurrently by many threads, so the final size of the
* StringBuilder is sometimes less than expected.
*
*/
public class StringBufferVSStringBuilder {
public static void main(String[] args) throws InterruptedException {
int n = 10;
//*************************String Builder Test*******************************//
StringBuilder sb = new StringBuilder();
StringBuilderTest[] builderThreads = new StringBuilderTest[n];
for (int i = 0; i < n; i++) {
builderThreads[i] = new StringBuilderTest(sb);
}
for (int i = 0; i < n; i++) {
builderThreads[i].start();
}
for (int i = 0; i < n; i++) {
builderThreads[i].join();
}
System.out.println("StringBuilderTest: Expected result is 1000; got " + sb.length());
//*************************String Buffer Test*******************************//
StringBuffer sb2 = new StringBuffer();
StringBufferTest[] bufferThreads = new StringBufferTest[n];
for (int i = 0; i < n; i++) {
bufferThreads[i] = new StringBufferTest(sb2);
}
for (int i = 0; i < n; i++) {
bufferThreads[i].start();
}
for (int i = 0; i < n; i++) {
bufferThreads[i].join();
}
System.out.println("StringBufferTest: Expected result is 1000; got " + sb2.length());
}
}
// Every run would attempt to append 100 "A"s to the StringBuilder.
class StringBuilderTest extends Thread {
StringBuilder sb;
public StringBuilderTest (StringBuilder sb) {
this.sb = sb;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb.append("A");
}
}
}
//Every run would attempt to append 100 "A"s to the StringBuffer.
class StringBufferTest extends Thread {
StringBuffer sb2;
public StringBufferTest (StringBuffer sb2) {
this.sb2 = sb2;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb2.append("A");
}
}
}
StringBuffer digunakan untuk menyimpan string karakter yang akan diubah (objek String tidak dapat diubah). Secara otomatis mengembang sesuai kebutuhan. Kelas terkait: String, CharSequence.
StringBuilder ditambahkan di Java 5. Ini identik dalam semua hal dengan StringBuffer kecuali bahwa itu tidak disinkronkan, yang berarti bahwa jika beberapa utas mengaksesnya pada saat yang sama, mungkin ada masalah. Untuk program single-threaded, kasus yang paling umum, menghindari overhead sinkronisasi membuat StringBuilder sangat cepat
StringBuilder
locals biasanya lokal untuk suatu metode, di mana mereka terlihat hanya satu utas.
StringBuffer
disinkronkan, tetapi StringBuilder
tidak. Akibatnya, StringBuilder
lebih cepat dari StringBuffer
.
StringBuffer bisa berubah. Itu dapat berubah dalam hal panjang dan konten. StringBuffers aman digunakan, yang berarti bahwa mereka memiliki metode yang disinkronkan untuk mengontrol akses sehingga hanya satu utas yang dapat mengakses kode tersinkronisasi objek StringBuffer sekaligus. Dengan demikian, objek StringBuffer umumnya aman untuk digunakan dalam lingkungan multi-threaded di mana beberapa thread mungkin mencoba mengakses objek StringBuffer yang sama pada saat yang sama.
StringBuilder Kelas StringBuilder sangat mirip dengan StringBuffer, kecuali bahwa aksesnya tidak disinkronkan sehingga tidak aman untuk thread. Dengan tidak disinkronkan, kinerja StringBuilder bisa lebih baik daripada StringBuffer. Jadi, jika Anda bekerja di lingkungan single-threaded, menggunakan StringBuilder sebagai ganti StringBuffer dapat menghasilkan peningkatan kinerja. Ini juga berlaku untuk situasi lain seperti variabel lokal StringBuilder (yaitu, variabel dalam suatu metode) di mana hanya satu utas yang akan mengakses objek StringBuilder.
StringBuffer:
StringBuilder
String c = a + b
sama dengan String c = new StringBuilder().append(a).append(b).toString()
, jadi tidak lebih cepat. Ini hanya bahwa Anda membuat yang baru untuk setiap penugasan string yang, sementara Anda bisa memiliki hanya satu ( String d = a + b; d = d + c;
yang String d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();
sementara StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();
akan menyimpan satu StringBuilder instanciation).
Pembuat String :
int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.
Penyangga-Tali
StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);
Dianjurkan untuk menggunakan StringBuilder kapan pun dimungkinkan karena lebih cepat daripada StringBuffer. Namun, jika keamanan utas diperlukan, opsi terbaik adalah objek StringBuffer.
Penggunaan yang lebih baik StringBuilder
karena tidak disinkronkan dan karenanya menawarkan kinerja yang lebih baik. StringBuilder
adalah pengganti dari yang lebih lama StringBuffer
.
StringBu(ff|ild)er
adalah variabel lokal yang hanya digunakan oleh satu utas.
Karena StringBuffer
disinkronkan, perlu beberapa upaya ekstra, karenanya berdasarkan kinerja, ini agak lambat StringBuilder
.
Tidak ada perbedaan mendasar antara StringBuilder
dan StringBuffer
, hanya ada beberapa perbedaan di antara mereka. Dalam StringBuffer
metode disinkronkan. Ini berarti bahwa pada suatu waktu hanya satu utas yang dapat beroperasi pada mereka. Jika ada lebih dari satu utas maka utas kedua harus menunggu yang pertama selesai dan yang ketiga harus menunggu yang pertama dan yang kedua selesai dan seterusnya. Ini membuat proses sangat lambat dan karenanya kinerja dalam kasusStringBuffer
rendah.
Di sisi lain, StringBuilder
tidak disinkronkan. Ini berarti bahwa pada suatu waktu beberapa utas dapat beroperasi pada StringBuilder
objek yang sama pada saat yang sama. Ini membuat proses sangat cepat dan karenanya kinerja StringBuilder
tinggi.
A String
adalah objek yang tidak dapat diubah yang artinya nilainya tidak dapat diubah sementara StringBuffer
itu bisa berubah.
Ini StringBuffer
Disinkronkan karenanya thread-safe sedangkan StringBuilder
tidak dan hanya cocok untuk instance single-threaded.
Perbedaan utama StringBuffer
adalah disinkronkan tetapi StringBuilder
tidak. Jika Anda perlu menggunakan lebih dari satu utas, maka StringBuffer direkomendasikan. Namun, sesuai kecepatan eksekusi StringBuilder
lebih cepat daripada StringBuffer
, karena tidak disinkronkan.
Periksa internal metode StringBuffer
penambahan yang disinkronkan dan metode penambahan yang tidak disinkronkan dari StringBuilder
.
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
Karena append adalah synchronized
, StringBuffer
memiliki overhead kinerja dibandingkan dengan StrinbBuilder
skenario multi-threading. Selama Anda tidak berbagi buffer di antara beberapa utas, gunakan StringBuilder
, yang cepat karena tidak adanya synchronized
metode tambahan.
Berikut ini adalah hasil pengujian kinerja untuk String vs StringBuffer vs StringBuilder . Akhirnya, StringBuilder memenangkan Tes. Lihat di bawah ini untuk kode uji dan hasil.
Kode :
private static void performanceTestStringVsStringbuffereVsStringBuilder() {
// String vs StringBiffer vs StringBuilder performance Test
int loop = 100000;
long start = 0;
// String
String str = null;
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
str += i + "test";
}
System.out.println("String - " + (System.currentTimeMillis() - start) + " ms");
// String buffer
StringBuffer sbuffer = new StringBuffer();
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Buffer - " + (System.currentTimeMillis() - start) + " ms");
// String builder
start = System.currentTimeMillis();
StringBuilder sbuilder = new StringBuilder();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Builder - " + (System.currentTimeMillis() - start) + " ms");
}
Hasil :
100000 iterasi untuk menambahkan satu teks
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
10000 iterasi untuk menambahkan satu teks
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms
StringBuffer disinkronkan dan aman, StringBuilder tidak disinkronkan dan lebih cepat.