跳轉到內容

字串

100% developed
來自華夏公益教科書,開放的書籍,面向開放的世界

方法 Java 程式設計
字串
類,物件和型別
瀏覽 語言基礎 主題:v  d  e )


String 是 Java 語言中內建的類,定義在 java.lang 包中。它代表字元字串。字串在 Java 中無處不在。仔細研究 String 類及其方法。熟練地掌握如何操作它們將對你大有裨益。Java 程式中的 字串字面量,如“abc”,是作為此類例項實現的,如下所示

Example 程式碼段 3.81:字串示例。
String str = "This is string literal";

在右側,建立了一個由字串字面量表示的 String 物件。它的物件引用被分配給 str 變數。

不可變性

[編輯 | 編輯原始碼]

字串是 不可變 的;也就是說,一旦建立它們就不能修改。無論何時看起來像是修改了 String 物件,實際上都會建立一個新的 String 物件。例如,String.trim() 方法返回刪除了前導和尾隨空格的字串。實際上,它會建立一個新的修剪後的字串,然後返回它。請注意 程式碼段 3.82 中發生了什麼

Example 程式碼段 3.82:不可變性。
String badlyCutText = "     Java is great.     ";
System.out.println(badlyCutText);

badlyCutText.trim();
System.out.println(badlyCutText);
Standard input or output 程式碼段 3.82 的輸出
     Java is great.    
     Java is great.    

trim() 方法呼叫不會修改物件,因此不會發生任何事情。它會建立一個新的修剪後的字串,然後丟棄它。

Example 程式碼段 3.83:賦值。
String badlyCutText = "     Java is great.     ";
System.out.println(badlyCutText);

badlyCutText = badlyCutText.trim();
System.out.println(badlyCutText);
Standard input or output 程式碼段 3.83 的輸出
     Java is great.    
Java is great.

返回的字串被分配給變數。它完成了任務,因為 trim() 方法建立了一個新的 String 例項。

Java 語言為使用運算子 + 連線字串提供特殊支援

Example 程式碼段 3.84:連線示例。
System.out.println("First part");
System.out.println(" second part");
String str = "First part" + " second part";
System.out.println(str);
Standard input or output 程式碼段 3.84 的輸出
First part
 second part
First part second part

連線並不總是同時進行。 原始字串字面量 連線在編譯時完成,因此類位元組碼中只有一個字串字面量。包含至少一個物件的連線在執行時完成。

+ 運算子可以將其他物件與字串連線起來。例如,整數將在連線之前轉換為字串

Example 程式碼段 3.85:整數連線。
System.out.println("Age=" + 25);
Standard input or output 程式碼段 3.85 的輸出
Age=25

每個 Java 物件都有從 Object 類繼承的 String toString() 方法。此方法提供了一種將物件轉換為 String 的方法。大多數類會覆蓋預設行為,以在返回的 String 中提供更具體的(更有用的)資料

Example 程式碼段 3.86:物件連線。
System.out.println("Age=" + new Integer(31));
Standard input or output 程式碼段 3.86 的輸出
Age=31

使用 StringBuilder/StringBuffer 連線字串

[編輯 | 編輯原始碼]

請記住,String 物件是不可變物件。一旦建立了 String,就不能修改它,它會佔用記憶體,直到被垃圾回收。小心編寫這樣的方法

Example 程式碼段 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

  1. ""
  2. "Foo"
  3. " "
  4. "Foo "
  5. "Foo Bar"
  6. " "
  7. "Foo Bar "
  8. "Foo Bar Bam"
  9. " "
  10. "Foo Bar Bam "
  11. "Foo Bar Bam Baz"
  12. " "
  13. "Foo Bar Bam Baz "

即使實際上只有最後一個才是有用的。

為了避免像這樣不必要的記憶體使用,請使用 StringBuilder 類。它提供與 String 相似的功能,但以可變的方式儲存其資料。只建立一個 StringBuilder 物件。同樣,由於物件建立很耗時,使用 StringBuilder 會生成速度更快的程式碼。

Example 程式碼段 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 時,請注意你在做什麼

Example 程式碼段 3.89:危險的比較。
String greeting = "Hello World!";
if (greeting == "Hello World!") {
    System.out.println("Match found.");
}
Standard input or output 程式碼段 3.89 的輸出
Match found.

上面和下面程式碼的區別在於,上面程式碼檢查 String 是否是記憶體中的相同物件,它們是。這是由於 String 儲存在稱為字串常量池的記憶體位置中的緣故。如果建立 String 時沒有顯式使用 new 關鍵字,它會檢查該 String 是否已存在於池中,並使用現有的 String。如果不存在,則會建立一個新物件。這就是 Java 中使字串不可變的原因。要測試相等性,請使用 equals(Object) 方法,該方法由每個類繼承並由 String 定義,如果且僅當傳入的物件是 String 並且包含完全相同的資料時,才返回 true

Example 程式碼段 3.90:正確的比較。
String greeting = "Hello World!";
if (greeting.equals("Hello World!")) {
    System.out.println("Match found.");
}
Standard input or output 程式碼段 3.90 的輸出
Match found.

請記住,比較區分大小寫。

Example 程式碼段 3.91:使用小寫進行比較。
String greeting = "Hello World!";
if (greeting.equals("hello world!")) {
    System.out.println("Match found.");
}
Standard input or output 程式碼段 3.91 的輸出

要對 String 物件進行排序,請使用 compareTo() 方法,該方法可以在使用 String 資料型別的地方訪問。compareTo() 方法如果引數小於、等於或大於呼叫它的物件,則返回負數、零或正數。讓我們來看一個示例

Example 程式碼段 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 變數 person1person2 進行比較。如果 person1 即使是最細微的差別,我們也會得到一個大於或小於 0 的值,具體取決於確切的差異。如果此 String 物件在字典順序上先於引數字串,則結果為負。如果此 String 物件在字典順序上後於引數字串,則結果為正。檢視 Java API 以瞭解更多詳細資訊。

拆分字串

[編輯 | 編輯原始碼]

有時將字串拆分為單獨的字串(基於 正則表示式)很有用。String 類有一個 split() 方法(從 Java 1.4 開始),它將返回一個 String 陣列

Example 程式碼段 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];

另一個有用的應用程式可能是根據換行符來 拆分 字串文字,以便你可以逐行處理文字。

子字串

[編輯 | 編輯原始碼]

有時建立 子字串(或使用現有字串中字母順序的字串)也很有用。這可以透過兩種方法完成。

第一種方法涉及從給定索引到末尾的字串中建立子字串

Example 程式碼段 3.94:截斷字串。
String str = "coffee";
System.out.println(str.substring(3));
Standard input or output 程式碼段 3.94 的輸出
fee

字串中第一個字元的索引為 0。

c o f f e e
0 1 2 3 4 5

從那裡開始計數,很明顯索引為 3 的字元是 "coffee" 中的第二個 "f"。這被稱為beginIndex。從beginIndex到字串結尾的所有字元都將複製到新的子字串中。

第二種方法涉及使用者定義的beginIndexendIndex

Example 程式碼部分 3.95:字串提取。
String str = "supporting";
System.out.println(str.substring(3, 7));
Standard input or output 程式碼部分 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(包括)的所有字元都被複制到子字串中。

Note 很容易將substring()方法誤認為subString()(它不存在,編譯時會返回語法錯誤)。子字串被認為是一個詞。這就是為什麼方法名稱似乎不遵循 Java 的常用語法。只要記住,這種風格只適用於由多個單片語成的的方法或其他元素。

字串大小寫

[編輯 | 編輯原始碼]

String類還允許修改大小寫。實現此功能的兩種方法是toLowerCase()toUpperCase()

Example 程式碼部分 3.96:大小寫修改。
String str = "wIkIbOoKs";
System.out.println(str.toLowerCase());
System.out.println(str.toUpperCase());
Standard input or output 程式碼部分 3.96 的輸出
wikibooks
WIKIBOOKS

這些方法對於進行不區分大小寫的搜尋非常有用。

Example 程式碼部分 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);
}
Standard input or output 程式碼部分 3.97 的輸出
Integer appears at column 38.
Integer appears at column 47.
測試您的知識

問題 3.12:您有以下形式的郵件地址:<firstName>.<lastName>@<companyName>.org

編寫String getDisplayName(String)方法,該方法接收郵件字串作為引數,並返回可讀的姓名,如下所示:LASTNAME Firstname

答案
Example 答案 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;
}
  1. 我們只處理非空字串,
  2. 我們首先將郵件分成兩部分,將個人資訊與公司資訊分開,並保留姓名資料,
  3. 然後我們將姓名資訊拆分以將名字與姓氏分開。由於split()方法使用正則表示式,而.是一個萬用字元,因此我們需要對其進行轉義(\.)。但是,在字串中,\也是一個特殊字元,因此我們也需要對其進行轉義(\\.),
  4. 姓氏只是大寫,
  5. 由於所有名字字元的大小寫可能不一致,因此我們必須擷取名字。只有名字的首字母將大寫,
  6. 現在我們可以連線所有片段。我們更喜歡使用StringBuilder來做到這一點。

另請參見

[編輯 | 編輯原始碼]
方法 Java 程式設計
字串
類,物件和型別
華夏公益教科書