กรุณาบอกฉันสถานการณ์เวลาจริงเพื่อเปรียบเทียบString, StringBufferและStringBuilder?
กรุณาบอกฉันสถานการณ์เวลาจริงเพื่อเปรียบเทียบString, StringBufferและStringBuilder?
คำตอบ:
ความแตกต่างที่ไม่แน่นอน:
Stringจะไม่เปลี่ยนรูปถ้าคุณพยายามที่จะเปลี่ยนค่าของพวกเขาวัตถุอื่นได้รับการสร้างในขณะที่StringBufferและStringBuilderจะไม่แน่นอนเพื่อให้พวกเขาสามารถเปลี่ยนค่าของพวกเขา
ความแตกต่างของหัวข้อความปลอดภัย:
ความแตกต่างระหว่างStringBufferและStringBuilderคือStringBufferความปลอดภัยของเธรด StringBuilderดังนั้นเมื่อความต้องการใช้ที่จะทำงานเฉพาะในหัวข้อเดียวแล้วมันจะดีกว่าที่จะใช้ จะมีประสิทธิภาพมากกว่าStringBuilderStringBuffer
สถานการณ์:
Stringวัตถุไม่เปลี่ยนรูปStringBuilderดีพอStringBufferเนื่องจากStringBufferเป็นซิงโครนัสเพื่อให้คุณมีความปลอดภัยของเธรดStringsเมื่อเราปรับเปลี่ยนค่าวัตถุอื่นจะถูกสร้างขึ้น การอ้างอิงวัตถุเก่าเป็นโมฆะเพื่อที่อาจเป็นขยะที่รวบรวมโดยGCหรือเป็นขยะแม้แต่การเก็บรวบรวม?
Stringด้วยStringBuilderหรือไม่
Stringเมื่อโครงสร้างที่ไม่เปลี่ยนรูปเหมาะสม การรับลำดับอักขระใหม่จาก a Stringอาจมีการปรับประสิทธิภาพที่ยอมรับไม่ได้ไม่ว่าในเวลา CPU หรือหน่วยความจำ (การได้รับ substrings นั้นมีประสิทธิภาพของ CPU เนื่องจากข้อมูลไม่ได้ถูกคัดลอกStringBuilderเมื่อคุณต้องการสร้างลำดับอักขระที่ไม่แน่นอนโดยปกติแล้วจะเชื่อมต่ออักขระหลายตัวเข้าด้วยกันStringBufferในสถานการณ์เดียวกันกับที่คุณจะใช้StringBuilderแต่เมื่อการเปลี่ยนแปลงกับสตริงที่ต้องถูกซิงโครไนซ์ (เนื่องจากหลายเธรดกำลังอ่าน / แก้ไขดัชนีสตริงบัฟเฟอร์)พื้นฐาน:
Stringเป็นคลาสที่ไม่เปลี่ยนรูปมันไม่สามารถเปลี่ยนแปลงได้
StringBuilderเป็นคลาสที่ไม่แน่นอนที่สามารถผนวกเข้าด้วยอักขระแทนที่หรือลบออกและในที่สุดก็แปลงเป็น a String
StringBufferรุ่นซิงโครไนซ์ดั้งเดิมของStringBuilder
คุณควรเลือกStringBuilderในทุกกรณีที่คุณมีเพียงเธรดเดียวที่เข้าถึงวัตถุของคุณ
รายละเอียด:
โปรดทราบด้วยว่าStringBuilder/Buffersไม่ใช่เวทมนตร์พวกเขาใช้ Array เป็นวัตถุสำรองและ Array นั้นจะต้องได้รับการจัดสรรอีกครั้งเมื่อมันเต็ม ตรวจสอบให้แน่ใจและสร้างStringBuilder/Bufferวัตถุของคุณมีขนาดใหญ่พอที่เดิมซึ่งไม่จำเป็นต้องปรับขนาดใหม่อย่างต่อเนื่องทุกครั้งที่.append()ถูกเรียก
การปรับขนาดใหม่อาจลดลงมาก โดยพื้นฐานแล้วมันจะปรับขนาดของอาเรย์สำรองเป็น 2 เท่าของขนาดปัจจุบันทุกครั้งที่ต้องการขยาย ซึ่งอาจส่งผลให้ RAM จำนวนมากได้รับการจัดสรรและไม่ใช้เมื่อStringBuilder/Bufferคลาสเริ่มมีขนาดใหญ่ขึ้น
ใน Java String x = "A" + "B";ใช้StringBuilderฉากหลัง ดังนั้นในกรณีที่เรียบง่ายไม่มีประโยชน์ที่จะประกาศตัวคุณเอง แต่ถ้าคุณกำลังสร้างStringวัตถุที่มีขนาดใหญ่พูดน้อยกว่า 4k การประกาศStringBuilder sb = StringBuilder(4096);จะมีประสิทธิภาพมากกว่าการต่อข้อมูลหรือใช้ตัวสร้างเริ่มต้นซึ่งมีเพียง 16 ตัวอักษร หากคุณStringกำลังจะน้อยกว่า 10k ให้เริ่มต้นด้วย constructor ที่ 10k เพื่อความปลอดภัย แต่ถ้ามันเริ่มต้นที่ 10k คุณเขียนตัวละครมากกว่า 10k 1 ตัวมันจะได้รับการจัดสรรและคัดลอกไปยังอาร์เรย์ 20k ดังนั้นการเริ่มต้นสูงจึงดีกว่าต่ำ
ในกรณีที่ปรับขนาดอัตโนมัติที่อักขระที่ 17 อาร์เรย์สำรองได้รับการจัดสรรใหม่และคัดลอกไปที่ 32 ตัวอักษรเมื่ออักขระที่ 33 เกิดขึ้นอีกครั้งและคุณจะได้รับการจัดสรรใหม่และคัดลอก Array เป็น 64 ตัวอักษร คุณสามารถดูว่าสิ่งนี้ทำให้การจัดสรรและการคัดลอกซ้ำซ้อนเป็นจำนวนมากซึ่งเป็นสิ่งที่คุณพยายามหลีกเลี่ยงการใช้StringBuilder/Bufferในตอนแรก
นี่คือจากซอร์สโค้ด JDK 6 สำหรับ AbstractStringBuilder
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
วิธีปฏิบัติที่ดีที่สุดคือการเริ่มต้นStringBuilder/Bufferให้ใหญ่กว่าที่คุณคิดเล็กน้อยถ้าคุณไม่รู้ว่าจะใหญ่แค่ไหนStringแต่คุณสามารถเดาได้ การจัดสรรหน่วยความจำมากกว่าหนึ่งเล็กน้อยที่คุณต้องการจะดีกว่าการจัดสรรและการคัดลอกจำนวนมาก
นอกจากนี้ระวังการกำหนดค่าเริ่มต้น a StringBuilder/Bufferด้วยStringซึ่งจะจัดสรรขนาดของอักขระ String + 16 เท่านั้นซึ่งโดยส่วนใหญ่แล้วจะเริ่มต้นการจัดสรรซ้ำอีกครั้งและรอบการคัดลอกที่คุณพยายามหลีกเลี่ยง ต่อไปนี้เป็นข้อมูลโดยตรงจากซอร์สโค้ด Java 6
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
หากคุณบังเอิญจบลงด้วยอินสแตนซ์StringBuilder/Bufferที่คุณไม่ได้สร้างและไม่สามารถควบคุมนวกรรมิกที่เรียกว่ามีวิธีหลีกเลี่ยงพฤติกรรมการจัดสรรซ้ำและการคัดลอกที่แย่ลง โทร.ensureCapacity()ด้วยขนาดที่คุณต้องการเพื่อให้แน่ใจว่าผลลัพธ์ของคุณStringจะพอดี
ทางเลือก:
เช่นเดียวกับโน้ตถ้าคุณกำลังทำจริงๆหนัก Stringอาคารและการจัดการมีประสิทธิภาพมากขึ้นที่มุ่งเน้นทางเลือกที่เรียกว่าเชือก
อีกทางเลือกหนึ่งคือการสร้างการStringListดำเนินการโดยการจัดกลุ่มย่อยArrayList<String>และเพิ่มตัวนับเพื่อติดตามจำนวนอักขระใน.append()การดำเนินการกลายพันธุ์ทุกรายการและอื่น ๆ จากนั้นจึงแทนที่.toString()เพื่อสร้างStringBuilderขนาดที่แน่นอนที่คุณต้องการและวนผ่านรายการและสร้าง ผลลัพธ์คุณยังสามารถสร้างStringBuilderตัวแปรอินสแตนซ์และ 'แคช' ผลลัพธ์.toString()และต้องสร้างใหม่เมื่อมีการเปลี่ยนแปลงบางอย่างเท่านั้น
นอกจากนี้อย่าลืมว่าString.format()เมื่อสร้างผลลัพธ์ที่มีการจัดรูปแบบคงที่ซึ่งสามารถปรับให้เหมาะสมโดยคอมไพเลอร์เมื่อมันทำให้ดีขึ้น
String x = "A" + "B";จริงๆที่จะรวบรวม StringBuilder หรือไม่? ทำไมมันไม่คอมไพล์String x = "AB";มันควรใช้ StringBuilder เท่านั้นถ้าส่วนประกอบไม่รู้จักในเวลาคอมไพล์
คุณหมายถึงการต่อเรียงหรือไม่?
ตัวอย่างโลกจริง: คุณต้องการที่จะสร้างออกสตริงใหม่อื่น ๆ อีกมากมาย
ตัวอย่างเช่นการส่งข้อความ:
เชือก
String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I'm " + user.age + "yrs. old too"
StringBuilder
String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" )
.append(" I saw your profile and got interested in you.<br>")
.append(" I'm " ).append( user.age ).append( "yrs. old too")
.toString()
หรือ
String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as fuzzy lollipop points out.
StringBuffer (ไวยากรณ์ตรงกับ StringBuilder ผลที่แตกต่าง)
เกี่ยวกับ
StringBuffer เมื่อเทียบกับ StringBuilder
อดีตถูกซิงโครไนซ์และในภายหลังไม่ใช่
ดังนั้นหากคุณเรียกใช้หลายครั้งในเธรดเดียว (ซึ่งเป็น 90% ของเคส) StringBuilderจะทำงานเร็วขึ้นมากเพราะจะไม่หยุดเพื่อดูว่ามันเป็นเจ้าของล็อคเธรดหรือไม่
ดังนั้นจึงแนะนำให้ใช้StringBuilder(เว้นแต่แน่นอนว่าคุณมีมากกว่าหนึ่งเธรดที่เข้าถึงมันในเวลาเดียวกันซึ่งหายาก)
Stringการต่อข้อมูล ( ใช้ตัวดำเนินการ + ) อาจได้รับการปรับให้เหมาะสมโดยคอมไพเลอร์ที่จะใช้StringBuilderภายใต้ดังนั้นจึงไม่ใช่สิ่งที่ต้องกังวลอีกต่อไปในวันก่อนหน้าของ Java นี่เป็นสิ่งที่ทุกคนพูดว่าควรหลีกเลี่ยงค่าใช้จ่าย สร้างวัตถุ String ใหม่ คอมไพเลอร์สมัยใหม่จะไม่ทำเช่นนี้อีกต่อไป แต่ก็เป็นวิธีปฏิบัติที่ดีที่จะใช้StringBuilderแทนในกรณีที่คุณใช้คอมไพเลอร์ "เก่า"
แก้ไข
สำหรับผู้ที่อยากรู้อยากเห็นนี่คือสิ่งที่คอมไพเลอร์ทำสำหรับชั้นนี้:
class StringConcatenation {
int x;
String literal = "Value is" + x;
String builder = new StringBuilder().append("Value is").append(x).toString();
}
javap -c StringConcatenation
Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;
java.lang.String literal;
java.lang.String builder;
StringConcatenation();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/lang/StringBuilder
8: dup
9: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
12: ldc #4; //String Value is
14: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_0
18: getfield #6; //Field x:I
21: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
24: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: putfield #9; //Field literal:Ljava/lang/String;
30: aload_0
31: new #2; //class java/lang/StringBuilder
34: dup
35: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
38: ldc #4; //String Value is
40: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: aload_0
44: getfield #6; //Field x:I
47: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
50: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
53: putfield #10; //Field builder:Ljava/lang/String;
56: return
}
บรรทัดที่มีหมายเลข 5 - 27 สำหรับสตริงชื่อ "literal"
บรรทัดที่มีหมายเลข 31-53 สำหรับสตริงชื่อ "builder"
ไม่มีความแตกต่างรหัสเดียวกันนี้ถูกเรียกใช้สำหรับทั้งสองสตริง
StringBuilderทำ String concatenation ทางด้านขวามือของการมอบหมาย การนำไปใช้ที่ดีจะใช้ StringBuilder อยู่เบื้องหลัง นอกจากนี้ตัวอย่างของคุณ"a" + "b"จะได้รับการเรียบเรียงเขียนเป็นตัวอักษรเดียว"ab"แต่ถ้าคุณใช้มันจะส่งผลในสองสายความจำเป็นที่จะStringBuilder append()
"a"+"b"แต่จะพูดว่าString concatenationเกี่ยวกับอะไรที่ฉันเปลี่ยนให้ชัดเจน สิ่งที่คุณไม่พูดคือทำไมการฝึกฝนที่ดีจึงไม่ใช่วิธีที่ดี นั่นคือสิ่งที่คอมไพเลอร์ (สมัยใหม่) ทำ @ ฟัซซี่ฉันเห็นด้วยโดยเฉพาะอย่างยิ่งเมื่อคุณรู้ว่าขนาดของสตริงสุดท้ายจะเป็นอย่างไร (aprox)
-------------------------------------------------- --------------------------------
String StringBuffer StringBuilder
-------------------------------------------------- --------------------------------
พื้นที่จัดเก็บ ฮีปพูลของสตริงคงที่
แก้ไขได้ ไม่ (ไม่เปลี่ยนรูป) ใช่ (ไม่แน่นอน) ใช่ (ไม่แน่นอน)
กระทู้ปลอดภัย ใช่ใช่ไม่
ประสิทธิภาพ | เร็วมากเร็วมาก
-------------------------------------------------- --------------------------------
synchronisedและที่ว่าทำไม
เชือก
String classหมายถึงสตริงตัวอักษร สตริงตัวอักษรทั้งหมดในโปรแกรม Java เช่น"abc"ถูกใช้เป็นอินสแตนซ์ของคลาสนี้
วัตถุสตริงจะไม่เปลี่ยนรูปเมื่อมีการสร้างเราไม่สามารถเปลี่ยนแปลงได้ ( สตริงมีค่าคงที่ )
ถ้า String จะถูกสร้างขึ้นโดยใช้คอนสตรัคหรือวิธีการแล้วสตริงเหล่านั้นจะถูกเก็บไว้ในกองหน่วยความจำSringConstantPoolเช่นเดียวกับ แต่ก่อนที่จะบันทึกในพูลจะเรียกใช้intern()วิธีตรวจสอบความพร้อมใช้งานของวัตถุที่มีเนื้อหาเดียวกันในพูลโดยใช้วิธีเท่ากับ ถ้า String-copy พร้อมใช้งานในพูลจากนั้นส่งคืนการอ้างอิง มิฉะนั้นวัตถุสตริงจะถูกเพิ่มไปยังสระว่ายน้ำและส่งกลับการอ้างอิง
+) และสำหรับการแปลงวัตถุอื่นเป็นสตริง การต่อข้อมูลสตริงจะดำเนินการผ่านคลาส StringBuilder (หรือ StringBuffer) และวิธีการต่อท้ายString heapSCP = new String("Yash");
heapSCP.concat(".");
heapSCP = heapSCP + "M";
heapSCP = heapSCP + 777;
// For Example: String Source Code
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
StringConstantPoolตัวอักษรของสตริงจะถูกเก็บไว้ใน
String onlyPool = "Yash";
StringBuilderและStringBufferเป็นลำดับตัวอักษรที่ไม่แน่นอน นั่นหมายความว่าเราสามารถเปลี่ยนค่าของวัตถุเหล่านี้ได้ StringBuffer มีวิธีการเดียวกับ StringBuilder แต่แต่ละวิธีใน StringBuffer จะถูกซิงโครไนซ์ดังนั้นจึงเป็นเธรดที่ปลอดภัย
ข้อมูล StringBuffer และ StringBuilder สามารถสร้างได้โดยใช้ตัวดำเนินการใหม่เท่านั้น ดังนั้นพวกเขาจะถูกเก็บไว้ในหน่วยความจำฮีป
อินสแตนซ์ของ StringBuilder ไม่ปลอดภัยสำหรับการใช้หลายเธรด หากจำเป็นต้องมีการซิงโครไนซ์ดังกล่าวขอแนะนำให้ใช้ StringBuffer
StringBuffer threadSafe = new StringBuffer("Yash");
threadSafe.append(".M");
threadSafe.toString();
StringBuilder nonSync = new StringBuilder("Yash");
nonSync.append(".M");
nonSync.toString();
StringBuffer และ StringBuilder จะมีวิธีการพิเศษเช่น.
และreplace(int start, int end, String str)reverse()
หมายเหตุ : StringBuffer และ SringBuilder
Appendable Interfaceมีความไม่แน่นอนที่พวกเขาให้การดำเนินงานของ
เมื่อใดควรใช้อันไหน
String Classถ้าคุณจะไม่ได้ไปเปลี่ยนค่าทุกครั้งที่แล้วดีกว่าที่จะใช้ ในฐานะที่เป็นส่วนหนึ่งของ Generics ถ้าคุณต้องการที่จะเรียงลำดับหรือเปรียบเทียบค่าไปแล้วสำหรับComparable<T>String Class
//ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
Set<StringBuffer> set = new TreeSet<StringBuffer>();
set.add( threadSafe );
System.out.println("Set : "+ set);
หากคุณกำลังจะปรับเปลี่ยนค่าทุกครั้งที่ไปสำหรับ StringBuilder ซึ่งเร็วกว่า StringBuffer ถ้ามีหลายเธรดกำลังแก้ไขค่า go สำหรับ StringBuffer
นอกจากนี้ยังStringBufferปลอดภัยต่อเธรดซึ่งStringBuilderไม่ใช่
ดังนั้นในสถานการณ์แบบเรียลไทม์เมื่อเธรดที่แตกต่างเข้าถึงอยู่StringBuilderอาจมีผลลัพธ์ที่ไม่ได้กำหนดไว้
โปรดทราบว่าหากคุณกำลังใช้ Java 5 หรือใหม่กว่าคุณควรใช้แทนStringBuilder StringBufferจากเอกสาร API:
ในฐานะของการปล่อย JDK 5
StringBuilderชั้นนี้ได้รับการเสริมด้วยชั้นเทียบเท่าที่ออกแบบมาสำหรับการใช้งานโดยด้ายเดี่ยวStringBuilderชั้นโดยทั่วไปควรจะนำมาใช้ในการตั้งค่าให้เป็นหนึ่งในนี้มันสนับสนุนทั้งหมดของการดำเนินงานเดียวกัน แต่มันก็เป็นได้เร็วขึ้นเช่นจะดำเนินการประสานไม่มี
ในทางปฏิบัติคุณแทบจะไม่เคยใช้สิ่งนี้จากหลาย ๆ เธรดในเวลาเดียวกันดังนั้นการซิงโครไนซ์ที่StringBufferไม่จำเป็นต้องอยู่เหนือศีรษะเสมอไป
ส่วนตัวผมไม่คิดว่าจะมีการใช้งานใด ๆ StringBufferในโลกที่แท้จริงสำหรับ เมื่อใดที่ฉันจะต้องการสื่อสารระหว่างหลายเธรดด้วยการจัดการลำดับอักขระ? ไม่ได้มีประโยชน์อะไรเลย แต่ฉันอาจจะยังไม่เห็นแสง :)
ความแตกต่างระหว่าง String และอีกสองคลาสคือ String นั้นไม่เปลี่ยนรูปและอีกสองคลาสเป็นคลาสที่ไม่แน่นอน
แต่ทำไมเรามีสองคลาสเพื่อจุดประสงค์เดียวกัน
เหตุผลคือStringBufferด้ายปลอดภัยและStringBuilderไม่
StringBuilderเป็นคลาสใหม่บนStringBuffer Apiและถูกนำมาใช้JDK5และแนะนำเสมอถ้าคุณกำลังทำงานในสภาพแวดล้อมเธรดเดียวตามมากFaster
สำหรับรายละเอียดที่สมบูรณ์คุณสามารถอ่านhttp://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
ใน java, Stringนั้นไม่เปลี่ยนรูป การไม่เปลี่ยนรูปเราหมายถึงว่าเมื่อมีการสร้างสตริงเราไม่สามารถเปลี่ยนค่าได้ StringBufferไม่แน่นอน เมื่อสร้างวัตถุ StringBuffer เราเพียงผนวกเนื้อหาเข้ากับค่าของวัตถุแทนการสร้างวัตถุใหม่ StringBuilderคล้ายกับ StringBuffer แต่ไม่ปลอดภัยสำหรับเธรด วิธีการของ StingBuilder ไม่ได้ถูกซิงโครไนซ์ แต่เมื่อเปรียบเทียบกับ Strings อื่น ๆ Stringbuilder จะทำงานเร็วที่สุด คุณสามารถเรียนรู้ความแตกต่างระหว่างString, StringBuilder และ StringBufferโดยการใช้พวกเขา