前言java
Java 裏字符串表示字符的不可變序列,建立後就不能更改。在咱們平常的工做中,字符串的使用很是頻繁,熟練的對其操做能夠極大的提高咱們的工做效率,今天要介紹的主角是 Google 開源的一個核心 Java 庫 — Guava,它提供了集合類型、不可變的集合、併發、I / O、緩存、字符串等許多實用功能。在本文中,咱們將學習使用 Guava 中的 Strings 和 Splitter 字符串操做工具類。正則表達式
如何使用緩存
Google Guava 會同步到 Maven Central 中,因此,若是你是 Maven 項目的話只須要在 pom.xml 文件中引入以下依賴便可: <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>28.2-jre</version> </dependency>
對於 Gradle 項目在 build.gradle 中引入以下依賴便可:併發
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
PS:28.2-jre 是編寫本文時的最新版本,你能夠從 Maven Central 中查看當前的最新版本。ide
爲何須要引入類庫工具
Google Guava 提供了不少實用的靜態方法,這些能夠解決開發人員在開發中所要完成的一些重複任務。固然,這個工做咱們也能夠本身作,可是引入類庫它會下降錯誤發生的可能性,畢竟這些類庫都是已經通過多年的生產驗證。好比類庫中 Strings 提供的一個方法 commonPrefix,它接受兩個字符串並返回兩個字符串之間的公共前綴(eg: abcd 和 abef 返回 ab)。你能夠在腦子裏想象一下在應用程序代碼中面臨這樣的要求時,本身要如何編寫代碼來完成該操做,要本身實現這個功能,仍是須要花費一些時間的,同時還須要考慮到各類邊界異常狀況。這就是類庫提供給咱們的最大價值之一,因此當咱們須要的某種功能能夠做爲一種工具方法使用時,首先應該去尋找一些已存在的類庫並去熟練使用的它們,而不是本身去實現。總結起來使用類庫有以下幾個緣由:學習
Google Guava 類庫有人已經對其進行了完全的測試,bug 出現的機率會比咱們本身實現的小不少。測試
做爲 Google Guava 的一部分,已經存在各類測試用例,用於測試實用程序的實現。若是咱們本身編寫代碼實現的話,可能還要去編寫和維護它們的測試。gradle
Stringsui
Google Guava 有許多實用的工具類和方法,不可能在一篇文章中都有介紹完,在本文中,只會介紹和字符串操做相關的兩個工具類。首先第一個是 Strings 類,該類提供了操做 String 和 CharSequence 的實用方法。
nullToEmpty、emptyToNull 和 isNullOrEmpty
nullToEmpty 方法功能爲:若是傳入的字符串爲 null,則返回一個空字符串 "",不然,返回一個空字符串,不然按原樣返回傳遞的字符串。
@Test public void testStringsOfNullToEmpty() { System.out.println(Strings.nullToEmpty("mghio")); // mghio System.out.println(Strings.nullToEmpty("")); // "" System.out.println(Strings.nullToEmpty(null)); // "" System.out.println(Strings.nullToEmpty(null).isEmpty()); // true }
emptyToNull 方法功能爲:它與 nullToEmpty 相反,若是傳入了空字符串,則返回 null,不然返回原始字符串。
@Test public void testStringsOfEmptyToNull() { System.out.println(Strings.emptyToNull("mghio")); // mghio System.out.println(Strings.emptyToNull(null)); // null System.out.println(Strings.emptyToNull("")); // null }
isNullOrEmpty 方法功能爲:若是傳入的字符串爲 null 或爲空,則返回 true,不然返回 false。
@Test public void testStringsOfIsNullOrEmpty() { System.out.println(Strings.isNullOrEmpty("mghio")); // false System.out.println(Strings.isNullOrEmpty("")); // true System.out.println(Strings.isNullOrEmpty(null)); // true }
padStart 和 padEnd
這兩個方法有三個參數,分別爲:輸入字符串、最小長度和要填充的字符,它將字符根據須要屢次插入到輸入字符串的開頭,以使輸入字符串的長度等於傳入的最小長度。
@Test public void testStringsOfPadStart() { System.out.println(Strings.padStart("9527", 6, '0')); // 009527 System.out.println(Strings.padStart("123456", 6, '0')); // 123456 }
在第一行代碼中,將兩次填充 0 以使最終的字符串長度等於咱們傳入的最小長度(6)。在第二行代碼中,輸入字符串長度自己具備所需的最小長度,所以未進行填充 padEnd 方法和上面這個方法相似,只不過它是在字符的末尾而不是在開始處進行填充。
@Test public void testStringsOfPadEnd() { System.out.println(Strings.padEnd("9527", 6, '0')); // 952700 System.out.println(Strings.padEnd("123456", 6, '0')); // 123456 }
repeat
該方法須要傳入一個字符串和一個重複次數 count,它返回一個由原始字符串組成的字符串,該字符串重複了 count 次。
@Test public void testStringsRepeat() { System.out.println(Strings.repeat("mghio", 3)); // mghiomghiomghio }
commonPrefix 和 commonSuffix
commonPrefix 方法返回傳入的兩個字符串之間最大的公共前綴,而 commonSuffix 方法返回傳入兩個字符串之間最大的公共後綴。
@Test public void testStrings() { System.out.println(Strings.commonPrefix("mghio9527", "mghio666")); // mghio System.out.println(Strings.commonSuffix("iammghio", "nicemghio")); // mghio }
Splitter
Splitter 類提供的功能正如其名(題外話:一個好的命名很重要啊),它用於根據提供的分割符將字符串拆分爲多個子字符串。咱們能夠經過傳入一個分割符來獲一個 Splitter 的實例,有了分割器以後,咱們能夠根據分割器的配置方式對字符串進行分割。
@Test public void testSplitterOfSplit() { Iterable<String> result = Splitter.on(",").split("m,g,h,i,o"); System.out.println(result); // [m, g, h, i, o] }
上面的例子中使用逗號進行分割,所以,它將傳入的字符串 m,g,h,i,o 拆分爲一個 Iterable,而後當咱們對其進行迭代遍歷時會輸出 [m, g, h, i, o]。
獲取 Splitter 實例
on 和 onPattern
如今,咱們來看看得到一個分割器 Splitter 的各類方法。on 方法有各類不一樣的重載版本,它們以字符、字符串或正則表達式做爲分隔符,咱們還能夠將 Pattern 實例做爲字符串傳遞給 onPattern 方法中。
@Test public void testSplitterOfOn() { Splitter wordSplitter = Splitter.on(":;"); // 下面這行輸出結果 [the, text, is, separated, by, colon, semicolon] System.out.println(wordSplitter.split("the:;text:;is:;separated:;by:;colon:;semicolon")); Splitter patternBasedSplitter = Splitter.on(Pattern.compile("\\s+")); System.out.println(patternBasedSplitter.split("abc dmg hio")); // [abc, dmg, hio] System.out.println(Splitter.onPattern("\\s+").split("www mghio cn")); // [www, mghio, cn] }
fixedLength
fixedLength 也是最有用的方法之一,它能夠將字符串分紅給定長度的相等部分,須要注意的是,最後一個部分可能會小於給定的長度。
@Test public void testSplitterOfFixedLength() { Splitter fixedLengthSplitter = Splitter.fixedLength(3); System.out.println(fixedLengthSplitter.split("iammghiojava")); // [iam, mgh, ioj, ava] System.out.println(fixedLengthSplitter.split("https://www.mghio.cn")); // [htt, ps:, //w, ww., mgh, io., cn] }
Splitter 修飾符方法
Splitter 還提供了能夠在更改或修改 Splitter 行爲的經常使用方法。
trimResults
這個方法能夠從生成的分割器的結果字符串中刪除前面和末尾的空格。
@Test public void testSplitterOfTrimResult() { Splitter commaSplitter = Splitter.on(","); System.out.println(commaSplitter.split("m, g, h, i, o")); // [m, g, h, i, o] Splitter commaSplitterWithTrim = commaSplitter.trimResults(); System.out.println(commaSplitterWithTrim.split("m, g, h, i, o")); // [m, g, h, i, o] }
注意,第一個分割的結果在字符串 g、 h、i、o 以前有一個空格,使用 trimResults 方法後,將去除這些前導空格
omitEmptyStrings
這個方法會從結果中忽略全部空字符串。
@Test public void testSplitterOfOmitEmptyStrings() { Splitter commaSplitter = Splitter.on(","); System.out.println(commaSplitter.split("m,,g,h,i,o")); // [m, , g, h, i, o] Splitter commaSplitterWithNoEmptyString = commaSplitter.omitEmptyStrings(); System.out.println(commaSplitterWithNoEmptyString.split("m,,g,h,i,o")); // [m, g, h, i, o] }
上面的 commaSplitterWithNoEmptyString 會從輸出中刪除空字符串的結果。
limit
這個方法返回與原始分割器等效的分割器,但它會在達到指定的輸入限制後將中止拆分,將後續剩餘結果字符串做爲一項輸出,也就是說,咱們能夠經過的傳入的參數指定結果中存在的最大項目數。須要注意的是:該方法在省略空字符串時,省略的字符串不計算在內。。
@Test public void testSplitterOfLimit() { Splitter commaSplitter = Splitter.on(","); Splitter limitingCommaSplitter = commaSplitter.limit(3); System.out.println(limitingCommaSplitter.split("i,m,g,h,i,o")); // [i, m, g,h,i,o] }
有一點須要注意,Splitter 是不可變的(這一點和 String 相似),所以,調用它的任何修飾符方法都將返回新的 Splitter,而且不會修改原始的 Splitter。
@Test public void testSplitterImmutable() { Splitter splitter = Splitter.on('/'); System.out.println("Before: " + splitter); // Before: com.google.common.base.Splitter@33b37288 splitter.trimResults(); // do nothing System.out.println("First: " + splitter); // First: com.google.common.base.Splitter@33b37288 splitter = splitter.trimResults(); // the returned splitter to be assigned System.out.println("Second: " + splitter); // Second: com.google.common.base.Splitter@77a57272 }
splitToList
咱們前面已經使用的 split 方法,它返回的是一個 Iterable對象。而這裏的 splitToList 方法返回一個 List。因爲分割方法返回的是 Iterable,所以它是惰性的。
@Test public void testSplitterOfSplitToList() { Splitter commaSplitter = Splitter.on(","); List<String> result = commaSplitter.splitToList("m,g,h,i,o"); System.out.println(result); // [m, g, h, i, o] }
MapSplitter
MapSplitter 顧名思義就是用來將一個將字符串拆分爲 Map 對象的。咱們可使用 withKeyValueSeparator 方法從 Splitter 中獲取 MapSplitter 對象,該方法接收一個字符、字符串或者 Splitter 對象做爲參數。首先,根據原始的分割器將字符串分割爲多個項,而後,使用傳給 withKeyValueSeparator 方法的分割符將各個項分爲 Map 鍵-值對。
@Test public void testSplitterOfWithKeyValueSeparator() { Splitter commaSplitter = Splitter.on(','); Splitter.MapSplitter keyValueSplitter = commaSplitter.withKeyValueSeparator('='); Map<String, String> map = keyValueSplitter.split("name=mghio,blog=mghio.cn"); System.out.println(map); // {name=mghio, blog=mghio.cn} }
從結果能夠看到,它分割爲兩個 entry (name=mghio 與 blog=mghio.cn)項,還有一個點須要注意的是:若是咱們在原始的分割器上指定了任何修改器,則它們僅適用於該分割器,而不適用於 MapSplitter。
@Test public void testSplitterOfWithKeyValueSeparatorAndModifiers() { Splitter originalSplitter = Splitter.on(",").trimResults(); Splitter.MapSplitter keyValueSplitter = originalSplitter.withKeyValueSeparator('='); // 輸出結果:{name =mghio, blog= mghio.cn} System.out.println(keyValueSplitter.split("name =mghio, blog= mghio.cn")); }
由以上結果能夠看出 trimResults 修飾方法僅適用於原始拆分器。所以,blog 開頭的空格已被移除(使用 , 分割原始字符串時),可是,mghio.cn 開頭的空格不會被移除(使用 = 分割成鍵值時)。
最後須要注意的是:MapSplitter 類被標記爲 @Beta,這意味着類庫中與 MapSplitter 相關的類和方法是實驗性的,能夠更改(以中斷的方式),甚至未來版本可能刪除。
總結
在本文中,介紹了 Google Guava 庫以及在項目或應用程序中使用它的好處,如何將其導入到咱們的應用程序中使用。而後,介紹了 Guava 庫中對字符串操做工具類(Strings 和 Splitter )的一些基本用法,固然,這只是冰山一角,Guava 庫還提供了其它不少有用的基礎功能,須要咱們本身去查詢相關文檔學習瞭解,感興趣的朋友能夠去看看它的實現源碼,這個庫的代碼寫得很優雅。