เคยสงสัยกันไหมครับว่า StringBuffer และ StringBuilder ในภาษา Java ที่ทำหน้าที่เหมือนกันคือ ต่อ String แล้วมันแตกต่างกันยังไง ? จะมาเล่าให้อ่านครับ
TLDR;
StringBuffer คือ StringBuilder เวอร์ชันอัปเกรดให้ทำงานได้ดีบน multi-thread program ในขณะที่ StringBuilder อาจจะเจอปัญหา race condition บน multi-thread แต่หากอยู่บน single thread ถือว่าทำงานได้รวดเร็วกว่า StringBuffer เพราะไม่ต้องจัดการเรื่อง multi-thread
ก่อนเข้าเรื่อง Java มี 3 class ที่ represent data ตัวอักษรที่ต่อเนื่องกัน นั่นคือ String, StringBuffer, StringBuilder
String!!
String เป็น immutable class หมายความว่าเมื่อสร้างมาแล้วเราไม่สามารถแก้ value การที่เราจะต่อ string โดยใช้ class String ตรง ๆ อาจจะไม่ตอบโจทย์เรื่อง performance ครับ เพราะเมื่อก็ตามที่มีการสร้าง String เราก็จะเสีย memory เพื่อเก็บ String ที่เราต้องการมาต่อนั่นเอง กว่าจะมีการคืนให้ memory ก็อาจต้องรอให้ garbage collector มาจัดการ
ดังนั้นแล้ว StringBuffer กับ StringBuilder ก็อาจจะเป็นคำตอบในเรื่องนี้ เพราะ 2 ตัวนี้เป็น data type ที่เป็น mutable ก็ตรงกันข้ามคือเราสามารถแก้ไข value ได้
มาถึงประเด็นของเราแล้วว่า StringBuffer และ StringBuilder ต่างกันยังไง ? หลัก ๆ ความแตกต่างมี 2 เรื่องคือ Efficiency และ Thread Safe
Efficiency
StringBuilder ทำงานได้เร็วกว่า StringBuffer ทดสอบโดยใช้โค้ดด้านล่าง
output
เหตุผลที่ StringBuffer ช้ากว่า StringBuilder ก็จะเป็นเพราะเรื่องที่ต้องจัดการ Thread-safe
Thread Safe
StringBuffer เป็น thread-safe
StringBuilder ไม่ thread-safe หมายความว่า 2 thread สามารถเรียก method ของ StringBuilder ในเวลาเดียวกันได้
ทำให้ StringBuilder หากนำไปใช้งานแบบ concurrent ต้องใช้อย่างระมัดระวัง เพราะอาจจะเกิดปัญหา visibility problem และได้ผลลัพธ์ที่ไม่ถูกต้องได้
ทดสอบเรื่อง thread-safe ผ่านโค้ดด้านล่าง
output
จริง ๆ เราสามารถแก้ปัญหา non-thread safe ของ StringBuilder ให้เป็น thread safe ด้วยการใช้ keyword synchronized
แต่ด้าน Efficiency ก็จะน้อยลงไปกลายเป็นเหมือนเราใช้ StringBuffer
StringBuilder sb = new StringBuilder();Runnable r = () -> { synchronized (sb) {
// do something with 'sb' }
};
สรุป
การเลือกใช้งานขึ้นอยู่กับโจทย์ว่างานนั้น ๆ เกี่ยวกับเรื่อง concurrent หรือเปล่า ถ้าใช่ StringBuffer ก็น่าจะเป็นคำตอบ ถ้าไม่ใช่ก็ไปใช้ StringBuilder