Được chỉnh sửa ngày 23/11/2022.
Chào mừng các bạn đến với bài học Java số 14, bài học về StringBuffer và StringBuilder. Bài học này nằm trong chuỗi bài học lập trình ngôn ngữ Java của Yellow Code Books.
Bài này là bài học mở rộng so với bài về Chuỗi của bữa trước. Có thể nói là bài học bổ sung, nó không quan trọng lắm, nhưng không nói thì lại áy náy, ăn ngủ không yên. Nếu bạn nào quan tâm đến hiệu năng (performance) của ứng dụng, thì chú ý kỹ các bài học dạng này.
Để làm quen với các kiến thức và ví dụ của bài học hôm nay, bạn nhất thiết phải thực hành một chút với các phương thức của chuỗi ở bài trước để hiểu được cơ bản đối tượng này, thì hôm nay bạn mới có thể làm quen dễ hơn với các khái niệm và phương thức mở rộng.
Tại Sao Phải Biết Về StringBuffer Và StringBuilder?
Tất nhiên đây sẽ là thắc mắc đầu tiên của các bạn khi mình giới thiệu hai đối tượng này trong ngày hôm nay.
Chà… thực ra bài học hôm nay mình cũng cân nhắc nhiều. Bạn cũng biết là khi tìm hiểu về chuỗi thì coi như bạn đã “đặt một chân” vào cánh cửa OOP rồi, mà chúng ta lại chưa có bài viết nào về OOP cả. Vậy mà StringBuffer và StringBuilder của bài hôm nay lại tiếp tục nói nữa về OOP. Nhưng mình nghĩ nếu biết về chúng trễ quá sau khi học hết OOP thì lại không hay chút nào. Thế là mình quyết định thôi thì nói trước, sau này làm quen với OOP chắc chắn các bạn sẽ hiểu rõ hơn bài học hôm nay.
Vậy quay lại câu hỏi tại sao phải biết hai đối tượng này? Như bài hôm trước mình có nói, nếu bạn đã làm quen với chuỗi thì nên biết rằng chuỗi mang đặc tính không thể thay đổi được, tiếng Anh gọi là immutable. Điều này có nghĩa là khi bạn tạo ra một chuỗi, thì chuỗi đó là cố định và bạn không thể thay đổi được.
Nhưng mà khoan!!! Bài hôm trước chúng ta có thực hành việc nối chuỗi, cắt chuỗi, chuyển in hoa/thường cho chuỗi… thì đó không phải là thay đổi chuỗi hay sao??? Hoang mang quá.
Thực ra là, nếu bạn tác động để làm một chuỗi thay đổi, hệ thống sẽ tạo ra chuỗi mới cho bạn. Chuỗi cũ (trước khi bị bạn thay đổi) sẽ còn lại trong hệ thống và sẽ trở thành rác, làm ảnh hưởng đến hiệu năng của ứng dụng.
Khi đó StringBuffer và StringBuilder ra đời nhằm đáp ứng nhu cầu của bạn trong các trường hợp muốn sử dụng đến chuỗi có khả năng thay đổi được (mutable). Sử dụng chúng như thế nào? Có khác với chuỗi truyền thống không? Mời các bạn xem tiếp phần dưới sẽ rõ.
StringBuffer Và StringBuilder Khác Nhau Ra Sao?
Lại một câu hỏi nữa khiến mình càng thêm cân nhắc khi nói đến hai đối tượng này ở bài hôm nay. Vì câu trả lời cho câu hỏi này lại liên quan đến khái niệm luồng, hay đa luồng. Cụ thể là: StringBuffer và StringBuilder có công năng và cách sử dụng hoàn toàn giống nhau, tuy nhiên về mặt cấu trúc thì có khác nhau đôi chút, đó là StringBuffer được cấu tạo để ứng dụng vào các xử lý đa luồng (multithreading) giúp tránh các tranh chấp giữa các luồng (thread), còn StringBuilder được cấu tạo để ứng dụng trong một luồng mà thôi. Khái niệm luồng hay đa luồng sẽ được nói đến ở các bài học sau nữa, do đó một lần nữa mình chỉ muốn nêu ra cho các bạn biết, còn để hiểu rõ hơn thì bạn lại phải tiếp tục theo dõi dông dài các bài viết của Yellow Code Books rồi 😉 .
Nếu bạn đọc document từ trang chính chủ Oracle thì sẽ biết, sử dụng StringBuilder sẽ cho ra tốc độ xử lý nhanh hơn so với StringBuffer. Nội dung của document này cụ thể như sau (dòng này là đang nói về StringBuilder).
This class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.
Cách Sử Dụng StringBuffer Và StringBuilder
Do mình đã nói rằng, cách sử dụng StringBuffer và String Builder là hoàn toàn giống nhau, do đó ở mục cách sử dụng này, mình chỉ đưa ra ví dụ về StringBuffer thôi nhé, bạn hoàn toàn có thể áp dụng các kiến thức của phần này dành cho StringBuffer vào StringBuilder mà không gặp chút rắc rối nào.
Khai Báo Và Khởi Tạo
Bạn có nhớ hai cách khai báo và khởi tạo một chuỗi không? Nếu quên thì xem lại bài trước cho nhớ nhé. Cơ bản với chuỗi bạn sẽ có hai cách khởi tạo, hoặc là khởi tạo kiểu “nguyên thủy”, hoặc là khởi tạo kiểu “đối tượng”.
Còn với StringBuffer (và cả StringBuilder) của bài hôm nay thì hơi khác chuỗi thông thường một chút, đó là chỉ có một cách duy nhất để khởi tạo chúng mà thôi, chính là khởi tạo kiểu “đối tượng”.
Như đã trình bày ở bài chuỗi, bài này mình cũng xin đưa ra ví dụ về khai báo StringBuffer mà không đưa ra cú pháp.
StringBuffer strBuffer_1 = new StringBuffer(); // Khởi tạo một StringBuffer rỗng, với khả năng chứa đựng ban đầu là 16 ký tự StringBuffer strBuffer_2 = new StringBuffer(50); // Khởi tạo một StringBuffer rỗng, với khả năng chứa đựng ban đầu do bạn định nghĩa StringBuffer strBuffer_3 = new StringBuffer("Hello World!"); // Giống với Chuỗi, cách này khởi tạo một StringBuffer với chuỗi xác định
Và vì StringBuffer và StringBuilder là các cấu trúc giúp thay đổi chuỗi thoải mái, nên bạn cứ yên tâm là sẽ không ảnh hưởng đến hiệu suất của hệ thống nếu bạn thay đổi nhiều và liên tục trên chuỗi. Dưới đây là các phương thức hữu ích của StringBuffer và StringBuilder mà bạn có thể xem sơ qua.
Nối Chuỗi – append()
Nếu như với chuỗi, bạn có thể dùng phương thức concat() hay toán tử + để nối hai chuỗi lại với nhau, nhưng cách này như chúng ta biết nó sẽ tạo ra một chuỗi mới là sự kết kợp của hai chuỗi cũ. Thì với bài này phương thức nối chuỗi chính là append() sẽ có tác dụng gần như tương tự, tức là sẽ thêm chuỗi mới vào chuỗi cũ (hệ thống vẫn không tạo ra chuỗi khác). Bạn xem ví dụ cách sử dụng hàm này như sau.
StringBuffer str1 = new StringBuffer("Hello World!"); str1.append(" Hello Yellow Code Books!"); System.out.println(str1); // Kết quả in ra là "Hello World! Hello Yellow Code Books!"
Chèn Chuỗi – insert()
Phương thức này giúp chèn một chuỗi vào một vị trí nào đó ở chuỗi gốc. Ví dụ dưới đây giúp chèn thêm chuỗi “Java” vào sau chuỗi “Hello” ở ví dụ trên, để tạo thành chuỗi “Hello Java World! Hello Yellow Code Books!”.
StringBuffer str2 = new StringBuffer("Hello World!"); str2.append(" Hello Yellow Code Books!"); str2.insert(5, " Java"); System.out.println(str2); // Kết quả in ra là "Hello Java World! Hello Yellow Code Books!"
Thay Thế – replace()
Nếu bạn còn nhớ thì ở chuỗi chúng ta cũng đã làm quen với phương thức có tên replace() này rồi. Nhưng khi đó tham số truyền vào của replace() là hai chuỗi, giúp bạn thay thế tất cả chuỗi nếu có tồn tại trong chuỗi gốc bằng một chuỗi mới. Qua đến replace() của bài hôm nay các bạn phải chỉ định vị trí bắt đầu và kết thúc của chuỗi gốc cần được thay thế bằng chuỗi mới. Như ví dụ sau (mình lấy lại từ yêu cầu thực hành thay thế chuỗi “Hello” thành “Hi” ở bài trước).
StringBuffer str3 = new StringBuffer("Hello World! Hello Yellow Code Books!"); str3.replace(0, 5, "Hi"); System.out.println(str3); // Kết quả in ra là "Hi World! Hello Yellow Code Books!"
Bạn lưu ý là chuỗi mới “Hi” chỉ thay thế cho chuỗi “Hello” có vị trí từ 0 đến 5 trong chuỗi gốc. chuỗi “Hello” đứng sau đó vẫn còn trong chuỗi gốc, điều này khác với replace() ở bài Chuỗi là thay thế hết tất cả “Hello” thành “Hi” luôn đấy nhé.
Xóa Chuỗi – delete()
Phương thức này không có trong bài trước, dùng để xóa chuỗi từ vị trí bắt đầu đến vị trí kết thúc trong chuỗi gốc. Ví dụ sau xóa chuỗi “Java” ra khỏi chuỗi gốc ban đầu.
StringBuffer str4 = new StringBuffer("Hello Java World! Hello Yellow Code Books!"); str4.delete(6, 11); System.out.println(str4); // Kết quả in ra là "Hello World! Hello Yellow Code Books!"
Đảo Ngược Chuỗi – reverse()
Một phương thức khá thú vị ở bài hôm nay, đó là đảo chuỗi. Bạn hãy xem kết quả đảo ngược từ ví dụ bên dưới.
StringBuffer str5 = new StringBuffer("Hello World! Hello Yellow Code Books!"); str5.reverse(); System.out.println(str5); // Kết quả in ra là "!skooB edoC wolleY olleH !dlroW olleH"
Trích Xuất Chuỗi – toString()
Trong trường hợp bạn đã xử lý xong các thao tác trên chuỗi thông qua StringBuffer hay StringBuilder, mà muốn chúng xuất ra một chuỗi cuối cùng có kiểu String, thì hãy dùng phương thức toString() như sau.
StringBuffer str6 = new StringBuffer("Hello World! Hello Yellow Code Books!"); str6.reverse(); String strFinal = str6.toString(); System.out.println(strFinal);
Kiểm Tra Dung Lượng Bộ Đệm – capacity()
Ở bước khởi tạo trên đây bạn đã biết đến khả năng chứa đựng số lượng ký tự của StringBuffer và StringBuilder. Nếu bạn khởi tạo các đối tượng này rỗng, dung lượng mặc định ban đầu là 16. Hãy xem ví dụ chứng minh sau đây.
StringBuffer str7 = new StringBuffer(); System.out.println(str7.capacity()); // Kết quả in ra là 16
Điều này cũng giống khi bạn làm việc với Mảng, khi đó bạn cấp phát một bộ nhớ cho mảng có khả năng chứa 16 phần tử chẳng hạn mà chưa khởi tạo giá trị cho Mảng đó. Thì với cách khai báo trên đây của StringBuffer cũng vậy. Hay với cách khai báo trên đây có truyền vào số lượng ký tự có thể chứa ban đầu.
StringBuffer str8 = new StringBuffer(30); System.out.println(str8.capacity()); // Kết quả in ra là 30
Mình tiếp tục thử thêm chuỗi vào rồi kiểm tra lại capicity() nhé.
StringBuffer str9 = new StringBuffer(); str9.append("Hello World!"); System.out.println(str9.capacity()); // Kết quả in ra là 16
Vậy khi bạn khai báo và thêm một chuỗi “Hello World!” vào thì dung lượng mặc định ban đầu vẫn dựa vào khả năng chứa 16 ký tự. Nếu số lượng ký tự của chuỗi vượt qua 16, khả năng chứa sẽ tự tăng lên. Điều này làm cho StringBuffer và StringBuilder khá linh động và hiệu năng sử dụng bộ nhớ cũng được tối ưu nữa.
Ngoài các phương thức cho StringBuffer và StringBuilder trên đây, đó là các phương thức đặc biệt linh động mà với chuỗi ở bài trước không có. Thì hai anh em mới này của chuỗi cũng vẫn có các phương thức tương tự như bên chuỗi mà bạn có thể mang ra dùng, mình chỉ điểm mặt thôi, đó là.
subString(startIndex);
subString(startIndex, endIndex);
charAt(index);
indexOf(Chuỗi);
Kết Luận
Chúng ta vừa đến với kiến thức có thể nói là cuối cùng của Java Cơ Bản trong chương trình học của Yellow Code Books, để từ bài học sau sẽ cùng nhau bước sang một lĩnh vực mới trong lập trình, tất nhiên vẫn sẽ là ngôn ngữ Java, nhưng sẽ là các bài học về hướng đối tượng (OOP) của Java.
Cảm ơn bạn đã đọc các bài viết của Yellow Code Books. Bạn hãy ủng hộ blog bằng cách:
– Đánh giá 5 sao ở mỗi bài viết nếu thấy thích.
– Comment bên dưới mỗi bài viết nếu có thắc mắc.
– Để lại địa chỉ email của bạn ở thanh bên phải để nhận được thông báo sớm nhất khi có bài viết mới.
– Chia sẻ các bài viết của Yellow Code Books đến nhiều người khác.
– Ủng hộ blog theo hướng dẫn ở thanh bên phải để blog ngày càng phát triển hơn.
Bài Kế Tiếp
Tất nhiên là chúng ta bắt đầu tìm hiểu về OOP rồi.
a dạy dễ hiểu quá!!!
e cảm ơn a <3
Đúng tiêu chí “lập trình dễ dàng với…” ha 😀
Quá hay ạ lần đầu e biết đến StringBuffer luôn hihi e cảm ơn a nhiều
bài viết siêu hay luôn ạ <3
cảm ơn ad, cực kỳ chi tiết, dễ hiểu
cảm ơn ad nha, viết rất hay ạ