CodeGym /Các khóa học /JAVA 25 SELF /StringBuilder và StringBuffer

StringBuilder và StringBuffer

JAVA 25 SELF
Mức độ , Bài học
Có sẵn

1. Tính bất biến của String: bạn hay thù?

Trong Java, lớp Stringbất biến (immutable). Điều đó có nghĩa là sau khi được tạo, chuỗi không thể bị thay đổi. Mỗi lần bạn “thay đổi” chuỗi, ví dụ thêm gì đó bằng + hoặc concat(), thực ra một đối tượng mới được tạo ra, còn đối tượng cũ sẽ chờ bộ gom rác xóa khỏi bộ nhớ.

Ví dụ:

String s = "Hello";
s = s + " world!";
System.out.println(s); // Hello world!

Có vẻ như chuỗi s đã thay đổi, nhưng thực ra một chuỗi mới "Hello world!" đã được tạo, còn chuỗi cũ "Hello" vẫn tồn tại trong bộ nhớ cho đến khi bộ gom rác dọn dẹp. Nếu có rất nhiều thao tác như vậy — ví dụ trong vòng lặp — chương trình sẽ chậm lại và tiêu tốn thêm bộ nhớ.

Hãy hình dung bạn xây một tòa tháp bằng các khối gạch, và mỗi lần muốn thêm một khối mới, bạn phải xây lại cả tòa tháp từ đầu. Không hề hiệu quả, đúng không? String thông thường trong Java hoạt động giống như vậy khi bạn thay đổi thường xuyên.

2. StringBuilder: “thợ xây” chuỗi nhanh

Lớp StringBuilder (trong gói java.lang, không cần import) là công cụ chuyên dụng để lắp ghép và chỉnh sửa chuỗi một cách hiệu quả. Nó là có thể thay đổi (mutable): bạn có thể thêm, xóa, chèn ký tự và chuỗi con mà không phải tạo đối tượng mới cho mỗi thao tác.

Tương tự:
Nếu String là một tấm bê tông, thì StringBuilder là bộ lắp ghép LEGO: thêm/bớt mảnh ghép tùy ý mà không phải tháo cả khối ra làm lại.

Cách tạo StringBuilder

StringBuilder sb = new StringBuilder(); // rỗng
StringBuilder sb2 = new StringBuilder("Giá trị ban đầu");

Các phương thức chính

Phương thức Mô tả Ví dụ sử dụng
append(...)
Thêm vào cuối chuỗi, số, ký tự, v.v.
sb.append("Java");
insert(index, ...)
Chèn giá trị vào vị trí chỉ định
sb.insert(0, "Hello ");
delete(start, end)
Xóa ký tự từ vị trí start (bao gồm) đến end (không bao gồm)
sb.delete(0, 5);
replace(start, end, str)
Thay thế một phần chuỗi bằng nội dung khác
sb.replace(0, 4, "Hi");
reverse()
Đảo ngược chuỗi
sb.reverse();
toString()
Chuyển thành chuỗi thông thường
String s = sb.toString();
setLength(newLen)
Cắt bớt hoặc đệm chuỗi đến độ dài chỉ định
sb.setLength(3);

Ví dụ sử dụng

StringBuilder sb = new StringBuilder();
sb.append("Xin chào, ");
sb.append("thế giới!");
System.out.println(sb); // Xin chào, thế giới!

sb.insert(7, "Java "); // chèn "Java " sau "Xin chào, "
System.out.println(sb); // Xin chào, Java thế giới!

sb.replace(8, 12, "khác"); // thay "Java" bằng "khác"
System.out.println(sb); // Xin chào, khác thế giới!

sb.reverse();
System.out.println(sb); // !iớig ếht cáhk ,oàhc niX

3. StringBuffer: “đàn anh” có bảo vệ cho đa luồng

Khác nhau thế nào giữa StringBuilderStringBuffer?

  • StringBuilder — nhanh nhưng không an toàn luồng (không đồng bộ).
  • StringBuffer — chậm hơn nhưng an toàn luồng (đồng bộ).

Nếu ứng dụng của bạn chạy một luồng — hãy dùng StringBuilder (nhanh hơn). Nếu nhiều luồng có thể cùng sửa đổi một chuỗi — hãy dùng StringBuffer.

4. Khi nào dùng StringBuilder thay cho String?

Kịch bản

  • Thay đổi chuỗi thường xuyên (thêm, xóa, chèn) trong vòng lặp hoặc khi ghép các văn bản lớn.
  • Ghép chuỗi từ mảng/danh sách (CSV, HTML, báo cáo, v.v.).
  • Phân tích cú pháp và xử lý văn bản với số lượng lớn thao tác trên chuỗi.

Ví dụ: ghép chuỗi từ mảng

Cách không tốt (dùng String+):

String[] names = {"Ivan", "Pyotr", "Maria"};
String result = "";

for (int i = 0; i < names.length; i++) 
{
    result += names[i];
    if (i < names.length - 1) 
    {
        result += ", ";
    }
}
System.out.println(result);

Cách tốt (dùng StringBuilder):

String[] names = {"Ivan", "Pyotr", "Maria"};
StringBuilder sb = new StringBuilder();

for (int i = 0; i < names.length; i++) 
{
    sb.append(names[i]);
    if (i < names.length - 1) 
    {
        sb.append(", ");
    }
}
System.out.println(sb.toString());

Khác biệt: ở cách đầu, mỗi bước lại tạo ra một chuỗi mới; ở cách sau — chúng ta chỉ mở rộng một đối tượng StringBuilder.

5. So sánh hiệu năng: String vs StringBuilder


// Qua String
long t1 = System.currentTimeMillis();
String s = "";
for (int i = 0; i < 10000; i++)
{
    s += i + " ";
}
long t2 = System.currentTimeMillis();
System.out.println("String: " + (t2 - t1) + " ms");

// Qua StringBuilder
t1 = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
    sb.append(i).append(" ");
}
s = sb.toString();
t2 = System.currentTimeMillis();
System.out.println("StringBuilder: " + (t2 - t1) + " ms");

Kết luận: trong đa số trường hợp, StringBuilder nhanh hơn nhiều bậc khi thực hiện nối chuỗi nhiều lần.

6. Các lưu ý hữu ích

Có thể dùng các phương thức của String không?
StringBuilder có bộ phương thức riêng. Muốn nhận về chuỗi — hãy gọi toString().

StringBuilder sb = new StringBuilder("Hello");
String s = sb.toString(); // giờ s là chuỗi thông thường

Có thể so sánh StringBuilder bằng equals không?
Cẩn thận: sb1.equals(sb2) so sánh tham chiếu, không phải nội dung. Hãy so sánh như sau:

if (sb1.toString().equals(sb2.toString())) 
{
    // nội dung trùng khớp
}

Có thể truyền StringBuilder vào System.out.println không?
Có. System.out.println sẽ tự động gọi toString().

Có thể đọc ký tự theo chỉ số không?
Có, hãy dùng charAt(int index), giống như với chuỗi thông thường.

7. Những lỗi thường gặp khi làm việc với StringBuilder và StringBuffer

Lỗi #1: so sánh hai StringBuilder bằng equals hoặc toán tử ==. Các phép này so sánh tham chiếu, không phải nội dung. Hãy dùng toString() và so sánh chuỗi.

Lỗi #2: quên gọi toString() ở nơi cần String (giá trị trả về từ phương thức, ghi log, truyền vào API).

Lỗi #3: dùng StringBuilder cho vài phép nối đơn giản. Cách viết dạng "Hello, " + name vừa dễ đọc vừa hiệu quả.

Lỗi #4: nối String trong vòng lặp bằng +. Điều này không hiệu quả về thời gian và bộ nhớ — hãy dùng StringBuilder.

Lỗi #5: nhầm lẫn giữa StringBufferStringBuilder khi không cần thiết. Nếu không có sửa đổi đồng thời từ nhiều luồng — hãy chọn StringBuilder.

Lỗi #6: tùy tiện cắt nội dung StringBuilder bằng setLength(). Hãy kiểm tra độ dài mới; dữ liệu sau vị trí đó sẽ bị mất.

1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Làm việc với chuỗi
Làm việc với chuỗi
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION