Bạn học Java lâu chưa? Bạn đã code những phần mềm nào với Java mà phải xử lý các chuỗi? Tôi chắn rằng bạn biết trong Java có một số lớp liên quan đến chuỗi (xâu) và xử lý chuỗi (VD: String, StringBuilder, StringBuffer, StringTokenizer), có khi nào bạn đặt câu hỏi rằng đã có String sao lại phải có thêm StringBuider? Hay bạn mặc nhiên dùng String mà không thèm đoái hoài gì đến StringBuffer và StringBuilder?! Việc bạn không dùng StringBuilder có thể do bạn chưa hiểu được vì sao lại có lớp này trong Java. Vậy chúng ta cùng tìm hiểu về sự khác biệt giữa các lớp này nhé.

Nói chung, khác biệt đáng kể nhất giữa String và StringBufferStringBuilder trong Java đó là đối tượng String là không thể thay đổi (immutable – không thể thay đổi giá trị) trong khi đó các đối tượng StringBuffer, StringBuilder lại có thể thay đổi (mutable – có thể thay đổi giá trị). Tức là giá trị (chuỗi) được lưu trữ trong đối tượng String không thể thay đổi được. Nếu vậy chắc rằng bạn sẽ đặt tiếp câu hỏi “như thế thì làm thế nào để tôi thay đổi giá trị của đối tượng này?” hay “tôi vẫn thay được giá trị của nó đấy thôi?”. Thực ra, việc thay đổi giá trị của đối tượng String được thực hiện bằng cách tạo một đối tượng mới có giá trị mà bạn muốn đổi sang. Cụ thể như sau:

Bạn khai báo một chuỗi:

[sourcecode language=”java”]

String myName = "Tạp chí Lập trình";

//Tiếp đến để thêm vào cuối chuỗi này bạn làm như sau:
myName = myName + " – 2012";

[/sourcecode]

Khi đó, nếu xem nội dung của chuỗi myName chắc chắn bạn nhận được là “Tạp chí Lập trình – 2012”, tuy nhiên để làm được điều này JVM sẽ phải tạo một đối tượng mới có chứa nội dung là “Tạp chí Lập trình – 2012” rồi gán nó cho tham chiếu myName thay vì sửa nội dung của đối tượng ban đầu. Đến đây chắc là bạn sẽ nghĩ tới tình huống mà ta cần thực hiện các hành động như thêm nội dung, bớt nội dung, thay thế, v.v. với một đối tượng String sẽ dẫn đến phát sinh hàng loạt các đối tượng String mới trong bộ nhớ.

Vậy vấn đề của chúng ta ở đây đó là hiệu suất (performance)? Quá rõ ràng rồi, nếu chúng ta thao tác nhiều với chuỗi (thay đổi nội dung)  thông qua các đối tượng String thì HIỆU SUẤT chính là vấn đề mà bạn gặp phải. Tức là càng tạo ra nhiều đối tượng tạm thì bộ thu dọn rác (Garbage Collection) càng phải làm việc nhiều hơn để dọn dẹp lại bộ nhớ.

Trong trường hợp này StringBuilder hoặc StringBuffer sẽ giúp bạn giải quyết vấn đề về hiệu suất. Tại sao vậy?

Như đã khẳng định ở phần đầu, hai lớp trên đều thuộc lọai mutable, chúng ta có thể thay đổi được các giá trị của chúng, hay nói cách khác các chuỗi chứa trong StringBuffer, StringBuilder có thể thay đổi được giá trị. Nhờ đặc tính này mà khi thay đổi các chuỗi trong những đối tượng này JVM không phải tạo các đối tượng mới (đối tượng tạm) và vấn đề về performance như kể trên với String được giải quyết triệt để ở StringBuffer, StringBuilder. Chúng ta cùng xem thao tác thay đổi nội dung một chuỗi với StringBuilder:

Tạo mới một chuỗi:

[sourcecode language=”java”]

StringBuilder myName = new StringBuilder("Tạp chí Lập trình");

//Bổ sung vào cuối một chuỗi
myName.append(" – 2012");

[/sourcecode]

Vậy là bạn đã đổi được nội dung của một chuỗi với StringBuilder mà không lo sợ về performance.

Nếu bạn muốn có bằng chứng thuyết phục hơn về sự hiệu quả của StringBuilder so với String, xin mời đọc thêm bài viết này: Dùng Profiler đo hiệu năng ứng dụng Java.

Cuối cùng, bạn có muốn biết sự khác biệt giữa StringBuilder và StringBuffer không? Hai lớp này được thiết kế với mục đích giống nhau, đó là thao tác hiệu quả với chuỗi, chúng cũng có các phương thức giống nhau để làm việc với chuỗi. Điểm khác biệt đáng lưu ý: StringBuffer thuộc loại synchronized do đó các phương thức của nó đều là “thread safe” (thích hợp với xử lý đa luồng – multi thread), trong khi StringBuilder thì ngược lại, không synchronized. Với đặc tính “thread safe”, các phương thức của StringBuffer sẽ chạy chậm hơn so với StringBuilder, vì vậy nếu không làm về Multi-thread bạn nên chọn StringBuilder thay vì chọn StringBuffer.

Lưu ý: StringBuilder mới được giới thiệu từ Java 1.5, do đó nếu bạn đang phát triển trên Java 1.4 bạn sẽ không sử dụng được lớp này.

Nguyễn Việt Khoa.