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
|
|
使用 StringBuilder/StringBuffer 連線字串
[編輯 | 編輯原始碼]
請記住,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 時沒有顯式使用 new 關鍵字,它會檢查該 String 是否已存在於池中,並使用現有的 String。如果不存在,則會建立一個新物件。這就是 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];
|
另一個有用的應用程式可能是根據換行符來 拆分 字串文字,以便你可以逐行處理文字。
有時建立 子字串(或使用現有字串中字母順序的字串)也很有用。這可以透過兩種方法完成。
第一種方法涉及從給定索引到末尾的字串中建立子字串
|
程式碼段 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來做到這一點。