ความแตกต่างระหว่าง StringBuilder และ StringBuffer


1577

ความแตกต่างหลักระหว่างStringBufferและStringBuilderคืออะไร? มีปัญหาเรื่องประสิทธิภาพเมื่อตัดสินใจเลือกข้อใดข้อหนึ่งเหล่านี้หรือไม่

คำตอบ:


1665

StringBufferถูกซิงโครไนซ์StringBuilderไม่ใช่


239
และ StringBuilder มีจุดประสงค์เพื่อแทนที่การแทนที่สำหรับ StringBuffer โดยไม่จำเป็นต้องทำการซิงโครไนซ์
Joel

95
และไม่จำเป็นต้องมีการซิงโครไนซ์ หากมีคนต้องการซิงโครไนซ์กับ StringBuilder พวกเขาสามารถล้อมรอบบล็อกทั้งหมดด้วยการซิงโครไนซ์ (sb) {} บนอินสแตนซ์
locka

23
@ ล็อคฉันจะยืนยันว่า StringBuffer ไม่เคยเป็นความคิดที่ดี (เว้นแต่คุณจะมี API ที่ต้องใช้) vanillajava.blogspot.de/2013/04/…
Peter Lawrey

8
สถานที่เดียวที่ฉันเห็นสำหรับ StringBuffer เป็นคอนโซลเช่นเอาท์พุทและยูทิลิตี้การบันทึกต่างๆ: กระทู้จำนวนมากอาจส่งออกในความขัดแย้ง เนื่องจากคุณไม่ต้องการให้ 2 เอาท์พุทมั่ว ... แต่โดยทั่วไปการซิงโครไนซ์ที่ระดับ StringBuffer นั้นอยู่ในระดับต่ำเกินไปคุณจะต้องซิงโครไนซ์ที่ appender เช่น levelm ดังนั้นคำตอบ locka ดีที่สุดและควรเลิกใช้ StringBuffer มันจะช่วยประหยัดเวลาในการตรวจสอบรหัสด้วยมือใหม่
Remi Morin

20
ช่วยในการจำที่ดีสำหรับผู้ที่ผสมสองคนนี้ - BuFFer คือ First, เก่ากว่าและมีการใช้งานที่ตรงกัน คลาสตัวสร้างที่ใหม่กว่าใช้รูปแบบตัวสร้างและแบบอะซิงโครนัส
Datageek

728

StringBuilderจะเร็วกว่าเพราะมันไม่ได้StringBuffersynchronized

นี่คือการทดสอบมาตรฐานอย่างง่าย:

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);
        }
    }
}

ทดสอบการทำงานจะช่วยให้ตัวเลขของ2241 msสำหรับStringBufferVS สำหรับ753 msStringBuilder


10
ฉันเปลี่ยนสตริงตัวอักษรเป็นสิ่งที่ใหญ่กว่า: "สุนัขจิ้งจอกสีน้ำตาลด่วน" และได้ผลลัพธ์ที่น่าสนใจยิ่งขึ้น โดยพื้นฐานแล้วพวกมันเร็วพอ จริง ๆ แล้วฉันมีหน่วยความจำไม่เพียงพอดังนั้นฉันจึงต้องลบเซเว่นออกสองสามอัน คำอธิบาย: การซิงโครไนซ์ถูกปรับให้เหมาะสมโดยฮอตสปอต คุณเพียงแค่ทำการวัดเวลาที่ฮอตสปอตใช้ในการทำสิ่งนี้ (และอาจเป็นการเพิ่มประสิทธิภาพให้มากขึ้น)
Jilles van Gurp

7
คุณต้องอุ่นเครื่องก่อน การทดสอบนี้ไม่ยุติธรรมกับ StringBuffer นอกจากนี้มันจะดีถ้ามันผนวกสิ่งที่จริง ที่จริงฉันพลิกการทดสอบและผนวกสตริงแบบสุ่มและได้รับการทดสอบตรงข้าม จะบอกว่าไม่มีใครสามารถเชื่อถือได้มาตรฐานที่เรียบง่าย ตรงกันข้ามแสดงให้เห็นว่า StringBuffer เร็วขึ้น 5164 สำหรับ StringBuilder เทียบกับ 3699 สำหรับ StringBuffer hastebin.com/piwicifami.avrasm
mmm

75
นี่เป็นครั้งแรกที่ฉันเห็น--> 0เป็นวง เอาฉันสักครู่เพื่อรู้ว่ามันหมายถึงอะไร เป็นสิ่งที่ใช้จริงในทางปฏิบัติแทน...; i > 0; i--ไวยากรณ์ปกติหรือไม่
Raimund Krämer

19
นั่นi -->เป็นเรื่องที่น่ารำคาญจริง ๆ ... ฉันคิดว่ามันเป็นลูกศรเพราะความคิดเห็นเกี่ยวกับศิลปะ ASCII
Sameer Puri

14
อื่น ๆ สรุปกับผลลัพธ์ที่แตกต่าง: alblue.bandlem.com/2016/04/jmh-stringbuffer-stringbuilder.html การวัดประสิทธิภาพควรทำกับ JMH ไม่ใช่แบบง่ายmain()นอกจากนี้การวัดประสิทธิภาพของคุณไม่ยุติธรรม ไม่มีการอุ่นเครื่อง
Lukas Eder

249

โดยทั่วไปStringBufferวิธีการจะถูกซิงโครไนซ์ในขณะที่StringBuilderไม่ใช่

การดำเนินการ "เกือบ" เหมือนกัน แต่การใช้วิธีการซิงโครไนซ์ในเธรดเดียวนั้นเกินขีด

มันเกี่ยวกับมันมาก

อ้างอิงจากStringBuilder API :

ชั้นนี้ [StringBuilder] มี API เข้ากันได้กับ StringBuffer, แต่มีการรับประกันของการประสานไม่มี คลาสนี้ถูกออกแบบมาเพื่อใช้แทนการแทนที่สำหรับ StringBuffer ในตำแหน่งที่มีการใช้บัฟเฟอร์สตริงโดยเธรดเดี่ยว (โดยทั่วไปจะเป็นกรณี) หากเป็นไปได้ขอแนะนำให้ใช้คลาสนี้ในการกำหนดค่าตามความชอบกับ StringBuffer เนื่องจากจะเร็วกว่าในการนำไปใช้งานส่วนใหญ่

ดังนั้นมันจึงถูกสร้างขึ้นมาเพื่อทดแทนมัน

เช่นเดียวกับที่เกิดขึ้นกับและVectorArrayList


1
นอกจากนี้ยังมีและHashtable HashMap
shmosel

176

แต่จำเป็นต้องได้รับความแตกต่างที่ชัดเจนด้วยความช่วยเหลือของตัวอย่างหรือไม่

StringBuffer หรือ StringBuilder

เพียงใช้StringBuilderเว้นแต่คุณพยายามแบ่งบัฟเฟอร์ระหว่างเธรดจริงๆ StringBuilderเป็นหมู่ (= ค่าใช้จ่ายที่มีประสิทธิภาพน้อยกว่า) น้องชายของตรงกันเดิมStringBufferระดับ

StringBufferมาก่อน ดวงอาทิตย์เกี่ยวข้องกับความถูกต้องภายใต้เงื่อนไขทั้งหมดดังนั้นพวกเขาจึงทำการซิงโครไนซ์เพื่อทำให้เธรดปลอดภัยในกรณี

StringBuilderมาในภายหลัง การใช้งานส่วนใหญ่StringBufferเป็นแบบเธรดเดี่ยวและจ่ายค่าใช้จ่ายในการซิงโครไนซ์โดยไม่จำเป็น

ตั้งแต่StringBuilderเป็นดรอปแทนสำหรับStringBufferโดยไม่ตรงกันจะไม่มีความแตกต่างระหว่างตัวอย่างใด ๆ

ถ้าคุณกำลังพยายามที่จะใช้ร่วมกันระหว่างหัวข้อคุณสามารถใช้StringBufferแต่พิจารณาว่าการประสานในระดับสูงเป็นสิ่งที่จำเป็นเช่นอาจจะแทนการใช้ StringBuffer คุณควรประสานวิธีการที่ใช้นั้น StringBuilder


14
คำตอบแรกที่ดี !! จุดคือ "ถ้าคุณไม่แชร์บัฟเฟอร์ระหว่างเธรด"
AlexWien

1
คำตอบอย่างละเอียดมาก!
Raúl

81

ก่อนอื่นให้ดูความเหมือนกัน : ทั้ง StringBuilder และ StringBuffer นั้นเปลี่ยนแปลงได้ ซึ่งหมายความว่าคุณสามารถเปลี่ยนเนื้อหาของพวกเขาด้วยในตำแหน่งเดียวกัน

ความแตกต่าง : StringBuffer สามารถเปลี่ยนแปลงได้และทำข้อมูลให้ตรงกันเช่นกัน โดยที่เป็น StringBuilder ไม่แน่นอน แต่ไม่ซิงโครไนซ์โดยค่าเริ่มต้น

ความหมายของการซิงโครไนซ์ (การซิงโครไนซ์) : เมื่อบางสิ่งถูกซิงโครไนซ์หลายเธรดสามารถเข้าถึงและแก้ไขโดยไม่เกิดปัญหาหรือผลข้างเคียงใด ๆ StringBuffer ถูกซิงโครไนซ์ดังนั้นคุณสามารถใช้กับหลายเธรดโดยไม่มีปัญหา

จะใช้อันไหนเมื่อไหร่? StringBuilder: เมื่อคุณต้องการสตริงซึ่งสามารถแก้ไขได้และมีเพียงหนึ่งเธรดเท่านั้นที่เข้าถึงและแก้ไข StringBuffer: เมื่อคุณต้องการสตริงซึ่งสามารถแก้ไขได้และหลายกระทู้กำลังเข้าถึงและแก้ไข

หมายเหตุ : อย่าใช้ StringBuffer โดยไม่จำเป็นเช่นไม่ใช้ถ้ามีเพียงหนึ่งเธรดที่กำลังแก้ไขและเข้าถึงเนื่องจากมีการล็อกและปลดล็อกรหัสจำนวนมากสำหรับการซิงโครไนซ์ซึ่งจะใช้เวลา CPU โดยไม่จำเป็น อย่าใช้ล็อคเว้นแต่จะจำเป็น


2
แค่อยากพูดถึงว่าการเรียกใช้เมธอด StringBuffer INDIVIDUAL นั้นปลอดภัยต่อเธรด แต่ถ้าคุณมีรหัสหลายบรรทัดให้ใช้บล็อคโค้ดที่ซิงโครไนซ์เพื่อรับประกันความปลอดภัยของเธรดพร้อมกับล็อค / มอนิเตอร์ (ตามปกติ ... ) โดยพื้นฐานแล้วอย่าเพิ่งสันนิษฐานว่าการใช้ไลบรารี่แบบปลอดภัยสำหรับเธรดจะรับประกันความปลอดภัยของเธรดในโปรแกรมของคุณทันที!
Kevin Lee

57

ในเธรดเดี่ยวStringBuffer ไม่ช้ากว่า StringBuilder อย่างมีนัยสำคัญเนื่องจากการเพิ่มประสิทธิภาพ JVM และในมัลติเธรดคุณไม่สามารถใช้ StringBuilder อย่างปลอดภัย

นี่คือการทดสอบของฉัน (ไม่ใช่มาตรฐานเพียงแค่การทดสอบ):

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));
}

ผลลัพธ์:
สตริง: 319740
บัฟเฟอร์: 23 ตัว
สร้าง: 7!

ดังนั้นผู้สร้างจึงเร็วกว่าบัฟเฟอร์และวิธีเร็วกว่าการรวมสตริงเข้าด้วยกัน ตอนนี้ลองใช้Executorสำหรับหลาย ๆ เธรด:

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);
    }
}

ตอนนี้ StringBuffers ใช้เวลา157 msต่อการผนวก 100,000 ครั้ง มันไม่ได้เป็นการทดสอบเดียวกัน แต่เมื่อเทียบกับก่อนหน้านี้ 37 มิลลิวินาทีที่คุณได้อย่างปลอดภัยสามารถสมมติว่าStringBuffers ผนวกจะช้ากับ multithreading ใช้ เหตุผลคือ JIT / ฮอตสปอต / คอมไพเลอร์ / บางอย่างทำให้การปรับให้เหมาะสมเมื่อตรวจพบว่าไม่จำเป็นต้องตรวจสอบล็อค

แต่ด้วย StringBuilder คุณมี java.lang.ArrayIndexOutOfBoundsExceptionเนื่องจากเธรดพร้อมกันพยายามเพิ่มบางสิ่งที่ไม่ควร

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


5
คุณลืมที่จะทำ "t0 = System.currentTimeMillis ();" ก่อนทำการทดสอบ StringBuilder ดังนั้นรูปที่แสดงสำหรับ StringBuilder จึงเป็นเวลาที่ใช้ในการรันการทดสอบ stringbuffer และ stringbuilder เพิ่มบรรทัดนี้แล้วคุณจะเห็นว่า StringBuilder เร็วขึ้นประมาณสองเท่า
Gena Batsyan

โปรดทราบว่าwithString+="some string"+i+" ; ";ไม่เท่ากับอีกสองลูปดังนั้นจึงไม่ใช่การเปรียบเทียบที่เป็นธรรม
เดฟจาร์วิส

ถูกต้องแก้ไข สตริงความคิดยังคงช้ามาก
Nicolas Zozol

คุณช่วยอธิบายเพิ่มเติมได้ไหมว่าเหตุใดการเพิ่มArrayIndexOutOfBoundsExceptionสำหรับStringBuilder
Alireza Fattahi

คุณควรใช้ JMH สำหรับการวัดประสิทธิภาพ มาตรฐานของคุณไม่ถูกต้องจริงๆ
Lukas Eder

42

StringBuilder ถูกนำมาใช้ใน Java 1.5 ดังนั้นมันจะไม่ทำงานกับ JVM ก่อนหน้านี้

จากJavadocs :

คลาส StringBuilder จัดเตรียม API ที่เข้ากันได้กับ StringBuffer แต่ไม่รับประกันการซิงโครไนซ์ คลาสนี้ถูกออกแบบมาเพื่อใช้แทนการแทนที่สำหรับ StringBuffer ในตำแหน่งที่มีการใช้บัฟเฟอร์สตริงโดยเธรดเดี่ยว (โดยทั่วไปจะเป็นกรณี) หากเป็นไปได้ขอแนะนำให้ใช้คลาสนี้ในการกำหนดค่าตามความชอบกับ StringBuffer เนื่องจากจะเร็วกว่าในการนำไปใช้งานส่วนใหญ่


13
1.4 อยู่ในช่วงหมดอายุการใช้งานดังนั้นจึงไม่น่ากังวลเกี่ยวกับ pre-1.5
Tom Hawtin - tackline

@ tomHawtin-tackline ไม่จำเป็น - มีผลิตภัณฑ์ระดับองค์กรออกมาในช่วงก่อน 1.4 ที่พวกเราส่วนใหญ่ใช้ทุกวัน BlackBerry Java ยังใช้ 1.4 และยังคงเป็นปัจจุบันมาก
Richard Le Mesurier

และ CDC และ CLDC StringBuilderไม่ได้
Jin Kwon

37

คำถามที่ดีงาม

นี่คือความแตกต่างฉันได้สังเกต:

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.

สิ่งทั่วไป: -

ทั้งสองมีวิธีการเดียวกันที่มีลายเซ็นเหมือนกัน ทั้งสองไม่สามารถเปลี่ยนแปลงได้


23

StringBuffer

  • จึงทำให้เธรดปลอดภัย
  • เธรดที่ปลอดภัยจึงช้า

StringBuilder

  • แนะนำใน Java 5.0
  • แบบอะซิงโครนัสจึงรวดเร็วและมีประสิทธิภาพ
  • ผู้ใช้ต้องทำการซิงโครไนซ์ถ้าเขาต้องการ
  • คุณสามารถแทนที่ด้วยStringBufferไม่มีการเปลี่ยนแปลงอื่น ๆ

หมายเหตุ: การดำเนินการเดียวเท่านั้นที่ปลอดภัยสำหรับเธรดการดำเนินการหลายรายการไม่ได้ เช่นถ้าคุณโทรหาappendสองครั้งหรือappendและtoStringไม่ปลอดภัย
Peter Lawrey

22

StringBuilder ไม่ปลอดภัยเธรด String Buffer คือ ข้อมูลเพิ่มเติมที่นี่

แก้ไข: สำหรับประสิทธิภาพหลังจากฮอตสปอตเริ่มเข้า StringBuilder เป็นผู้ชนะ อย่างไรก็ตามสำหรับการทำซ้ำเล็ก ๆ ความแตกต่างด้านประสิทธิภาพนั้นเล็กน้อย


21

StringBuilderและStringBufferเกือบจะเหมือนกัน ความแตกต่างคือการStringBufferซิงโครไนซ์และStringBuilderไม่ แม้ว่าStringBuilderจะเร็วกว่าStringBufferแต่ความแตกต่างของประสิทธิภาพก็น้อยมาก จะเปลี่ยนของดวงอาทิตย์StringBuilder StringBufferมันหลีกเลี่ยงการซิงโครไนซ์จากวิธีสาธารณะทั้งหมด มากกว่านั้นฟังก์ชั่นของพวกเขาเหมือนกัน

ตัวอย่างการใช้งานที่ดี:

StringBufferถ้าข้อความของคุณจะมีการเปลี่ยนแปลงและถูกใช้โดยหลายกระทู้แล้วมันจะดีกว่าที่จะใช้ ถ้าข้อความของคุณจะมีการเปลี่ยนแปลง StringBuilderแต่จะถูกใช้โดยหัวข้อเดียวแล้วใช้


19

StringBuffer

StringBuffer ไม่แน่นอนหมายความว่าเราสามารถเปลี่ยนค่าของวัตถุ วัตถุที่สร้างขึ้นผ่าน StringBuffer จะถูกเก็บไว้ในกอง StringBuffer มีวิธีการเดียวกับ StringBuilder แต่แต่ละวิธีใน StringBuffer จะซิงโครไนซ์ที่เป็น StringBuffer มีความปลอดภัยของเธรด

ด้วยเหตุนี้จึงไม่อนุญาตให้สองเธรดเข้าถึงวิธีเดียวกันพร้อมกัน แต่ละวิธีสามารถเข้าถึงได้ครั้งละหนึ่งเธรด

แต่การมีเธรดที่ปลอดภัยก็มีข้อเสียเช่นเดียวกันกับประสิทธิภาพของ StringBuffer ที่นิยมเนื่องจากคุณสมบัติที่ปลอดภัยของเธรด ดังนั้น StringBuilder จะเร็วกว่า StringBuffer เมื่อเรียกวิธีการเดียวกันของแต่ละคลาส

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

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 Vs StringBuffer Vs StringBuilder


StringBuilder นั้นไม่เปลี่ยนรูปแบบและประเภท String ไม่แน่นอน
Brinda Rathod

ฉันจะไม่ยอมรับว่า Strings และ StringBuilders นั้น "เร็ว" และ StringBuffers นั้น "ช้ามาก" ดูคำตอบข้างต้น
FireCubez

17

String เป็นสิ่งที่ไม่เปลี่ยนรูป

StringBuffer คือความไม่แน่นอนและการซิงโครไนซ์

StringBuilder ไม่แน่นอนเช่นกัน แต่ไม่ซิงโครไนซ์


นอกจากนี้ StringBuffer ล็อคเธรดเพื่อเข้าถึงเธรดข้อมูลที่ปลอดภัยซึ่งเป็นสาเหตุที่การดำเนินการช้าลง StringBuilder ไม่ล็อคเธรดและทำงานในแบบมัลติเธรดซึ่งเป็นสาเหตุที่รวดเร็ว สตริง - เมื่อคุณไม่จำเป็นต้องสตริง concatenate นี้เป็นวิธีที่ดี แต่เมื่อคุณจำเป็นต้องใช้มัน StringBuilder -> เพราะ String สร้างทุกครั้งที่วัตถุใหม่ในกอง แต่ StringBuilder กลับวัตถุเดียวกัน ...
มูซา

11

Javadocอธิบายความแตกต่าง:

คลาสนี้ให้ API ที่เข้ากันได้กับ StringBuffer แต่ไม่มีการรับประกันการซิงโครไนซ์ คลาสนี้ถูกออกแบบมาเพื่อใช้แทนการแทนที่สำหรับ StringBuffer ในตำแหน่งที่มีการใช้บัฟเฟอร์สตริงโดยเธรดเดี่ยว (โดยทั่วไปจะเป็นกรณี) หากเป็นไปได้ขอแนะนำให้ใช้คลาสนี้ในการกำหนดค่าตามความชอบกับ StringBuffer เนื่องจากจะเร็วกว่าในการนำไปใช้งานส่วนใหญ่


10

StringBuilder(เปิดตัวใน Java 5) เหมือนกันStringBufferยกเว้นวิธีการที่ไม่ตรงกัน ซึ่งหมายความว่ามันมีประสิทธิภาพที่ดีกว่าหลัง แต่ข้อเสียเปรียบคือมันไม่ปลอดภัยต่อเธรด

อ่านบทช่วยสอนสำหรับรายละเอียดเพิ่มเติม


6

โปรแกรมอย่างง่ายที่แสดงให้เห็นถึงความแตกต่างระหว่าง StringBuffer และ 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");
        }

    }
}

4

StringBuffer ใช้เพื่อเก็บสตริงอักขระที่จะเปลี่ยนแปลง (ไม่สามารถเปลี่ยนวัตถุสตริง) มันขยายโดยอัตโนมัติตามความจำเป็น คลาสที่เกี่ยวข้อง: String, CharSequence

StringBuilder ถูกเพิ่มเข้าไปใน Java 5 มันเหมือนกันทุกประการกับ StringBuffer ยกเว้นว่ามันจะไม่ถูกซิงโครไนซ์ซึ่งหมายความว่าหากมีหลายเธรดที่เข้าถึงในเวลาเดียวกันอาจมีปัญหาได้ สำหรับโปรแกรมแบบเธรดเดี่ยวกรณีที่พบบ่อยที่สุดการหลีกเลี่ยงค่าใช้จ่ายในการซิงโครไนซ์ทำให้ StringBuilder เร็วขึ้นเล็กน้อย


4
โปรแกรมแบบเธรดเดี่ยวไม่ได้เป็นกรณีที่พบบ่อยที่สุดใน Java แต่StringBuilderโดยทั่วไปแล้ววิธีการแบบโลคอลจะเป็นแบบโลคอล
finnw


4

StringBuffer ไม่แน่นอน มันสามารถเปลี่ยนแปลงในแง่ของความยาวและเนื้อหา StringBuffers เป็น thread-safe ซึ่งหมายความว่าพวกเขามีวิธีการซิงโครไนซ์เพื่อควบคุมการเข้าถึงเพื่อให้มีเพียงหนึ่งเธรดเท่านั้นที่สามารถเข้าถึงรหัสที่ตรงกันของวัตถุ StringBuffer ในเวลาเดียวกัน ดังนั้นวัตถุ StringBuffer โดยทั่วไปจะปลอดภัยที่จะใช้ในสภาพแวดล้อมแบบมัลติเธรดที่หลายเธรดอาจพยายามเข้าถึงวัตถุ StringBuffer เดียวกันในเวลาเดียวกัน

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


4

StringBuffer:

  • หลายกระทู้
  • Synchronized
  • ช้ากว่า StringBuilder

StringBuilder

  • เดี่ยวกระทู้
  • ไม่ตรงกัน
  • เร็วกว่าที่เคย String

2
แม่นยำยิ่งขึ้นString c = a + bเทียบเท่ากับString c = new StringBuilder().append(a).append(b).toString()ดังนั้นจึงไม่เร็วขึ้น มันเป็นเพียงที่คุณสร้างขึ้นมาใหม่สำหรับแต่ละสายนัดในขณะที่คุณอาจจะมีเพียงหนึ่ง ( String d = a + b; d = d + c;คือString d = new StringBuilder().append(a).append(b).toString(); d = new StringBuilder().append(d).append(c).toString();ในขณะที่StringBuilder sb = new StringBuilder(); sb.append(a).append(b); sb.append(c); String d = sb.toString();จะบันทึกหนึ่ง StringBuilder instanciation)
Chop

4

String-Builder :

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.

สตริงบัฟเฟอร์

StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);  

ขอแนะนำให้ใช้ StringBuilder ทุกครั้งที่ทำได้เพราะมันเร็วกว่า StringBuffer อย่างไรก็ตามถ้าจำเป็นต้องมีความปลอดภัยของเธรดตัวเลือกที่ดีที่สุดคือวัตถุ StringBuffer


ถ้าคุณต้องการความปลอดภัยของเธรดตัวเลือกที่ดีที่สุดคือการใช้ StringBuilder เนื่องจาก StringBuffer เป็นเธรดที่ปลอดภัยสำหรับแต่ละการดำเนินการเท่านั้น สำหรับการทำงานหลายครั้งคุณต้องล็อคอย่างชัดเจน
Peter Lawrey

4

ใช้งานได้ดีขึ้นStringBuilderเนื่องจากไม่มีการซิงโครไนซ์และให้ประสิทธิภาพที่ดีกว่า StringBuilderเป็นดรอปแทนStringBufferของพี่


3
@ Mark จริง แต่ส่วนใหญ่เวลาStringBu(ff|ild)erเป็นตัวแปรท้องถิ่นที่ใช้โดยด้ายเดียวเท่านั้น
gabuzo

1
@MarkMcKenna: แม้ในแอพพลิเคชั่นแบบมัลติเธรดก็มักจะต้องใช้การล็อคภายนอกหรือทำงานพิเศษเพื่อหลีกเลี่ยงมัน ตัวอย่างเช่นถ้าสองเธรดแต่ละปรารถนาที่จะผนวกระเบียนที่มีหลายสตริงในตัวสร้างสตริงพวกเขาจะต้องรวมข้อมูลที่จะเพิ่มแล้วเพิ่มเป็นหน่วยแม้ว่ามันจะเร็วขึ้น - ขาดเธรดปัญหา - เพื่อทำการเรียงลำดับของการดำเนินการผนวกที่ไม่ต่อเนื่อง
supercat

3

เนื่องจากStringBufferมีการซิงโครไนซ์มันต้องใช้ความพยายามพิเศษดังนั้นจึงขึ้นอยู่กับประสิทธิภาพการทำงานของมันซึ่งช้ากว่าStringBuilderเล็กน้อย


3

ไม่มีความแตกต่างพื้นฐานระหว่างStringBuilderและStringBufferมีเพียงความแตกต่างเล็กน้อยระหว่างพวกเขา ในStringBufferวิธีการทำข้อมูลให้ตรงกัน ซึ่งหมายความว่าในแต่ละครั้งมีเพียงหนึ่งเธรดเท่านั้นที่สามารถทำงานกับเธรดได้ หากมีมากกว่าหนึ่งเธรดเธรดที่สองจะต้องรอเธรดแรกให้เสร็จและเธรดที่สามจะต้องรอเธรดแรกและที่สองให้เสร็จและอื่น ๆ ทำให้กระบวนการช้ามากและด้วยเหตุนี้ประสิทธิภาพในกรณีของStringBufferอยู่ในระดับต่ำ

ในทางตรงกันข้ามStringBuilderจะไม่ทำข้อมูลให้ตรงกัน ซึ่งหมายความว่าในเวลาหลายกระทู้สามารถทำงานบนStringBuilderวัตถุเดียวกันในเวลาเดียวกัน ทำให้กระบวนการรวดเร็วและประสิทธิภาพการทำงานของStringBuilderสูง


3

A Stringเป็นวัตถุที่ไม่เปลี่ยนรูปซึ่งหมายความว่าค่าไม่สามารถเปลี่ยนแปลงได้ในขณะที่StringBufferไม่แน่นอน

การStringBufferซิงโครไนซ์จึงปลอดภัยเธรดในขณะที่StringBuilderไม่เหมาะสำหรับอินสแตนซ์เธรดเดียวเท่านั้น


3
เพียงเพราะ StringBuffer มีรหัสที่ตรงกันไม่จำเป็นต้องหมายความว่า StringBuffer เป็น threadsafe ลองพิจารณาตัวอย่างต่อไปนี้: StringBuffer testingBuffer = "stackoverflow"; ตอนนี้เธรด -1 กำลังพยายามผนวก "1" กับการทดสอบ Buffer และเธรด -2 กำลังพยายามผนวก "2" เข้ากับการทดสอบ Buffer ในขณะนี้ถึงวิธีการผนวก () ได้รับการซิงโครไนซ์คุณไม่สามารถแน่ใจได้ว่าค่าของการทดสอบ Buffer จะเป็น "stackoverflow12" หรือ "stackoverflow21" ที่จริงแล้ว Oracle ขอแนะนำให้ใช้ stringbuilder แทน stringbuffer ฉันหวังว่านี่จะช่วยได้ :)
Biman Tripathy

2

ความแตกต่างที่สำคัญStringBufferคือการทำข้อมูลให้ตรงกัน แต่StringBuilderไม่ใช่ถ้าคุณต้องการใช้มากกว่าหนึ่งเธรดแนะนำให้ใช้ StringBuffer แต่ตามความเร็วในการดำเนินการStringBuilderจะเร็วกว่าStringBufferเพราะไม่ได้ทำข้อมูลให้ตรงกัน


4
StringBuffer เป็นเธรดที่ปลอดภัยเท่านั้นหากคุณดำเนินการเพียงหนึ่งครั้งเท่านั้น ฉันจะไม่แนะนำให้ใช้ในหลายเธรดเพราะยากที่จะทำให้ถูกต้อง
Peter Lawrey

@PeterLawrey คุณหมายถึงอะไร? :-)
Tamad Lang

1
@ b16db0 ฉันหมายความว่าการใช้งานส่วนใหญ่ของ StringBuffer จะไม่ปลอดภัยเนื่องจากพวกเขาทำการโทรหลายครั้งโดยไม่ต้องซิงโครไนซ์ภายนอกทำให้คลาสค่อนข้างไม่มีจุดหมาย
ปีเตอร์ Lawrey

@PeterLawrey อามันก็เหมือน StringBuffer ยังคงต้องการสภาพแวดล้อมที่ตรงกัน
Tamad Lang

2

ตรวจสอบ internals ของวิธีการผนวกตรงกันของและวิธีการผนวกที่ไม่ตรงกันของStringBufferStringBuilder

StringBuffer :

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;
}

StringBuilder :

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;
}

ตั้งแต่ผนวกเป็นsynchronized, StringBufferมีค่าใช้จ่ายเมื่อเทียบกับผลการดำเนินงานStrinbBuilderในหลายเธรดสถานการณ์ ตราบใดที่คุณไม่ได้แชร์บัฟเฟอร์ระหว่างหลาย ๆ เธรดให้ใช้StringBuilderซึ่งรวดเร็วเนื่องจากไม่มีsynchronizedวิธีต่อท้าย


1

นี่คือผลการทดสอบประสิทธิภาพการทำงานสำหรับString VS StringBuffer VS StringBuilder ในที่สุด StringBuilder ชนะการทดสอบ ดูรหัสทดสอบและผลลัพธ์ด้านล่าง

รหัส :

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");

  }

ดำเนินการกับฉันใน ideone

ผลลัพธ์ :

100,000 ซ้ำสำหรับการเพิ่มข้อความเดียว

String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms

10,000 การวนซ้ำสำหรับการเพิ่มข้อความเดียว

String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms

1
  • StringBuffer เป็นเธรดที่ปลอดภัย แต่ StringBuilder ไม่ปลอดภัยเธรด
  • StringBuilder เร็วกว่า StringBuffer
  • StringBuffer ทำข้อมูลให้ตรงกันในขณะที่ StringBuilder ไม่ได้ทำข้อมูลให้ตรงกัน

1

StringBuffer ได้รับการซิงโครไนซ์แล้วและมีความปลอดภัยสำหรับเธรด StringBuilder จะไม่ซิงโครไนซ์และเร็วกว่า


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