StringBuilder so với StringBuffer trong Java

1. Khái quát chung

Trong bài viết ngắn này, chúng ta sẽ xem xét những điểm giống và khác nhau giữa StringBuilderStringBuffer trong Java.

Nói một cách đơn giản, StringBuilder đã được giới thiệu trong Java 1.5 để thay thế cho StringBuffer .

2. Điểm giống nhau

Cả StringBuilderStringBuffer đề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ày hoạt động như thế nào và nó như thế nào so với một lớp String bất biến :

String immutable = "abc"; immutable = immutable + "def";

Mặc dù có thể trông giống như chúng tôi đang sửa đổi cùng một đối tượng bằng cách thêm “def” , chúng tôi đang tạo một đối tượng mới vì không thể sửa đổi các phiên bản Chuỗi .

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. Chúng tôi đã gọi phương thức append () trên sb instance và sửa đổi nội dung của nó. StringBufferStringBuilder là các đối tượng có thể thay đổi.

3. Sự khác biệt

StringBuffer được đồng bộ hóa và do đó an toàn cho chuỗi. StringBuilder tương thích vớiAPI StringBuffer nhưng không đảm bảo đồng bộ hóa.

Bởi vì nó không phải là cách triển khai an toàn cho luồng, nó sẽ nhanh hơn và bạn nên sử dụng nó ở những nơi không cần an toàn cho luồng.

3.1. Hiệu suất

Trong các lần lặp nhỏ, sự khác biệt về hiệu suất là không đáng kể. Hãy làm một điểm chuẩn vi mô nhanh 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; }

Chúng tôi đã sử dụng chế độ Thông lượng mặc định - tức là các hoạt động trên một đơn vị thời gian (điểm càng cao thì càng tốt), điều này mang lại:

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 lại từ 1k đến 1m thì chúng ta 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à một điểm chuẩn vi mô, có thể có hoặc không có tác động thực sự đến hiệu suất thực tế trong thế giới thực của một ứng dụng.

4.Kết luận

Nói một cách đơn giản, StringBuffer là một triển khai an toàn theo luồng và do đó chậm hơn StringBuilder .

Trong các chương trình đơn luồng, chúng ta có thể sử dụng StringBuilder . Tuy nhiên, hiệu suất của StringBuilder so với StringBuffer có thể quá nhỏ để có thể thay thế nó ở mọi nơi. Luôn luôn là một ý kiến ​​hay để lập hồ sơ ứng dụng và hiểu các đặc điểm hiệu suất thời gian chạy của nó trước khi thực hiện bất kỳ loại công việc nào để thay thế một triển khai này bằng một triển khai khác.

Cuối cùng, như mọi khi, mã được sử dụng trong cuộc thảo luận có thể được tìm thấy trên GitHub.