- Sản phẩm & Dịch vụSản phẩm & Dịch vụ
- Giải phápGiải pháp
- Bảng giáBảng giá
- Công tyCông ty
- Tài liệuTài liệu
vi
vi
Chuyên mục với các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.
Web Developer
I’m passionate about web development and sharing my insights through articles, with over 8 years of experience. I hope these sharings inspire you and help build a strong web development community. @#@ Tôi đam mê phát triển web và chia sẻ những hiểu biết của mình thông qua các bài viết, với hơn 8 năm kinh nghiệm. Tôi hy vọng những chia sẻ này sẽ truyền cảm hứng cho các bạn và giúp xây dựng một cộng đồng phát triển web mạnh mẽ.
Thảo luận (0)
Đăng nhập để thảo luận
String là một trong những lớp được sử dụng rộng rãi nhất trong Java. StringBuffer và StringBuilder cung cấp các phương thức để thao tác với chuỗi. Chúng ta sẽ tìm hiểu sự khác biệt giữa sự khác biệt giữa String, StringBuffer và StringBuilder. Nên dùng StringBuffer hay StringBuilder cũng là một câu hỏi phổ biến trong phỏng vấn Java.

String là một trong những chủ đề quan trọng nhất trong phỏng vấn core Java. Nếu cần viết một chương trình in dữ liệu ra console, bạn sẽ dùng String. Hướng dẫn này tập trung vào những đặc điểm chính của lớp String, sau đó so sánh với các lớp StringBuffer và StringBuilder.
String str = "ABC";
// hoặc
String str = new String("ABC");
new để tạo chuỗi, đối tượng sẽ được tạo trong heap memory.+ được nạp chồng cho String. Có thể dùng để nối 2 chuỗi, mặc dù bên trong JVM thực hiện thao tác này bằng StringBuffer.equals() và hashCode(). Hai String chỉ bằng nhau khi có cùng chuỗi ký tự. Phương thức equals() phân biệt chữ hoa và chữ thường. Nếu muốn so sánh mà không phân biệt chữ hoa và chữ thường, bạn nên dùng equalsIgnoreCase().private int hash. Trường này lưu giá trị của hàm hashCode(). Giá trị hash chỉ được tính khi phương thức hashCode() được gọi lần đầu, sau đó lưu lại trong trường này. Hash được tạo dựa trên các trường final của lớp String cùng một số phép tính. Vì vậy mỗi lần gọi hashCode(), kết quả trả về luôn giống nhau. Với người gọi, có vẻ như việc tính toán được thực hiện lại trong mỗi lần gọi phương thức nhưng thực tế giá trị đã được lưu sẵn trong trường hash.Vì String là immutable trong Java, nên mỗi khi thực hiện thao tác như nối chuỗi (concatenation), tách chuỗi (substring),… JVM sẽ tạo ra một String mới và bỏ String cũ vào garbage collection. Đây là các thao tác tiêu tốn nhiều tài nguyên xử lý và tạo ra nhiều đối tượng rác trong heap.
Để khắc phục, Java cung cấp các lớp StringBuffer và StringBuilder dùng cho việc thao tác chuỗi. StringBuffer và StringBuilder là các đối tượng mutable trong Java, cung cấp các phương thức append(), insert(), delete() và substring() để xử lý chuỗi.
Trước Java 1.4, StringBuffer là giải pháp thao tác với chuỗi duy nhất trên Java. Tuy nhiên, nhược điểm của nó là tất cả các phương thức public đều được đồng bộ hóa. StringBuffer đảm bảo an toàn theo luồng (thread-safety) nhưng phải đánh đổi bằng hiệu năng.
Trong hầu hết trường hợp, chuỗi không được dùng trong môi trường đa luồng, vì thế Java 1.5 đã giới thiệu lớp StringBuilder, có chức năng tương tự StringBuffer nhưng không có cơ chế đồng bộ hóa và thread-safety.
StringBuffer có thêm một số phương thức như substring, length, capacity, trimToSize…, tuy nhiên chúng không thực sự cần thiết vì đã có sẵn trong lớp String. Chính vì vậy các phương thức này không được triển khai trong lớp StringBuilder.
StringBuffer ra mắt từ Java 1.0, còn StringBuilder chỉ được bổ sung ở Java 1.5 để khắc phục những hạn chế của StringBuffer. Trong môi trường đơn luồng hoặc khi không cần đến thread safety, bạn nên dùng StringBuilder. Ngược lại, nếu yêu cầu thao tác an toàn theo luồng thì hãy chọn StringBuffer.
Để kiểm tra ảnh hưởng của cơ chế đồng bộ hóa đến hiệu năng, chúng ta sẽ dùng một chương trình mẫu, trong đó thực hiện nhiều lần gọi append() trên đối tượng StringBuffer và StringBuilder.
package com.journaldev.java;import java.util.GregorianCalendar;
public class TestString {
public static void main(String[] args) { System.gc(); long start=new GregorianCalendar().getTimeInMillis(); long startMemory=Runtime.getRuntime().freeMemory(); StringBuffer sb = new StringBuffer(); //StringBuilder sb = new StringBuilder(); for(int i = 0; i<10000000; i++){ sb.append(":").append(i); } long end=new GregorianCalendar().getTimeInMillis(); long endMemory=Runtime.getRuntime().freeMemory(); System.out.println("Time Taken:"+(end-start)); System.out.println("Memory used:"+(startMemory-endMemory)); }}
Đoạn code trên cũng được chạy với đối tượng StringBuffer để so sánh thời gian và bộ nhớ sử dụng. Mỗi trường hợp được thực thi 5 lần và sau đó tính giá trị trung bình.
| Giá trị i | StringBuffer (Time, Memory) | StringBuilder (Time, Memory) |
|---|---|---|
| 10,00,000 | 808, 149356704 | 633, 149356704 |
| 1,00,00,000 | 7448, 147783888 | 6179, 147783888 |
Kết quả cho thấy StringBuilder cho hiệu năng tốt hơn StringBuffer ngay cả trong môi trường đơn luồng. Nguyên nhân chính của sự khác biệt này là do các phương thức trong StringBuffer đều được đồng bộ hóa.
+) trong nội bộ thực chất sử dụng lớp StringBuffer hoặc StringBuilder.Trên đây là phần tổng kết nhanh sự khác biệt giữa String, StringBuffer và StringBuilder. Trong hầu hết các tình huống lập trình phổ biến, StringBuilder phù hợp hơn so với StringBuffer.