Java String là một trong những lớp được sử dụng rộng rãi nhất. Lớp Java String được định nghĩa trong package (gói) java.lang.
Java String là gì?
- Về cơ bản, string là một chuỗi ký tự nhưng nó không phải là một kiểu dữ liệu nguyên thủy (primitive type)
- Khi chúng ta tạo một chuỗi trong Java, nó thực sự tạo ra một đối tượng (object) thuộc kiểu string
- String là một đối tượng bất biến (immutable object), có nghĩa là nó không thể thay đổi sau khi đã được tạo.
- String là lớp duy nhất trong Java hỗ trợ nạp chồng toán tử (operator overloading). Chúng ta có thể nối hai chuỗi bằng cách sử dụng toán tử
+
. Ví dụ:"a" + "b" = "ab"
. - Java cung cấp hai lớp hữu ích để thao tác chuỗi là StringBuffer và StringBuilder.
Hãy cùng tìm hiểu thêm về lớp Java String.
Các cách khác nhau để tạo String
Có nhiều cách để tạo một đối tượng chuỗi trong Java. Dưới đây là một số cách phổ biến.
1. Sử dụng String Literal
Đây là cách phổ biến nhất để tạo chuỗi. Trong trường hợp này, một chuỗi ký tự (string literal) được đặt trong dấu ngoặc kép.
String str = "abc";
Khi chúng ta tạo một string sử dụng dấu ngoặc kép, JVM sẽ tìm kiếm trong string pool (vùng nhớ đặc biệt dành cho các string) để xem liệu có string nào khác có cùng giá trị đã được lưu trữ ở đó hay chưa. Nếu tìm thấy, nó chỉ trả về tham chiếu đến đối tượng string đó; nếu không, nó sẽ tạo một đối tượng string mới với giá trị đã cho và lưu trữ nó vào string pool.
2. Sử dụng từ khóa new
Chúng ta có thể tạo đối tượng string bằng toán tử new
, giống như bất kỳ lớp Java thông thường nào. Có một số hàm tạo (constructors) có sẵn trong lớp string để tạo string từ mảng ký tự (char array), mảng byte (byte array), StringBuffer và StringBuilder.
String str = new String("abc");
char[] a = {'a', 'b', 'c'};
String str2 = new String(a);
So sánh String trong Java
Lớp String cung cấp các phương thức equals()
và equalsIgnoreCase()
để so sánh hai chuỗi. Các phương thức này so sánh giá trị của chuỗi để kiểm tra xem hai chuỗi có bằng nhau hay không. Nó trả về true
nếu hai chuỗi bằng nhau và false
nếu không.
package com.journaldev.string.examples;
/**
* Java String Example
*
* @author pankaj
*
*/
public class StringEqualExample {
public static void main(String[] args) {
//creating two string object
String s1 = "abc";
String s2 = "abc";
String s3 = "def";
String s4 = "ABC";
System.out.println(s1.equals(s2));//true
System.out.println(s2.equals(s3));//false
System.out.println(s1.equals(s4));//false;
System.out.println(s1.equalsIgnoreCase(s4));//true
}
}
Kết quả của chương trình trên là:
true
false
false
true
Lớp string triển khai giao diện Comparable, cung cấp các phương thức compareTo()
và compareToIgnoreCase()
. Các phương thức này so sánh hai chuỗi theo thứ tự từ điển (lexicographically). Cả hai chuỗi được chuyển đổi thành giá trị Unicode để so sánh và trả về một giá trị số nguyên có thể lớn hơn, nhỏ hơn hoặc bằng 0. Nếu các chuỗi bằng nhau thì nó trả về 0, hoặc nếu không thì nó trả về một giá trị lớn hơn hoặc nhỏ hơn 0.
package com.journaldev.examples;
/**
* Java String compareTo Example
*
* @author pankaj
*
*/
public class StringCompareToExample {
public static void main(String[] args) {
String a1 = "abc";
String a2 = "abc";
String a3 = "def";
String a4 = "ABC";
System.out.println(a1.compareTo(a2));//0
System.out.println(a2.compareTo(a3));//less than 0
System.out.println(a1.compareTo(a4));//greater than 0
System.out.println(a1.compareToIgnoreCase(a4));//0
}
}
Kết quả của chương trình trên là:
0
-3
32
0
Các phương thức String trong Java
Hãy cùng xem xét một số phương thức phổ biến của lớp string cùng với một chương trình ví dụ.
1. split()
Phương thức Java String split()
được sử dụng để chia chuỗi dựa trên một biểu thức đã cho. Có hai biến thể của phương thức split()
:
split(String regex)
: Phương thức này chia chuỗi sử dụng biểu thức chính quy đã cho và trả về một mảng chuỗi.split(String regex, int limit)
: Phương thức này chia chuỗi sử dụng biểu thức chính quy đã cho và trả về một mảng chuỗi, nhưng số lượng phần tử của mảng bị giới hạn bởi giá trị giới hạn. Nếu giới hạn được chỉ định là 2, thì phương thức sẽ trả về một mảng có kích thước là 2.
package com.journaldev.examples;
/**
* Java String split example
*
* @author pankaj
*
*/
public class StringSplitExample {
public static void main(String[] args) {
String s = "a/b/c/d";
String[] a1 = s.split("/");
System.out.println("split string using only regex:");
for (String string : a1) {
System.out.println(string);
}
System.out.println("split string using regex with limit:");
String[] a2 = s.split("/", 2);
for (String string : a2) {
System.out.println(string);
}
}
}
Kết quả của chương trình trên là:
split string using only regex:
a
b
c
d
split string using regex with limit:
a
b/c/d
2. contains(CharSequence s)
Phương thức Java String contains()
kiểm tra xem chuỗi có chứa chuỗi ký tự được chỉ định hay không. Phương thức này trả về true
nếu chuỗi chứa chuỗi ký tự được chỉ định, ngược lại trả về false
.
package com.journaldev.examples;
/**
* Java String contains() Example
*
* @author pankaj
*
*/
public class StringContainsExample {
public static void main(String[] args) {
String s = "Hello World";
System.out.println(s.contains("W"));//true
System.out.println(s.contains("X"));//false
}
}
Kết quả của chương trình trên là:
true
false
3. length()
Phương thức Java String length()
trả về độ dài của chuỗi.
package com.journaldev.examples;
/**
* Java String length
*
* @author pankaj
*
*/
public class StringLengthExample {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abcdef";
String s3 = "abcdefghi";
System.out.println(s1.length());//3
System.out.println(s2.length());//6
System.out.println(s3.length());//9
}
}
4. replace()
Phương thức Java string replace()
được dùng để thay thế một phần cụ thể của chuỗi bằng một chuỗi khác. Có bốn biến thể của phương thức replace()
:
replace(char oldChar, char newChar)
: Phương thức này thay thế tất cả các lần xuất hiện củaoldChar
bằngnewChar
trong chuỗi.replace(CharSequence target, CharSequence replacement)
: Phương thức này thay thế mỗi literal (ký tự hoặc chuỗi ký tự)target
bằngreplacement
trong chuỗi.replaceAll(String regex, String replacement)
: Phương thức này thay thế tất cả các lần xuất hiện của chuỗi con phù hợp với biểu thức chính quy đã cho bằngreplacement
được chỉ định trong chuỗi.replaceFirst(String regex, String replacement)
: Phương thức này thay thế lần xuất hiện đầu tiên của chuỗi con phù hợp với biểu thức chính quy đã cho bằngreplacement
được chỉ định trong chuỗi.
Kết quả của chương trình trên là:
After Replacing l with m :
Hemmo Wormd
After Replacing :
Hi journaldev, Hi pankaj
After Replacing :
Hi guys, Hello world
5. format()
Phương thức Java String format()
được dùng để định dạng chuỗi. Có hai biến thể của phương thức Java String format()
:
format(Locale l, String format, Object… args)
: Phương thức này định dạng chuỗi sử dụng locale được chỉ định, định dạng chuỗi và các đối số.format(String format, Object… args)
: Phương thức này định dạng chuỗi sử dụng định dạng chuỗi và các đối số được chỉ định.
package com.journaldev.examples;
import java.util.Locale;
/**
* Java String format
*
* @author pankaj
*
*/
public class StringFormatExample {
public static void main(String[] args) {
String s = "journaldev.com";
// %s is used to append the string
System.out.println(String.format("This is %s", s));
//using locale as Locale.US
System.out.println(String.format(Locale.US, "%f", 3.14));
}
}
Kết quả của chương trình trên là:
This is journaldev.com
3.140000
substring()
Phương thức này trả về một phần của chuỗi dựa trên các chỉ số (indexes) được chỉ định.
package com.journaldev.examples;
/**
* Java String substring
*
*/
public class StringSubStringExample {
public static void main(String[] args) {
String s = "This is journaldev.com";
s = s.substring(8,18);
System.out.println(s);
}
}
Nối chuỗi (String Concatenation)
Nối chuỗi là một thao tác rất cơ bản trong Java. Chuỗi có thể được nối bằng cách sử dụng toán tử +
hoặc bằng phương thức concat()
.
package com.journaldev.examples;
/**
* Java String concatenation
*
* @author pankaj
*
*/
public class StringConcatExample {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "World";
String s3 = s1 + s2;
//using + operator
System.out.println("Using + operator: ");
System.out.println(s3);
//using concat method
System.out.println("Using concat method: ");
System.out.println(s1.concat(s2));
}
}
Kết quả của chương trình trên là:
Using + operator:
HelloWorld
Using concat method:
HelloWorld
Java String Pool
Quản lý bộ nhớ là khía cạnh quan trọng nhất của bất kỳ ngôn ngữ lập trình nào. Quản lý bộ nhớ đối với string trong Java có một chút khác biệt so với các lớp khác. Để làm cho Java hiệu quả bộ nhớ hơn, JVM đã giới thiệu một vùng bộ nhớ đặc biệt dành cho String được gọi là String Constant Pool (Vùng hằng chuỗi). Khi chúng ta tạo một chuỗi ký tự, JVM sẽ kiểm tra xem có chuỗi nào giống hệt đã tồn tại trong String pool hay không. Nếu có, nó sẽ trả về tham chiếu của chuỗi hiện có trong string pool. Hãy cùng xem xét chương trình ví dụ dưới đây.
package com.journaldev.examples;
/**
* Java String Pool Example
*
*/
public class StringPoolExample {
public static void main(String[] args) {
String a = "abc";
String b = "abc";
String c = "def";
//same reference
if (a==b) {
System.out.println("Both string refer to the same object");
}
//different reference
if (a==c) {
System.out.println("Both strings refer to the same object");
}else {
System.out.println("Both strings refer to the different object");
}
}
}
Kết quả của chương trình trên là:
Both string refer to the same object
Both strings refer to the different object
Phương thức String intern()
Khi chúng ta tạo một chuỗi bằng cách sử dụng chuỗi ký tự, nó sẽ được tạo trong string pool. Nhưng điều gì sẽ xảy ra nếu chúng ta tạo một chuỗi bằng từ khóa new
với cùng giá trị đã tồn tại trong string pool? Chúng ta có thể di chuyển chuỗi từ bộ nhớ heap sang string pool không?
Để làm điều này, phương thức intern()
được sử dụng và nó trả về một biểu diễn chuẩn của đối tượng chuỗi. Khi chúng ta gọi phương thức intern()
trên một đối tượng chuỗi được tạo bằng từ khóa new
, nó sẽ kiểm tra xem đã có một string có cùng giá trị trong pool chưa. Nếu có, thì nó sẽ trả về tham chiếu của đối tượng string đó từ pool. Nếu không, thì nó sẽ tạo một string mới với cùng nội dung trong pool và trả về tham chiếu đó.
package com.journaldev.examples;
/**
* Java String intern
*
* @author pankaj
*
*/
public class StringInternExample {
public static void main(String[] args) {
String s1 = "pankaj";
String s2 = "pankaj";
String s3 = new String("pankaj");
System.out.println(s1==s2);//true
System.out.println(s2==s3);//false
String s4 = s3.intern();
System.out.println(s1==s4);//true
}
}
Lợi ích của tính bất biến của String
Tính bất biến (immutability) của lớp string mang lại một số lợi ích quan trọng trong Java:
- String Constant Pool, nhờ đó giúp tiết kiệm bộ nhớ
- Bảo mật vì nó không thể bị thay đổi
- An toàn luồng (Thread safe)
- Bảo mật tải lớp
Java 8 String join()
Trong Java 8, một phương thức static mới là join()
đã được thêm vào lớp string. Phương thức này trả về một chuỗi mới được tạo thành từ các bản sao của các phần tử CharSequence được nối lại với nhau bằng một bản sao của ký tự phân cách (delimiter) đã chỉ định. Hãy xem một ví dụ để hiểu rõ hơn.
List<String> words = Arrays.asList(new String[]{"Hello", "World", "2019"});
String msg = String.join(" ", words); // Nối các chuỗi trong 'words' bằng dấu cách " "
System.out.println(msg);
Kết quả:
Hello World 2019
Phương thức String trong Java 9
Trong bản phát hành Java 9, hai phương thức mới đã được thêm vào lớp string: đó là codePoints()
và chars()
. Cả hai phương thức này đều trả về một đối tượng IntStream, trên đó chúng ta có thể thực hiện một số thao tác. Hãy cùng xem xét nhanh các phương thức này.
String s = "abc";
// Sử dụng codePoints()
s.codePoints().forEach(x -> System.out.println(x));
// Sử dụng chars()
s.chars().forEach(x -> System.out.println(x));
Kết quả:
97
98
99
97
98
99
Các phương thức mới của lớp String trong Java 11
Trong bản phát hành Java 11, nhiều phương thức mới đã được thêm vào lớp String:
isBlank()
: Trả vềtrue
nếu chuỗi rỗng hoặc chỉ chứa các điểm mã khoảng trắng, ngược lại trả vềfalse
.lines()
: Trả về một luồng các dòng được trích xuất từ chuỗi này, phân tách bởi các ký tự kết thúc dòng.strip()
,stripLeading()
,stripTrailing()
: Để loại bỏ các khoảng trắng ở đầu và cuối chuỗi.repeat()
: Trả về một chuỗi mà giá trị của nó là sự nối của chuỗi hiện tại được lặp lại số lần đã cho.
Hãy cùng xem một chương trình ví dụ cho các phương thức này:
package com.journaldev.strings;
import java.util.List;
import java.util.stream.Collectors;
/**
* JDK 11 New Functions in String class
*
* @author pankaj
*
*/
public class JDK11StringFunctions {
public static void main(String[] args) {
// isBlank()
String s = "abc";
System.out.println(s.isBlank());
s = "";
System.out.println(s.isBlank());
// lines()
String s1 = "Hi\\nHello\\rHowdy";
System.out.println(s1);
List lines = s1.lines().collect(Collectors.toList());
System.out.println(lines);
// strip(), stripLeading(), stripTrailing()
String s2 = " Java, \\tPython\\t ";
System.out.println("#" + s2 + "#");
System.out.println("#" + s2.strip() + "#");
System.out.println("#" + s2.stripLeading() + "#");
System.out.println("#" + s2.stripTrailing() + "#");
// repeat()
String s3 = "Hello\\n";
System.out.println(s3.repeat(3));
s3 = "Co";
System.out.println(s3.repeat(2));
}
}
Kết quả của chương trình trên là:
false
true
Hi
Hello
Howdy
[Hi, Hello, Howdy]
# Java, Python #
#Java, Python#
#Java, Python #
# Java, Python#
Hello
Hello
Hello
CoCo
Trên đây là tất cả về lớp Java string, các phương thức của nó và các ví dụ về thao tác chuỗi.