String 是 Java 語言內建的一個類,定義在 java.lang 包中。它表示字元字串。字串在 Java 中無處不在。仔細研究 String 類及其方法。熟練地掌握如何操作它們對你非常有益。 Java 程式中的 字串字面量,如“abc”,使用此類的例項實現,如下所示
|
程式碼部分 3.81:字串示例。
String str = "This is string literal";
|
在右側,建立了一個由字串字面量表示的 String 物件。它的物件引用被分配給 str 變數。
字串是不可變的;也就是說,一旦建立,它們就不能被修改。每當看起來 String 物件被修改時,實際上都會建立一個新的 String 物件。例如,String.trim() 方法返回刪除了前導和尾隨空格的字串。實際上,它建立了一個新的修剪後的字串,然後將其返回。注意 程式碼部分 3.82 中發生了什麼
|
程式碼部分 3.82:不可變性。
String badlyCutText = " Java is great. ";
System.out.println(badlyCutText);
badlyCutText.trim();
System.out.println(badlyCutText);
|
|
|
程式碼部分 3.82 的輸出
Java is great.
Java is great.
|
|
trim() 方法呼叫不會修改物件,因此不會發生任何事情。它建立了一個新的修剪後的字串,然後將其丟棄。
|
程式碼部分 3.83:賦值。
String badlyCutText = " Java is great. ";
System.out.println(badlyCutText);
badlyCutText = badlyCutText.trim();
System.out.println(badlyCutText);
|
|
|
程式碼部分 3.83 的輸出
Java is great.
Java is great.
|
|
返回的字串被分配給變數。它完成了任務,因為 trim() 方法建立了一個新的 String 例項。
Java 語言為字串串聯提供了使用運算子 + 的特殊支援
|
程式碼部分 3.84:串聯示例。
System.out.println("First part");
System.out.println(" second part");
String str = "First part" + " second part";
System.out.println(str);
|
|
|
程式碼部分 3.84 的輸出
First part
second part
First part second part
|
|
串聯並不總是同時處理的。 原始字串字面量 串聯在編譯時完成,因此類位元組碼中只有一個字串字面量。至少包含一個物件的串聯在執行時完成。
+ 運算子可以將其他物件與字串串聯起來。例如,整數將在串聯之前轉換為字串
|
程式碼部分 3.85:整數串聯。
System.out.println("Age=" + 25);
|
|
|
程式碼部分 3.85 的輸出
Age=25
|
|
每個 Java 物件都有從 Object 類繼承的 String toString()。此方法提供了一種將物件轉換為 String 的方法。大多數類覆蓋預設行為以在返回的 String 中提供更具體的(更有用)的資料
|
程式碼部分 3.86:物件串聯。
System.out.println("Age=" + new Integer(31));
|
|
|
程式碼部分 3.86 的輸出
Age=31
|
|
請記住,String 物件是不可變物件。一旦建立了 String,它就無法修改,直到被垃圾回收之前它會佔用記憶體。小心編寫這樣的方法
|
程式碼部分 3.87:原始串聯。
public String convertToString(Collection<String> words) {
String str = "";
// Loops through every element in words collection
for (String word : words) {
str = str + word + " ";
}
return str;
}
|
在 + 操作中,每次迭代都會建立一個新的 String 物件。假設 words 包含元素 ["Foo", "Bar", "Bam", "Baz"]。在執行時,該方法會建立 13 個 String
""
"Foo"
" "
"Foo "
"Foo Bar"
" "
"Foo Bar "
"Foo Bar Bam"
" "
"Foo Bar Bam "
"Foo Bar Bam Baz"
" "
"Foo Bar Bam Baz "
即使實際上只有最後一個是有用的。
為了避免這種不必要的記憶體使用,請使用 StringBuilder 類。它提供了與 String 相似的功能,但以可變的方式儲存其資料。只建立了一個 StringBuilder 物件。此外,由於物件建立非常耗時,使用 StringBuilder 會產生快得多的程式碼。
|
程式碼部分 3.88:使用 StringBuilder 進行串聯。
public String convertToString(Collection<String> words) {
StringBuilder buf = new StringBuilder();
// Loops through every element in words collection
for (String word : words) {
buf.append(word);
buf.append(" ");
}
return buf.toString();
}
|
由於 StringBuilder 不是執行緒安全的(參見有關 併發 的章節),因此不能在多個執行緒中使用它。對於多執行緒環境,請改用 StringBuffer,它執行相同的操作並且是執行緒安全的。但是,StringBuffer 速度較慢,因此只在需要時使用它。此外,在 Java 5 之前,只有 StringBuffer 存在。
比較字串並不像乍看起來那樣容易。在使用 == 比較 String 時,請注意您在做什麼
|
程式碼部分 3.89:危險的比較。
String greeting = "Hello World!";
if (greeting == "Hello World!") {
System.out.println("Match found.");
}
|
|
|
程式碼部分 3.89 的輸出
Match found.
|
|
上面和下面程式碼之間的區別在於,上面程式碼檢查 String 是否是記憶體中的相同物件,它們是。這是因為 String 儲存在記憶體中的一個名為 String 常量池的地方。如果在建立 String 時沒有顯式使用 new 關鍵字,它會檢查它是否已存在於池中,並使用現有的那個。如果不存在,則會建立一個新的物件。這就是允許字串在 Java 中不可變的原因。要測試相等性,請使用每個類繼承的 equals(Object) 方法,該方法由 String 定義,如果傳入的物件是 String 幷包含完全相同的資料,則返回 true
|
程式碼部分 3.90:正確的比較。
String greeting = "Hello World!";
if (greeting.equals("Hello World!")) {
System.out.println("Match found.");
}
|
|
|
程式碼部分 3.90 的輸出
Match found.
|
|
請記住,比較區分大小寫。
|
程式碼部分 3.91:使用小寫進行比較。
String greeting = "Hello World!";
if (greeting.equals("hello world!")) {
System.out.println("Match found.");
}
|
|
|
程式碼部分 3.91 的輸出
|
|
要對 String 物件進行排序,請使用compareTo() 方法,可以在使用 String 資料型別的地方訪問該方法。如果引數小於、等於或大於呼叫它的物件,則 compareTo() 方法返回一個負數、零或正數。讓我們看一個例子
|
程式碼部分 3.92:順序。
String person1 = "Peter";
String person2 = "John";
if (person1.compareTo(person2) > 0) {
// Badly ordered
String temp = person1;
person1 = person2;
person2 = temp;
}
|
程式碼部分 3.92 正在將 String 變數 person1 與 person2 進行比較。如果 person1 即使在最細微的程度上有所不同,我們也會根據確切的差異獲得大於或小於 0 的值。如果此 String 物件在字典順序上先於引數字串,則結果為負數。如果此 String 物件在字典順序上後於引數字串,則結果為正數。請檢視 Java API 獲取更多詳細資訊。
有時,根據正則表示式 將字串拆分為單獨的字串很有用。String 類有一個split() 方法(從 Java 1.4 開始),它將返回一個 String 陣列
|
程式碼部分 3.93:順序。
String person = "Brown, John:100 Yonge Street, Toronto:(416)777-9999";
...
String[] personData = person.split(":");
...
String name = personData[0];
String address = personData[1];
String phone = personData[2];
|
另一個有用的應用可能是根據換行符拆分 String 文字,以便您可以逐行處理文字。
有時,使用現有字串中的字母順序建立子字串或字串也可能很有用。這可以透過兩種方法完成。
第一種方法涉及從給定索引到結尾從字串的字元中建立一個子字串
|
程式碼部分 3.94:截斷字串。
String str = "coffee";
System.out.println(str.substring(3));
|
|
|
程式碼部分 3.94 的輸出
fee
|
|
字串中第一個字元的索引為 0。
從那裡開始計數,很明顯,索引 3 中的字元是“coffee”中的第二個“f”。這被稱為 beginIndex。從 beginIndex 到字串結尾的所有字元都將複製到新的子字串中。
第二種方法涉及使用者定義的 beginIndex 和 endIndex
|
程式碼部分 3.95:字串提取。
String str = "supporting";
System.out.println(str.substring(3, 7));
|
|
|
程式碼部分 3.95 的輸出
port
|
|
substring() 返回的字串將是“port”。
s
|
u
|
p
|
p
|
o
|
r
|
t
|
i
|
n
|
g
|
| 0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
8
|
9
|
請注意,endIndex 不是包含的。這意味著最後一個字元的索引將是 endIndex-1。因此,在本例中,從索引 3 到索引 6(包括)的每個字元都被複制到子字串中。
|
很容易將 substring() 方法誤認為 subString()(它不存在,並且會在編譯時返回語法錯誤)。子字串被認為是一個詞。這就是為什麼方法名稱似乎沒有遵循 Java 的通用語法。只需記住,這種風格僅適用於由多個單片語成的函式或其他元素。 |
String 類還允許修改大小寫。使這成為可能的兩種方法是 toLowerCase() 和 toUpperCase()。
|
程式碼部分 3.96:大小寫修改。
String str = "wIkIbOoKs";
System.out.println(str.toLowerCase());
System.out.println(str.toUpperCase());
|
|
|
程式碼部分 3.96 的輸出
wikibooks
WIKIBOOKS
|
|
這些方法對於進行不區分大小寫的搜尋很有用
|
程式碼部分 3.97:文字搜尋。
String word = "Integer";
String text = "A number without a decimal part is an integer."
+ " Integers are a list of digits.";
...
// Remove the case
String lowerCaseWord = word.toLowerCase();
String lowerCaseText = text.toLowerCase();
// Search
int index = lowerCaseText.indexOf(lowerCaseWord);
while (index != -1) {
System.out.println(word
+ " appears at column "
+ (index + 1)
+ ".");
index = lowerCaseText.indexOf(lowerCaseWord, index + 1);
}
|
|
程式碼部分 3.97 的輸出
Integer appears at column 38.
Integer appears at column 47.
|
測試您的知識
問題 3.12:您的郵件地址採用以下格式:<firstName>.<lastName>@<companyName>.org
編寫 String getDisplayName(String) 方法,該方法接收郵件字串作為引數並返回可讀的人員姓名,如下所示:LASTNAME Firstname
答案
|
答案 3.12:getDisplayName()
public static String getDisplayName(String mail) {
String displayName = null;
if (mail != null) {
String[] mailParts = mail.split("@");
String namePart = mailParts[0];
String[] namesParts = namePart.split("\\.");
// The last name
String lastName = namesParts[1];
lastName = lastName.toUpperCase();
// The first name
String firstName = namesParts[0];
String firstNameInitial = firstName.substring(0, 1);
firstNameInitial = firstNameInitial.toUpperCase();
String firstNameEnd = firstName.substring(1);
firstNameEnd = firstNameEnd.toLowerCase();
// Concatenation
StringBuilder displayNameBuilder = new StringBuilder(lastName).append(" ").append(firstNameInitial).append(firstNameEnd);
displayName = displayNameBuilder.toString();
}
return displayName;
}
|
- 我們只處理非空字串。
- 我們首先將郵件拆分為兩個部分,以將個人資訊與公司資訊分開,並保留姓名資料。
- 然後我們拆分姓名資訊以將姓氏與名字分開。由於
split() 方法使用正則表示式,而 . 是萬用字元,因此我們需要對其進行轉義 (\.)。但是,在字串中,\ 也是一個特殊字元,因此我們也需要對其進行轉義 (\\.)。
- 姓氏只是大寫。
- 由於所有姓名的第一個字元都不相同,因此我們必須截斷名字。只有首字母大寫。
- 現在我們可以將所有片段拼接起來。我們更喜歡使用
StringBuilder來完成這個操作。