แนวทางปฏิบัติ / ประสิทธิภาพที่ดีที่สุด: การผสม StringBuilder.append กับ String.concat


87

ฉันพยายามทำความเข้าใจว่าแนวทางปฏิบัติที่ดีที่สุดคืออะไรและเหตุใดจึงต้องเชื่อมต่อตัวอักษรสตริงและตัวแปรสำหรับกรณีต่างๆ ตัวอย่างเช่นถ้าฉันมีรหัสเช่นนี้

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

นี่คือวิธีการทำหรือไม่? จากการโพสต์นี้ผมสังเกตเห็นว่า+ผู้ประกอบการในสายสร้างตัวอย่างใหม่ของ StringBuilder เชื่อมเข้าด้วยกันตัวถูกดำเนินการและส่งกลับแปลง String ซึ่งดูเหมือนว่าการทำงานมากขึ้นกว่าเพียงแค่การเรียก.append(); ดังนั้นหากเป็นเช่นนั้นจริงก็ไม่เป็นปัญหา แต่เรื่องString.concat()อะไร? มันเหมาะสม.append()หรือไม่ที่จะใช้สำหรับการเรียงต่อกันทุกครั้ง หรือสำหรับตัวแปรและตัวอักษรสามารถต่อท้ายด้วยได้.concat()หรือไม่?

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

กฎทั่วไปสำหรับแนวทางปฏิบัติที่ดีที่สุดและประสิทธิภาพในการดำเนินการกับสถานการณ์เหล่านี้คืออะไร? สมมติฐานของฉันถูกต้องหรือไม่+และไม่ควรใช้จริงๆ


ฉันคิดว่าโดยพื้นฐานแล้วคุณมีมัน ความคิดเห็นแตกต่างกันไปว่า String + "ไม่ควรใช้จริงๆ" ประเด็นก็คือคุณเข้าใจผลที่ตามมา
ControlAltDel

คำตอบ:


185

+ ตัวดำเนินการ

String s = s1 + s2

เบื้องหลังนี้แปลเป็น:

String s = new StringBuilder(s1).append(s2).toString();

ลองนึกดูว่างานพิเศษจะเพิ่มขึ้นเท่าไรหากคุณมีs1 + s2ที่นี่:

stringBuilder.append(s1 + s2)

แทน:

stringBuilder.append(s1).append(s2)

หลายสตริงด้วย +

ควรทราบว่า:

String s = s1 + s2 + s3 + ... +sN

แปลเป็น:

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

Stringสร้างchar[]อาร์เรย์ที่สามารถใส่ทั้งสองและs1 s2คัดลอกs1และs2เนื้อหาไปยังอาร์เรย์ใหม่นี้ ต้องใช้งานน้อยลงจากนั้น+ผู้ปฏิบัติงาน

StringBuilder.append()

รักษาchar[]อาร์เรย์ภายในที่เพิ่มขึ้นเมื่อจำเป็น จะไม่มีการchar[]สร้างส่วนเพิ่มเติมหากภายในมีขนาดใหญ่เพียงพอ

stringBuilder.append(s1.concat(s2))

นอกจากนี้ยังมีประสิทธิภาพไม่ดีเพราะs1.concat(s2)สร้างเสริมchar[]อาร์เรย์และสำเนาs1และมันเป็นเพียงแค่การคัดลอกเนื้อหาอาร์เรย์ใหม่เพื่อภายในs2StringBuilder char[]

ดังที่กล่าวไว้ว่าคุณควรใช้append()ตลอดเวลาและต่อท้ายสตริงดิบ (ข้อมูลโค้ดแรกของคุณถูกต้อง)


ขอบคุณสำหรับความช่วยเหลือและคำอธิบายเชิงลึก นั่นคือสิ่งที่ฉันต้องการจริงๆ
Nick Rolando

12
แม้ว่าคอมไพลเลอร์เวอร์ชันที่ใหม่กว่าจะปรับตัวดำเนินการ + ให้เหมาะสมกับตัวสร้างสตริงโดยอัตโนมัติ แต่ก็ไม่จำเป็นต้องถือว่าเป็นสิ่งที่ดีเพราะเวอร์ชันเก่าจะไม่ทำ มีหัวข้อที่สำคัญมากที่ถูกเพิกเฉยในการสนทนาทั้งหมดนี้ซึ่งจริงๆแล้วเป็นหนึ่งในวัตถุประสงค์หลักของ StringBuilder ซึ่งเป็นกลุ่มสตริง การใช้ตัวสร้างสตริงจะเก็บทุกอย่างเป็นอักขระ [] และไม่สร้างสตริงกลางเหมือนที่ตัวดำเนินการ + ทำก่อนการปรับแต่งคอมไพเลอร์ (ใช้เพื่อทำ concat) การใช้ concat สร้างอ็อบเจ็กต์ String กลางซึ่งแคชไว้ แต่ไม่ได้ใช้
LINEMAN78

ดังนั้นถ้าฉันกำลังทำคำสั่งแบบครั้งเดียว (ไม่ใช่หลายคำสั่งในวิธีการ) ต่อกันในหลาย ๆ สตริง มันจะโอเคไหมที่จะใช้+กับอ็อบเจกต์ String แทนที่จะสร้าง a StringBuilderสำหรับการต่อกันครั้งเดียวนี้เพราะโดยพื้นฐานแล้วมันจะทำสิ่งเดียวกัน?
Nick Rolando

1
และถ้าฉันต้องการต่อเฉพาะอักขระจะดีกว่าไหมถ้าใช้. append ('\ n') แทน. append ("\ n") เนื่องจากอักขระเป็นประเภทดั้งเดิมและ String คือ Object?
vrwim

3
รุ่น Java 2-nd ที่มีประสิทธิภาพ : การใช้ตัวดำเนินการต่อสายอักขระซ้ำ ๆ เพื่อเชื่อมต่อสตริง n ต้องใช้เวลากำลังสองใน n ดังนั้นมันยังคงเกี่ยวข้อง?
gkiko

16

คอมไพเลอร์ปรับแต่งการเชื่อมต่อ + ให้เหมาะสม

ดังนั้น

int a = 1;
String s = "Hello " + a;

ถูกเปลี่ยนเป็น

new StringBuilder().append("Hello ").append(1).toString();

มีหัวข้อที่ยอดเยี่ยมที่นี่อธิบายว่าทำไมคุณควรใช้ประกอบการด้าน +


3
คอมไพเลอร์จะปรับให้เหมาะสมString s = "Hello World";ตั้งแต่คุณใช้ตัวอักษร
ColinD

@ColinD: +1. เพิ่งแก้ไขข้อมูลโค้ดของฉัน

3

การเพิ่มประสิทธิภาพจะกระทำโดยอัตโนมัติโดยคอมไพเลอร์

คอมไพเลอร์ Java2 จะแปลงสิ่งต่อไปนี้โดยอัตโนมัติ:

String s = s1 + s2; 

ถึง

String s = (new StringBuffer()).append(s1).append(s2).toString();

นำมาจากJava Best Practicesบนเว็บไซต์ Oracles โดยตรง


2

appendคุณควรใช้

concatสร้าง String ใหม่ให้สวยอย่างที่+คิด

หากคุณconcatหรือใช้+กับ 2 สตริงสุดท้าย JVM สามารถทำการปรับให้เหมาะสมได้ดังนั้นจึงเหมือนกับการผนวกในกรณีนี้


1

หากคุณเชื่อมสตริงสองสตริงให้ตรงกันให้ใช้ String.concat (สร้างสตริงใหม่โดยสร้างอาร์เรย์ถ่านใหม่ที่เหมาะกับทั้งสตริงและคัดลอกอาร์เรย์ถ่านของสตริงทั้งสองเข้าด้วยกัน

หากคุณต่อสตริงหลาย ๆ ตัว (มากกว่าสอง) ในบรรทัดเดียวให้ใช้ + หรือ StringBuilder.append ก็ไม่สำคัญเนื่องจากคอมไพเลอร์จะแปลง + เป็น StringBuilder.append สิ่งนี้ดีสำหรับหลาย ๆ สตริงเพราะมันมีอาร์เรย์ถ่านหนึ่งตัวที่เติบโตตามต้องการ

หากคุณเชื่อมต่อหลายสตริงในหลายบรรทัดให้สร้าง StringBuilder หนึ่งตัวและใช้วิธีผนวก ในตอนท้ายเมื่อคุณต่อท้าย Strings กับ StringBuilder เสร็จแล้วให้ใช้. toString () - วิธีการสร้าง String จากมัน สำหรับการเชื่อมต่อกันในหลายบรรทัดจะเร็วกว่าวิธีที่สองเนื่องจากวิธีที่สองจะสร้าง StringBuilder ใหม่ในแต่ละบรรทัดให้ต่อท้าย Strings แล้วส่งกลับไปที่ String ในขณะที่วิธีที่สามใช้ StringBuilder เพียงตัวเดียวสำหรับทั้งสิ่ง


0

ใช้+ตัวดำเนินการเป็นแนวทางปฏิบัติที่ดีที่สุดนอกจากนี้ยังง่ายและอ่านได้

ภาษา Java ให้การสนับสนุนพิเศษสำหรับตัวดำเนินการต่อสตริง (+) และสำหรับการแปลงอ็อบเจ็กต์อื่นเป็นสตริง การต่อสตริงถูกนำไปใช้ผ่านคลาส StringBuilder (หรือ StringBuffer) และวิธีการต่อท้าย

เอกสารทางการ: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html


0

ในระดับไบต์โค้ดไม่แตกต่างกันและเราไม่ได้ลดทอนประสิทธิภาพที่นั่น ในกรณีของการดำเนินการระดับรหัสไบต์จะต้องผ่านวิธีการโอเวอร์โหลดของตัวดำเนินการที่ไม่ใช่อินไลน์สำหรับ + ​​โดยการเรียก append จากนั้นในระดับภาษาแอสเซมบลี (Java เขียนด้วย C และ C สร้างแอสเซมบลีที่คล้ายกับแอสเซมบลีจะมีการเรียกรีจิสเตอร์พิเศษเพื่อจัดเก็บการเรียกใช้งาน + เมธอดในสแต็กและจะมีการพุชเพิ่มเติม (ในความเป็นจริงคอมไพเลอร์ข้ามอาจเพิ่มประสิทธิภาพตัวดำเนินการ + โทรในกรณีนั้นทำให้ไม่มีความแตกต่างกับประสิทธิภาพ)

เป็นแนวทางปฏิบัติที่ดีมีวิธีหนึ่งในการเพิ่มความน่าอ่าน :)


0

ผมเองชอบStrings.format()ง่ายง่ายต่อการอ่านหนึ่งบรรทัดสตริงจัดรูปแบบ

String b = "B value";
String d = "D value";
String fullString = String.format("A %s C %s E F", b, d);
// Output: A B value C D value E F

0

คำตอบทั้งหมดค่อนข้างดีและอธิบายได้ แต่ฉันรู้สึกว่าการสำรวจเกี่ยวกับเทคนิคการต่อสตริงอื่น ๆ ก็ช่วยได้เช่น - Guava Joiner, Streams, String.format เป็นต้น

สำหรับรายละเอียดที่สมบูรณ์มากกว่าการปฏิบัติงานของแต่ละเทคนิค concatenation Java-สตริง concatenation ซึ่งทางคือที่ดีที่สุด

กล่าวโดยย่อประสิทธิภาพการเชื่อมต่อจะแตกต่างกันไปโดยไม่มี ของสตริงที่จะเชื่อมต่อกัน ตัวอย่างเช่น - ในการต่อสตริง 1-10 สายเทคนิคเหล่านี้จะทำงานได้ดีที่สุด - StringBuilder, StringBuffer และ Plus Operator และในการต่อสตริง 100s - Guava Joiner ไลบรารี stringsUtils ของ apache ก็ใช้งานได้ดีเช่นกัน

โปรดอ่านบล็อกด้านบน มันอธิบายประสิทธิภาพการทำงานได้เป็นอย่างดี

ขอบคุณ.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.