Chuỗi là gì
Một String chứa một dãy ký tự: văn bản như một cái tên, một câu hay một dòng đọc từ tệp. Bạn đã thấy String nằm trong danh sách kiểu tham chiếu ở trang trước; ở đây bạn sẽ thật sự làm việc với nó. Bạn viết một chuỗi (string) bằng dấu nháy kép (nháy đơn dành riêng cho một char duy nhất):
name.length() trả về số ký tự: 3 với "Ada". Đây là một lời gọi phương thức, nên cần dấu ngoặc đơn.
Nối chuỗi
Toán tử + nối các chuỗi lại với nhau. Nếu một trong hai vế của + là chuỗi, vế còn lại tự động được chuyển thành văn bản, nên bạn có thể trộn số và boolean vào mà không cần làm gì thêm:
Một điểm cần lưu ý: vì + tính từ trái sang phải, "" + 1 + 2 cho ra "12" (chuỗi + int, rồi chuỗi + int), nhưng 1 + 2 + "" cho ra "3" (hai số int cộng trước, rồi mới thành văn bản). Khi không chắc, hãy bọc phép tính trong ngoặc đơn.
Chuỗi là bất biến
Đây là điều quan trọng nhất cần hiểu về chuỗi trong Java: một String không bao giờ thay đổi sau khi được tạo. Mọi phương thức "sửa" chuỗi thật ra đều trả về một chuỗi hoàn toàn mới và giữ nguyên chuỗi gốc. Vì vậy nếu bạn quên lấy giá trị trả về, sẽ không có gì xảy ra:
Lời gọi đầu tiên tính ra "HELLO" rồi vứt đi ngay. Chỉ có dòng thứ hai, gán ngược lại vào s, mới có tác dụng thấy được. Gần như ai cũng từng vấp phải điều này một lần.
So sánh chuỗi
Dùng .equals() để so sánh nội dung của hai chuỗi. Dùng == là sai lầm kinh điển của người mới: == hỏi "đây có phải cùng một đối tượng trong bộ nhớ không?", chứ không hỏi "chúng có chứa cùng văn bản không?":
a == b ở đây là false vì new String(...) buộc tạo ra một đối tượng riêng. Luôn so sánh giá trị chuỗi bằng .equals() (hoặc .equalsIgnoreCase() để bỏ qua chữ hoa chữ thường). Một mẹo hay để tránh bị sập khi một vế có thể là null là gọi .equals trên chuỗi hằng: "yes".equals(input) không bao giờ ném lỗi kể cả khi input là null.
Các phương thức chuỗi dùng hằng ngày
Vì chuỗi là bất biến, mỗi phương thức dưới đây trả về một chuỗi mới (hoặc một giá trị) thay vì thay đổi chuỗi gốc. Đây là những phương thức bạn sẽ dùng liên tục:
Để ý cách gọi nối tiếp: s.trim().toUpperCase() chạy được vì trim() trả về một chuỗi, và bạn gọi tiếp toUpperCase() trên chuỗi đó. substring là một phương thức chủ lực khác: nó nhận chỉ số bắt đầu (bao gồm) và chỉ số kết thúc tùy chọn (không bao gồm):
Chỉ số bắt đầu từ 0, nên substring(0, 4) lấy các ký tự từ 0 đến 3. Yêu cầu một chỉ số vượt quá cuối chuỗi sẽ ném ra StringIndexOutOfBoundsException, một trong các ngoại lệ lúc chạy mà bạn có thể phòng tránh. Cũng lưu ý rằng split(",") ở trên trả về một mảng, nơi length là một thuộc tính không có dấu ngoặc, khác với phương thức .length() của chuỗi.
Tạo chuỗi trong vòng lặp
Nối bằng + vẫn ổn với vài mảnh, nhưng làm vậy bên trong một vòng lặp lớn thì chậm: mỗi lần + tạo ra một chuỗi mới và sao chép mọi thứ. Khi ghép văn bản trong vòng lặp, hãy dùng StringBuilder, nó sửa trực tiếp một vùng đệm và chỉ tạo chuỗi cuối cùng một lần ở cuối:
append trả về chính builder đó, nên các lời gọi có thể nối tiếp. Gọi .toString() để lấy ra một String bình thường ở cuối. Với những lần nối đơn lẻ, cứ dùng +; với việc gom nhiều mảnh, StringBuilder là công cụ phù hợp.
Tiếp theo: định dạng chuỗi
Nối chuỗi trở nên lộn xộn khi bạn cần các cột thẳng hàng, số chữ số thập phân cố định hay số được đệm. String.format và printf của Java dùng một mẫu với các chỗ giữ chỗ % để xử lý tất cả những việc đó một cách gọn gàng, và đó là nội dung của trang tiếp theo.
Câu hỏi thường gặp
So sánh hai chuỗi trong Java như thế nào?
Dùng .equals() để so sánh nội dung: a.equals(b) trả về true khi các ký tự giống nhau. Đừng dùng == để so sánh giá trị chuỗi: == so sánh tham chiếu đối tượng, nên nó có thể trả về false cho hai chuỗi chứa cùng một văn bản. Dùng .equalsIgnoreCase() khi không cần phân biệt chữ hoa chữ thường.
Vì sao chuỗi trong Java là bất biến?
Một khi đã tạo, đối tượng String không bao giờ thay đổi được. Các phương thức như replace hay toUpperCase trả về một chuỗi mới thay vì sửa chuỗi gốc. Tính bất biến giúp chuỗi an toàn khi chia sẻ và lưu đệm, nhưng nó có nghĩa là bạn phải gán kết quả: s = s.toUpperCase();. Nếu bạn gọi một phương thức mà bỏ qua giá trị trả về, sẽ không có gì xảy ra.
Lấy độ dài chuỗi trong Java như thế nào?
Gọi phương thức .length(): "hello".length() trả về 5. Lưu ý trên String đây là một phương thức có dấu ngoặc đơn, khác với mảng, nơi length là một thuộc tính không có dấu ngoặc (arr.length).