กรุณาบอกฉันสถานการณ์เวลาจริงเพื่อเปรียบเทียบString
, StringBuffer
และStringBuilder
?
กรุณาบอกฉันสถานการณ์เวลาจริงเพื่อเปรียบเทียบString
, StringBuffer
และStringBuilder
?
คำตอบ:
ความแตกต่างที่ไม่แน่นอน:
String
จะไม่เปลี่ยนรูปถ้าคุณพยายามที่จะเปลี่ยนค่าของพวกเขาวัตถุอื่นได้รับการสร้างในขณะที่StringBuffer
และStringBuilder
จะไม่แน่นอนเพื่อให้พวกเขาสามารถเปลี่ยนค่าของพวกเขา
ความแตกต่างของหัวข้อความปลอดภัย:
ความแตกต่างระหว่างStringBuffer
และStringBuilder
คือStringBuffer
ความปลอดภัยของเธรด StringBuilder
ดังนั้นเมื่อความต้องการใช้ที่จะทำงานเฉพาะในหัวข้อเดียวแล้วมันจะดีกว่าที่จะใช้ จะมีประสิทธิภาพมากกว่าStringBuilder
StringBuffer
สถานการณ์:
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โดยการใช้พวกเขา