Sự bất biến của String và giải pháp hiệu quả trong Java

0 0 0

Người đăng: Vinh Phạm

Theo Viblo Asia

Trong Java, chuỗi thường được thao tác, kết hợp và lưu trữ trên nhiều ứng dụng, do đó, việc hiểu được sự khác biệt giữa xử lý chuỗi bất biến và có thể thay đổi là rất quan trọng để viết mã hiệu quả. Bài đăng này khám phá các khái niệm về khả năng thay đổi và bất biến trong chuỗi Java, đi sâu vào lý do tại sao Java cung cấp các lớp riêng biệt như String, StringBuilder, và StringBuffer.

1. Tính bất biến của String trong Java

Trong Java, String là một kiểu dữ liệu bất biến. Điều này có nghĩa là một khi đối tượng String được tạo ra, giá trị của nó không thể thay đổi. Tính chất này mang lại lợi ích về bảo mật, hiệu suất và hiệu quả bộ nhớ trong môi trường đa luồng. Tính bất biến đảm bảo rằng:

  • Tính nhất quán: Khi một chuỗi được gán một giá trị, giá trị đó sẽ không đổi.
  • An toàn luồng: Nhiều luồng có thể sử dụng cùng một phiên bản String một cách an toàn mà không cần đồng bộ hóa.
  • Hiệu quả bộ nhớ: Java có một String Pool nội bộ để quản lý các đối tượng String một cách hiệu quả. Pool này lưu trữ một bản sao duy nhất của mỗi chuỗi ký tự, tái sử dụng nó bất cứ khi nào có thể.

VD:

String greeting = "Hello";
greeting = greeting + " World"; // A new String object is created
System.out.println(greeting); // Output: Hello World

Trong ví dụ trên, khi ta nối chuỗi " World" vào chuỗi "Hello", một đối tượng String mới được tạo ra thay vì thay đổi giá trị của chuỗi ban đầu. Tuy nhiên, tính bất biến này cũng có thể dẫn đến vấn đề về hiệu suất và bộ nhớ nếu chuỗi cần được thay đổi thường xuyên. Mỗi lần thay đổi, một đối tượng String mới được tạo ra, làm tăng mức sử dụng bộ nhớ và gây áp lực lên bộ thu gom rác.

2. Sử dụng String trong các tình huống có thể thay đổi: Nhược điểm

Mặc dù tính bất biến của String là một đặc điểm có giá trị, nhưng nó có thể dẫn đến các vấn đề về bộ nhớ và hiệu suất nếu được sử dụng trong các tình huống cần phải sửa đổi thường xuyên. Mỗi lần một String thay đổi, một đối tượng mới sẽ được tạo ra, làm tăng mức sử dụng bộ nhớ và gây thêm áp lực cho trình thu gom rác.

Hãy xem xét ví dụ sau về cách nối chữ cái:

private String alphabetConcat() { String series = ""; for (int i = 0; i < 26; i++) { series += (char) ('a' + i); System.out.println(series); // Outputs: a ab abc abcd ... } return series;
}

Qua ví dụ trên, mỗi lần lặp thì một đối tượng String mới được tạo ra do tính bất biến, dẫn đến độ phức tạp thời gian là O(n^2), khiến quá trình này trở nên không hiệu quả. Việc này cũng gây lãng phí bộ nhớ vì mỗi đối tượng String trung gian được lưu trữ riêng biệt.

3. Các lựa chọn thay thế có thể thay đổi: StringBuilder và StringBuffer

Java cung cấp các phương án thay đổi như StringBuilder và StringBuffer để xử lý các trường hợp chuỗi thường xuyên bị sửa đổi.

StringBuilder cho phép sửa đổi chuỗi trực tiếp, cải thiện hiệu suất bằng cách tránh việc tạo ra các đối tượng trung gian. Đây là lựa chọn lý tưởng cho các trường hợp cần thao tác chuỗi nhiều.

Sau đây là cách nó hoạt động trong ví dụ trước của chúng ta ở trên:

private String alphabetConcat() { StringBuilder series = new StringBuilder(); for (int i = 0; i < 26; i++) { series.append((char) ('a' + i)); System.out.println(series); // Outputs: a ab abc abcd ... } return series.toString();
}

Sử dụng StringBuilder trong ví dụ trên, ta thấy rằng cùng một đối tượng được sửa đổi trong suốt vòng lặp. Điều này giảm độ phức tạp thời gian xuống O(n), hiệu quả hơn đáng kể so với việc sử dụng String.

Những điểm chính cần nhớ

  • String không thể thay đổi và được hỗ trợ bởi String Pool để tối ưu hóa bộ nhớ.
  • StringBuilder và StringBuffercó thể thay đổi. StringBuilder nhanh hơn nhưng không an toàn cho luồng, trong khi StringBuffer được đồng bộ hóa và an toàn cho luồng .
  • Sử dụng StringBuilder trong các tình huống luồng đơn với những sửa đổi thường xuyên.
  • Sử dụng String khi cần tính bất biến hoặc khi mong đợi những sửa đổi tối thiểu.

Phần kết luận

Bài đăng này thiết lập nền tảng để hiểu khi nào sử dụng String, StringBuilder, hoặc StringBuffer dựa trên khả năng thay đổi và hiệu quả. Cảm ơn các bạn đã theo dõi

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tổng hợp các bài hướng dẫn về Design Pattern - 23 mẫu cơ bản của GoF

Link bài viết gốc: https://gpcoder.com/4164-gioi-thieu-design-patterns/. Design Patterns là gì. Design Patterns không phải là ngôn ngữ cụ thể nào cả.

0 0 302

- vừa được xem lúc

Học Spring Boot bắt đầu từ đâu?

1. Giới thiệu Spring Boot. 1.1.

0 0 277

- vừa được xem lúc

Cần chuẩn bị gì để bắt đầu học Java

Cần chuẩn bị những gì để bắt đầu lập trình Java. 1.1. Cài JDK hay JRE.

0 0 50

- vừa được xem lúc

Sử dụng ModelMapper trong Spring Boot

Bài hôm nay sẽ là cách sử dụng thư viện ModelMapper để mapping qua lại giữa các object trong Spring nhé. Trang chủ của ModelMapper đây http://modelmapper.org/, đọc rất dễ hiểu dành cho các bạn muốn tìm hiểu sâu hơn. 1.

0 0 194

- vừa được xem lúc

[Java] 1 vài tip nhỏ khi sử dụng String hoặc Collection part 1

. Hello các bạn, hôm nay mình sẽ chia sẻ về mẹo check String null hay full space một cách tiện lợi. Mình sẽ sử dụng thư viện Lớp StringUtils download file jar để import vào thư viện tại (link).

0 0 71

- vừa được xem lúc

Deep Learning với Java - Tại sao không?

Muốn tìm hiểu về Machine Learning / Deep Learning nhưng với background là Java thì sẽ như thế nào và bắt đầu từ đâu? Để tìm được câu trả lời, hãy đọc bài viết này - có thể kỹ năng Java vốn có sẽ giúp bạn có những chuyến phiêu lưu thú vị. DJL là tên viết tắt của Deep Java Library - một thư viện mã ng

0 0 139