Java Bài 14: StringBuffer Và StringBuilder

Posted by

Được chỉnh sửa ngày 22/3/2017.

Chào mừng các bạn quay trở lại với bài học số 14 trong chương trình học 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 hàm của Chuỗi của 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 là 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ẽ có nhiều nguy cơ trở thành rác, làm ảnh hưởng đến hiệu năng của ứng dụng.

Khi đó StringBufferStringBuilder 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). Chúng đã làm điều đó như thế nào? 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à: 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 😉 .

Có một số so sánh về tốc độ trên mạng có chỉ ra rằng, sử dụng StringBuilder là nhanh nhất, sau đó đến StringBuffer rồi cuối cùng là String. Mình tin là điều này đúng, nhưng mình vẫn chưa có cơ hội kiểm chứng.

Nếu bạn vẫn chưa nắm rõ lắm về sự khác nhau giữa StringBuffer và StringBuilder, mà vẫn muốn áp dụng chúng vào project hiện tại của bạn thay vì phải đợi đến khi học đến Luồng (Thread), thì bạn có thể dùng tạm một trong hai, StringBuffer chẳng hạn.

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 hàm 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 hàm nối chuỗi chính là hàm 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ũ mà 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"

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 str6 = new StringBuffer();
System.out.println(str6.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 str7 = new StringBuffer(30);
System.out.println(str7.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 str8 = new StringBuffer();
str8.append("Hello World!");
System.out.println(str8.capacity()); // Kết quả in ra là 16

Vậy khi bạn khai báo và thêm một chuỗi 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 thì 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);

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 đánh giá 5 sao nếu thấy thích bài viết, hãy comment bên dưới nếu có thắc mắc, hãy để lại địa chỉ email của bạn để nhận được thông báo mới nhất khi có bài viết mới, và nhớ chia sẻ các bài viết của Yellow Code Books đến nhiều người khác nữa nhé.

Bài Kế Tiếp

Tất nhiên là chúng ta bắt đầu tìm hiểu về OOP rồi.

Advertisements
Rating: 5.0/5. From 9 votes.
Please wait...

2 comments

Gửi phản hồi