將字串拆分為列表

為了分割字串,Guava 引入了 Splitter 類。

為什麼不使用 Java 的分裂功能?

通常,Guava 不會複製 Java 中可用的功能。為什麼我們需要額外的 Splitter 類?Java 的 String 類中的拆分方法不能為我們提供我們需要的所有字串拆分機制嗎?

回答這個問題的最簡單方法是舉幾個例子。首先,我們將處理以下槍支組合:

String gunslingers = "Wyatt Earp+Doc Holliday";

為了嘗試分裂這位傳奇的律師和他的牙醫朋友,我們可能會嘗試以下方法:

String[] result = gunslingers.split("+"); // wrong

但是,在執行時,我們遇到以下異常:

Exception in thread "main" java.util.regex.PatternSyntaxException:
Dangling meta character '+' near index 0

在一個非自願的 facepalm 之後,我們很快就會記住 String 的 split 方法將正規表示式作為引數,並且+字元用作正規表示式中的量詞。然後解決方案是轉義+字元,或將其包含在字元類中。

String[] result = gunslingers.split("\\+");
String[] result = gunslingers.split("[+]");

在成功解決了這個問題之後,我們轉向了三個火槍手。

String musketeers = ",Porthos , Athos ,Aramis,";

逗號在正規表示式中沒有特殊含義,所以讓我們通過應用 String.split() 方法並獲得結果陣列的長度來計算火槍手。

System.out.println(musketeers.split(",").length);

這會在控制檯中產生以下結果:

4

四?鑑於字串包含一個前導和一個尾隨逗號,五個結果將屬於正常期望範圍,但是四個?事實證明,Java 的 split 方法的行為是保留前導,但是丟棄尾隨的空字串,所以陣列的實際內容是 ["", "Porthos ", " Athos ", "Aramis"]

因為我們不需要任何空字串,前導或尾隨,所以讓我們用迴圈過濾它們:

for (String musketeer : musketeers.split(",")) {
    if (!musketeer.isEmpty()) {
        System.out.println(musketeer);
    }
}

這給了我們以下輸出:

Porthos 
 Athos
Aramis

正如你在上面的輸出中所看到的,逗號分隔符之前和之後的額外空格已保留在輸出中。為了解決這個問題,我們可以刪除不需要的空格,最終會產生所需的輸出:

for (String musketeer : musketeers.split(",")) {
    if(!musketeer.isEmpty()) {
        System.out.println(musketeer.trim());
    }
}

(或者,我們也可以調整正規表示式以包含逗號分隔符周圍的空格。但是,請記住,在第一個條目之前的前導空格或最後一個條目之後的尾隨空格仍然會被保留。)

通過閱讀上面的例子,我們不得不得出結論,用 Java 分割字串充其量是令人討厭的。

與番石榴分裂的字串

演示 Guava 如何將絃樂分成相對無痛的體驗的最好方法是再次對待相同的兩個絃樂,但這次使用的是 Guava 的 Splitter 類。

List<String> gunslingers = Splitter.on('+')
        .splitToList("Wyatt Earp+Doc Holliday");
List<String> musketeers = Splitter.on(",")
        .omitEmptyStrings()
        .trimResults()
        .splitToList(",Porthos , Athos ,Aramis,");

正如你在上面的程式碼中看到的,Splitter 公開了一個流暢的 API,並允許你通過一系列靜態工廠方法建立例項:

  • static Splitter on(char separator)
    允許你將分隔符指定為字元。

  • static Splitter on(String separator)
    允許你將分隔符指定為字串。

  • static Splitter on(CharMatcher separatorMatcher)
    允許你將分隔符指定為 Guava CharMatcher

  • static Splitter on(Pattern separatorPattern)
    允許你將分隔符指定為 Java 正規表示式 Pattern

  • static Splitter onPattern(String separatorPattern)
    允許你將分隔符指定為正規表示式字串。

除了這些基於分隔符的工廠方法之外,還有一個 static Splitter fixedLength(int length) 方法來建立 Splitter 例項,該例項將字串拆分為指定長度的塊。

建立 Splitter 例項後,可以應用許多修飾符:

  • Splitter omitEmptyStrings()
    指示 Splitter 從結果中排除空字串。

  • Splitter trimResults()
    指示 Splitter 使用預定義的空格 CharMatcher 修剪結果。

  • Splitter trimResults(CharMatcher trimmer)
    指示 Splitter 使用指定的 CharMatcher 修剪結果。

在建立(並且可選地修改)Splitter 之後,可以通過呼叫其 split 方法在字元序列上呼叫它,該方法將返回 Iterable<String> 型別的物件或其 splitToList 方法,該方法將返回 List<String> 型別的(不可變)物件。

你可能想知道在哪種情況下使用 split 方法(返回 Iterable)而不是 splitToList 方法(返回更常用的 List 型別)將是有益的。簡單的答案是:你可能只想使用 split 方法處理非常大的字串。稍微長一點的答案是因為 split 方法返回 Iterable,可以懶惰地評估拆分操作(在迭代時),從而無需將拆分操作的整個結果保留在記憶體中。