JavaRush /Blog Java /Random-VI /Giới thiệu về String, StringBuffer và StringBuilder trong...

Giới thiệu về String, StringBuffer và StringBuilder trong Java

Xuất bản trong nhóm
Có ba lớp trong Java để làm việc với dữ liệu văn bản: String , StringBufferStringBuilder . Mọi nhà phát triển đều gặp phải vấn đề đầu tiên khi bắt đầu học ngôn ngữ. Còn hai người còn lại thì sao? Sự khác biệt của chúng là gì và khi nào nên sử dụng lớp này hay lớp khác? Nói chung, sự khác biệt giữa chúng là nhỏ, nhưng tốt hơn hết bạn nên hiểu mọi thứ trong thực tế :) Giới thiệu về String, StringBuffer và StringBuilder trong Java - 1

Lớp chuỗi

Lớp này đại diện cho một chuỗi các ký tự. Tất cả các chuỗi ký tự được xác định trong các chương trình, chẳng hạn như "Đây là Chuỗi" đều là các thể hiện của lớp Chuỗi. Chuỗi có hai tính năng cơ bản:
  • đây là một lớp bất biến
  • đây là buổi học cuối cùng
Nói chung, lớp String không thể có con ( final) và các thể hiện của lớp không thể sửa đổi sau khi tạo ( immutable). Điều này mang lại cho lớp String một số lợi thế quan trọng:
  1. Do tính bất biến, mã băm của một thể hiện của lớp String được lưu vào bộ đệm. Nó không cần phải được đánh giá mỗi lần vì giá trị trường của đối tượng sẽ không bao giờ thay đổi sau khi nó được tạo. Điều này mang lại hiệu suất cao khi sử dụng lớp này làm khóa cho HashMap.

  2. Lớp String có thể được sử dụng trong môi trường đa luồng mà không cần đồng bộ hóa bổ sung.

  3. Một đặc điểm khác của lớp String là nó nạp chồng +toán tử " " trong Java. Vì vậy, việc nối (cộng) các chuỗi khá đơn giản:

public static void main(String[] args) {
    String command = "Follow" + " " + "the" + " " + "white" + " " + "rabbit";
    System.out.println(command); // Follow the white rabbit
}
Về cơ bản, việc nối chuỗi được thực hiện bởi lớp StringBuilder hoặc StringBuffer (tùy theo ý của trình biên dịch) và một phương thức append(chúng ta sẽ nói về các lớp này sau). Nếu chúng ta thêm các thể hiện của lớp String với các thể hiện của các lớp khác thì lớp sau sẽ được rút gọn thành biểu diễn chuỗi:
public static void main(String[] args) {
    Boolean b = Boolean.TRUE;
    String result = "b is " + b;
    System.out.println(result); //b is true
}
Đây là một thuộc tính thú vị khác của lớp String: các đối tượng của bất kỳ lớp nào có thể được chuyển thành biểu diễn chuỗi bằng cách sử dụng phương thức toString()được xác định trong lớp Objectvà được kế thừa bởi tất cả các lớp khác. Thông thường phương thức toString() trên một đối tượng được gọi ngầm. Ví dụ: khi chúng ta hiển thị một cái gì đó trên màn hình hoặc thêm một Chuỗi vào một đối tượng của lớp khác. Lớp String có thêm một tính năng nữa. Tất cả các chuỗi ký tự được xác định trong mã Java, chẳng hạn như "asdf", được lưu vào bộ nhớ đệm tại thời điểm biên dịch và được thêm vào cái gọi là nhóm chuỗi. Nếu chúng ta chạy đoạn mã sau:
String a = "Wake up, Neo";
String b = "Wake up, Neo";

System.out.println(a == b);
Chúng ta sẽ thấy true trong bảng điều khiển vì các biến athực sự sẽ btham chiếu đến cùng một phiên bản của lớp String đã được thêm vào nhóm chuỗi tại thời điểm biên dịch. Nghĩa là, các phiên bản khác nhau của lớp có cùng giá trị sẽ không được tạo và bộ nhớ sẽ được lưu.

Sai sót:

Không khó để đoán rằng lớp String chủ yếu cần thiết để làm việc với các chuỗi. Nhưng trong một số trường hợp, những đặc điểm trên của lớp String có thể chuyển từ ưu điểm thành nhược điểm. Khi các chuỗi được tạo bằng mã Java, nhiều thao tác thường được thực hiện trên chúng:
  • chuyển đổi chuỗi sang các thanh ghi khác nhau;
  • trích xuất chuỗi con;
  • nối;
  • vân vân.
Hãy nhìn vào mã này:
public static void main(String[] args) {

    String s = " Wake up, Neo! ";
    s = s.toUpperCase();
    s = s.trim();

    System.out.println("\"" + s + "\"");
}
Thoạt nhìn có vẻ như chúng tôi chỉ dịch dòng “Wake up, Neo!” thành chữ hoa, loại bỏ khoảng trắng thừa khỏi chuỗi này và gói nó trong dấu ngoặc kép. Trên thực tế, do tính bất biến của lớp String, kết quả của mỗi thao tác là các thể hiện của chuỗi mới được tạo ra và các thể hiện của chuỗi cũ bị loại bỏ, tạo ra một lượng lớn rác. Làm thế nào để tránh lãng phí bộ nhớ?

Lớp StringBuffer

Để xử lý việc tạo rác tạm thời do sửa đổi đối tượng String, bạn có thể sử dụng lớp StringBuffer. Đây là mutablemột lớp học, tức là có thể thay đổi. Một đối tượng của lớp StringBuffer có thể chứa một tập hợp ký tự cụ thể, độ dài và giá trị của chúng có thể được thay đổi bằng cách gọi một số phương thức nhất định. Hãy xem lớp này hoạt động như thế nào. Để tạo một đối tượng mới, hãy sử dụng một trong các hàm tạo của nó, ví dụ:
  • StringBuffer() - sẽ tạo một đối tượng trống (không có ký tự)
  • StringBuffer(String str) - sẽ tạo một đối tượng dựa trên biến str (chứa tất cả các ký tự của str trong cùng một chuỗi)
Luyện tập:
StringBuffer sb = new StringBuffer();
StringBuffer sb2 = new StringBuffer("Not empty");
Việc nối chuỗi thông qua StringBuffer trong Java được thực hiện bằng cách sử dụng append. Nói chung, phương thức appendtrong lớp StringBuffer bị quá tải theo cách nó có thể chấp nhận hầu hết mọi kiểu dữ liệu:
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2));
    sb.append("; ");
    sb.append(false);
    sb.append("; ");
    sb.append(Arrays.asList(1,2,3));
    sb.append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3];
}
Phương thức này appendtrả về đối tượng mà nó được gọi (giống như nhiều phương thức khác), cho phép nó được gọi theo một “chuỗi”. Ví dụ trên có thể viết như sau:
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2))
            .append("; ")
            .append(false)
            .append("; ")
            .append(Arrays.asList(1,2,3))
            .append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3];
}
Lớp StringBuffer có một số phương thức để làm việc với chuỗi. Hãy liệt kê những cái chính:
  • delete(int start, int end)— xóa một chuỗi ký tự con bắt đầu từ vị trí start, kết thúcend
  • deleteCharAt(int index)— xóa ký tự tại vị tríindex
  • insert(int offset, String str)— chèn một dòng strvào vị trí offset. Phương thức này insertcũng bị quá tải và có thể nhận các đối số khác nhau
  • replace(int start, int end, String str)- sẽ thay thế tất cả các ký tự từ vị trí này startsang vị trí endkhác bằngstr
  • reverse()- đảo ngược thứ tự của tất cả các ký tự
  • substring(int start)- sẽ trả về một chuỗi con bắt đầu từ vị trí start
  • substring(int start, int end)- sẽ trả về một chuỗi con bắt đầu từ vị trí này startsang vị trí khácend
Danh sách đầy đủ các phương thức và hàm tạo có trong tài liệu chính thức . Các phương pháp trên hoạt động như thế nào? Hãy xem trong thực tế:
public static void main(String[] args) {
     String numbers = "0123456789";

     StringBuffer sb = new StringBuffer(numbers);

     System.out.println(sb.substring(3)); // 3456789
     System.out.println(sb.substring(4, 8)); // 4567
     System.out.println(sb.replace(3, 5, "ABCDE")); // 012ABCDE56789

     sb = new StringBuffer(numbers);
     System.out.println(sb.reverse()); // 9876543210
     sb.reverse(); // Return the original order

     sb = new StringBuffer(numbers);
     System.out.println(sb.delete(5, 9)); // 012349
     System.out.println(sb.deleteCharAt(1)); // 02349
     System.out.println(sb.insert(1, "One")); // 0One2349
    }

Thuận lợi:

  1. Như đã đề cập, StringBuffer là một lớp có thể thay đổi, do đó làm việc với nó không tạo ra cùng một lượng rác bộ nhớ như với String. Do đó, nếu có nhiều sửa đổi đối với chuỗi thì tốt hơn nên sử dụng StringBuffer.

  2. StringBuffer là một lớp an toàn cho luồng. Các phương thức của nó được đồng bộ hóa và các phiên bản có thể được sử dụng đồng thời bởi nhiều luồng.

Sai sót:

Một mặt, an toàn luồng là một lợi thế của lớp, mặt khác, nó là một bất lợi. Các phương thức được đồng bộ hóa chậm hơn các phương thức không được đồng bộ hóa. Đây là lúc StringBuilder phát huy tác dụng. Hãy cùng tìm hiểu xem đây là loại lớp Java nào - StringBuilder, nó có những phương thức nào và các tính năng của nó là gì.

Lớp StringBuilder

StringBuilder trong Java là một lớp đại diện cho một chuỗi ký tự. Nó rất giống với StringBuffer về mọi mặt ngoại trừ tính an toàn của luồng. StringBuilder cung cấp API tương tự như StringBuffer. Hãy chứng minh điều này bằng một ví dụ quen thuộc, thay thế việc khai báo các biến từ StringBufer sang StringBuilder:
public static void main(String[] args) {
    String numbers = "0123456789";

    StringBuilder sb = new StringBuilder(numbers);

    System.out.println(sb.substring(3)); //3456789
    System.out.println(sb.substring(4, 8)); //4567
    System.out.println(sb.replace(3, 5, "ABCDE")); //012ABCDE56789

    sb = new StringBuilder(numbers);
    System.out.println(sb.reverse()); //9876543210
    sb.reverse(); // Return the original order

    sb = new StringBuilder(numbers);
    System.out.println(sb.delete(5, 9)); //012349
    System.out.println(sb.deleteCharAt(1)); //02349
    System.out.println(sb.insert(1, "One")); //0One2349
}
Sự khác biệt duy nhất là StringBuffer an toàn cho luồng và tất cả các phương thức của nó đều được đồng bộ hóa, trong khi StringBuilder thì không. Đây là tính năng duy nhất. StringBuilder trong Java nhanh hơn StringBuffer do không đồng bộ hóa các phương thức. Do đó, trong hầu hết các trường hợp, ngoại trừ trong môi trường đa luồng, tốt hơn nên sử dụng StringBuilder cho chương trình Java. Chúng tôi tóm tắt mọi thứ trong một bảng so sánh của ba lớp:

Chuỗi so với StringBuffer so với StringBuilder

Sợi dây Bộ đệm chuỗi Trình tạo chuỗi
Khả năng thay đổi Immutable(KHÔNG) mutable(Đúng) mutable(Đúng)
Khả năng mở rộng final(KHÔNG) final(KHÔNG) final(KHÔNG)
An toàn chủ đề Có, do tính bất biến Có, do đồng bộ hóa KHÔNG
Khi nào nên sử dụng Khi làm việc với các chuỗi hiếm khi được sửa đổi Khi làm việc với các chuỗi sẽ được sửa đổi thường xuyên trong môi trường đa luồng Khi làm việc với các chuỗi sẽ được sửa đổi thường xuyên trong môi trường đơn luồng
Bạn có thể nghiên cứu chủ đề này chi tiết hơn ở cấp độ thứ hai của nhiệm vụ Đa luồng Java trong khóa học JavaRush:
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION