String là chuỗi bất biến (immutable) trong Java, còn StringBuilder và StringBuffer là hai lớp chuỗi mutable dùng khi bạn cần nối hoặc chỉnh sửa chuỗi nhiều lần.
String sau khi tạo thì nội dung không đổi; mọi thao tác như + hay concat() đều trả về String mới. Trình biên dịch có thể tối ưu + liên tiếp trong cùng một biểu thức; từ Java 9 (JEP 280) cách tối ưu dùng invokedynamic với StringConcatFactory thay vì StringBuilder ẩn như Java 8 trở về trước, nhưng trong vòng lặp mỗi lần + lại tạo object mới và copy toàn bộ ký tự cũ nên chi phí lên tới O(n²) và tạo nhiều rác cho GC. StringBuilder và StringBuffer giữ buffer mảng có thể mở rộng với capacity riêng; append() chỉ ghi thêm vào cuối và chỉ cấp phát lại khi đầy nên chi phí trung bình gần O(n). Khác biệt duy nhất là StringBuffer đồng bộ hoá hầu hết phương thức bằng synchronized, còn StringBuilder thì không nên nhanh hơn.
| Loại | Mutable | Thread-safe | Khi nào dùng |
|---|---|---|---|
| String | Không | Có nhờ bất biến | Giá trị cố định, ít thay đổi, dùng làm key cho Map |
| StringBuilder | Có | Không | Nối/chỉnh sửa nhiều trong một thread |
| StringBuffer | Có | Có (synchronized) | Nhiều thread cùng ghi vào chung một buffer (hiếm) |
// Nối trong vòng lặp: dùng StringBuilder để tránh tạo object tạm
StringBuilder sb = new StringBuilder(20000); // ước lượng capacity ban đầu
for (int i = 0; i < 10_000; i++) {
sb.append(i).append(',');
}
String result = sb.toString();- Dùng
String +=trong vòng lặp tạo object mới mỗi lần lặp và làm chậm rõ rệt với dữ liệu lớn. - Chọn
StringBuffermặc định "cho an toàn" dù chỉ một thread sẽ chịu chi phísynchronizedkhông cần thiết. - Chia sẻ
StringBuildergiữa nhiều thread mà không đồng bộ có thể gây mất ký tự; nếu cần chia sẻ thật sự hãy dùngStringBufferhoặc tự bọc đồng bộ. - So sánh
Stringbằng==thay vìequals()dễ sai vì==so sánh tham chiếu.
Lưu ý: Mặc định dùng String cho giá trị không đổi và StringBuilder cho mọi nối chuỗi trong một thread; chỉ dùng StringBuffer khi nhiều thread thực sự cùng ghi vào một instance, trường hợp rất hiếm.