Tác giả: Lê Trung Kiên lớp java 08
Email: lekien.2803.cg@gmail.com
SĐT: 0942096947
Link bài gốc: https://www.baeldung.com/java-string-builder-string-buffer
1. Tổng quan
Trong bài viết ngắn này chúng ta sẽ cùng xem xét qua điểm khác biệt và tương đồng giữa StringBuilder và StringBuffer nhé. Trong Java 1.5, StringBuilder đã được giới thiệu để thay thế cho StringBuffer.
2. Điểm tương đồng
Cả StringBuilder và StringBuffer đều tạo ra các đối tượng chứa một chuỗi ký tự có thể thay đổi. Hãy xem cách nó hoạt động và so sánh nó với một class String bất biến:
String immutable = "abc";
immutable = immutable + "def";
Mặc dù có vẻ như chúng ta đang sửa đổi cùng một đối tượng bằng cách nối thêm “def”
, nhưng chúng ta đang tạo một đối tượng mới vì không thể sửa được chuỗi cũ, vì String trong Java là bất biến.
Các bạn có thể tham khảo thêm bài viết về sự bất biến của String qua bài viết này.
Khi sử dụng StringBuffer hoặc StringBuilder, chúng ta có thể sử dụng phương thức append()
:
StringBuffer sb = new StringBuffer("abc");
sb.append("def");
Trong trường hợp này, không có đối tượng mới nào được tạo thêm. Chúng ta đã gọi phương thức append()
trên sb instance và sửa đổi nội dung của nó. StringBuffer và StringBuilder đều là các đối tượng có thể thay đổi, không phải bất biến.
3. Điểm khác biệt
StringBuffer được đồng bộ hóa do đó nó an toàn cho các luồng (thread-safe). StringBuilder tương thích với StringBuffer API nhưng không đảm bảo đồng bộ hóa.
Bởi vì StringBuilder không đồng bộ hóa, nên nó nhanh hơn và được sử dụng ở môi trường không đa luồng.
3.1. Hiệu suất
Trong các lần lặp lại nhỏ, sự khác biệt về hiệu suất là không đáng kể. Hãy thực hiện micro-benchmark với JMH:
@State(Scope.Benchmark)
public static class MyState {
int iterations = 1000;
String initial = "abc";
String suffix = "def";
}
@Benchmark
public StringBuffer benchmarkStringBuffer(MyState state) {
StringBuffer stringBuffer = new StringBuffer(state.initial);
for (int i = 0; i < state.iterations; i++) {
stringBuffer.append(state.suffix);
}
return stringBuffer;
}
@Benchmark
public StringBuilder benchmarkStringBuilder(MyState state) {
StringBuilder stringBuilder = new StringBuilder(state.initial);
for (int i = 0; i < state.iterations; i++) {
stringBuilder.append(state.suffix);
}
return stringBuilder;
}
Sử dụng chế độ Throughput mặc định – tức là các hoạt động trên mỗi đơn vị thời gian (điểm càng cao càng tốt):
Benchmark Mode Cnt Score Error Units
StringBufferStringBuilder.benchmarkStringBuffer thrpt 200 86169.834 ± 972.477 ops/s
StringBufferStringBuilder.benchmarkStringBuilder thrpt 200 91076.952 ± 2818.028 ops/s
Nếu chúng ta tăng số lần lặp từ 1k lên 1m thì chúng ta sẽ nhận được:
Benchmark Mode Cnt Score Error Units
StringBufferStringBuilder.benchmarkStringBuffer thrpt 200 77.178 ± 0.898 ops/s
StringBufferStringBuilder.benchmarkStringBuilder thrpt 200 85.769 ± 1.966 ops/s
Tuy nhiên, hãy nhớ rằng đây là micro-benchmark , có thể có hoặc không có tác động thực sự đến hiệu suất thực khi chạy một ứng dụng trong thực tế.
4. Kết luận
Nói túm lại, StringBuffer đồng bộ và an toàn cho đa luồng, nên nó chậm hơn StringBuilder.
Còn trong môi trường đơn luồng, ta nên sử dụng StringBuilder.
Bình luận