JavaRush /Java Blog /Random-TW /讓我們分解一下 StringUtils 類
Roman Beekeeper
等級 35

讓我們分解一下 StringUtils 類

在 Random-TW 群組發布
大家好,我親愛的讀者。我嘗試寫下我真正感興趣的事情以及我目前擔心的事情。因此,今天將有一些輕讀,對您以後作為參考很有用:我們來談談StringUtils讓我們分解一下 StringUtils 類別 - 1恰巧我有一次繞過了Apache Commons Lang 3庫。這是一個帶有輔助類別的庫,用於處理不同的物件。這是用於處理字串、集合等的有用方法的集合。在目前的一個專案中,我必須更詳細地處理字串,將 25 年前的業務邏輯(從 COBOL 轉換為 Java),結果證明我對StringUtils 類別沒有足夠深入的了解。所以我必須自己創造一切。我的意思是說?事實上,您不必自己編寫涉及字串操作的某些任務,而是使用現成的解決方案。自己寫有什麼問題嗎?至少這是很久以前就已經寫的更多程式碼。同樣緊迫的是測試額外編寫的程式碼的問題。當我們使用一個已經證明自己很好的函式庫時,我們期望它已經經過測試,並且我們不需要編寫一堆測試案例來測試它。碰巧的是,Java 中處理字串的方法集並不是那麼大。對工作有用的方法確實不多。建立此類也是為了提供對 NullPointerException 的檢查。我們文章的大綱如下:
  1. 如何連接?
  2. 我的工作範例:在不了解如此有用的課程的情況下,我如何創建了我的自行車拐杖。
  3. 讓我們看看我覺得有趣的其他方法。
  4. 我們來總結一下。
所有案例都將新增至GitHub 上 Javarush 社群組織的單獨儲存庫。他們將會有單獨的例子和測試。

0. 如何連接

與我攜手同行的人都或多或少地熟悉了 Git 和 Maven,因此我將進一步依賴這些知識,不再重複。對於那些錯過了我之前的文章或剛開始閱讀的人,這裡有關於MavenGit 的材料。當然,如果沒有建置系統(Maven、Gredl),您也可以手動連接所有內容,但現在這很瘋狂,您絕對不需要這樣做:最好立即學習如何正確地完成所有操作。因此,要使用 Maven,我們首先添加適當的依賴項:
<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>${apache.common.version}</version>
</dependency>
其中${apache.common.version}就是該函式庫的版本。接下來,要導入某個類,請新增導入:
import org.apache.commons.lang3.StringUtils;
就這樣,一切都在袋子裡))

1. 實際專案範例

  • 左墊法

第一個例子現在看起來很愚蠢,我的同事知道StringUtils.leftPad並告訴我,這很好。任務是什麼:程式碼的建構方式是,如果資料未完全正確到達,則必須轉換資料。預計字串欄位應僅包含數字,即 如果它的長度是3且它的值是1,則該條目應該是「001」。也就是說,首先需要刪除所有空格,然後用零覆蓋它。更多範例可以讓任務的本質變得清晰:從“12” -> “012” 從“1” -> “001” 等等。我做了什麼?在LeftPadExample類別中對此進行了描述。我寫了一個方法來完成這一切:
public static String ownLeftPad(String value) {
   String trimmedValue = value.trim();

   if(trimmedValue.length() == value.length()) {
       return value;
   }

   StringBuilder newValue = new StringBuilder(trimmedValue);

   IntStream.rangeClosed(1, value.length() - trimmedValue.length())
           .forEach(it -> newValue.insert(0, "0"));
   return newValue.toString();
}
作為基礎,我的想法是,我們可以簡單地獲得原始值和修剪值之間的差異,並在前面用零填充。為此,我使用IntStream執行相同的操作 n 次。這絕對需要測試。如果我提前知道StringUtils.leftPad方法,我可以做以下事情:
public static String apacheCommonLeftPad(String value) {
   return StringUtils.leftPad(value.trim(), value.length(), "0");
}
可以看到,程式碼少了很多,還使用了大家都確認的函式庫。為此,我在LeftPadExampleTest類別中建立了兩個測試(通常當他們計劃測試一個類別時,他們會在同一個套件中建立一個同名的類別 + Test,僅在 src/test/java 中)。這些測試檢查一種方法以確保它正確轉換值,然後檢查另一種方法。當然,需要編寫更多的測試,但測試不是我們案例的主要主題:
package com.github.javarushcommunity.stringutilsdemo;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

@DisplayName("Unit-level testing for LeftPadExample")
class LeftPadExampleTest {

   @DisplayName("Should transform by using ownLeftPad method as expected")
   @Test
   public void shouldTransformOwnLeftPadAsExpected() {
       //given
       String value = "1   ";
       String expectedTransformedValue = "0001";

       //when
       String transformedValue = LeftPadExample.ownLeftPad(value);

       //then
       Assertions.assertEquals(expectedTransformedValue, transformedValue);
   }

   @DisplayName("Should transform by using StringUtils method as expected")
   @Test
   public void shouldTransformStringUtilsLeftPadAsExpected() {
       //given
       String value = "1   ";
       String expectedTransformedValue = "0001";

       //when
       String transformedValue = LeftPadExample.apacheCommonLeftPad(value);

       //then
       Assertions.assertEquals(expectedTransformedValue, transformedValue);
   }

}
我現在可以對測試發表一些評論。它們是使用 JUnit 5 編寫的:
  1. 如果測試具有適當的註釋 - @Test,則該測試將被視為測試。
  2. 如果名稱中難以描述測試的操作或描述較長不方便閱讀,可以添加@DisplayName註解,使其成為運行測試時可見的普通描述。
  3. 在編寫測試時,我使用 BDD 方法,將測試分為邏輯部分:
    1. //給定-測試前的資料設定區塊;
    2. //我們正在測試的程式碼部分何時啟動;
    3. //then是一個區塊,其中檢查when區塊的結果。
如果您運行它們,它們將確認一切都按預期工作。

  • stripStart方法

在這裡,我需要解決開頭可能有空格和逗號的行的問題。改造後,它們不應該有新的意義。問題陳述比以往更清晰。幾個例子將加深我們的理解: “, , books” -> “books” “,,, books” -> “books” b , books” -> “b , books” 與 leftPad 的情況一樣,我添加了StrimStartExample類,其中有兩個方法。一 - 有自己的解決方案:
public static String ownStripStart(String value) {
   int index = 0;
   List commaSpace = asList(" ", ",");
   for (int i = 0; i < value.length(); i++) {
       if (commaSpace.contains(String.valueOf(value.charAt(i)))) {
           index++;
       } else {
           break;
       }
   }
   return value.substring(index);
}
這裡的想法是找到從不再有空格或逗號的索引開始。如果它們一開始就不存在,那麼索引將為零。第二個 - 透過StringUtils解決方案:
public static String apacheCommonLeftPad(String value) {
   return StringUtils.stripStart(value, StringUtils.SPACE + COMMA);
}
在這裡,我們傳遞第一個參數有關我們正在使用哪個字串的信息,在第二個參數中,我們傳遞一個由需要跳過的字元組成的字串。我們以相同的方式建立StripStartExampleTest類別:
package com.github.javarushcommunity.stringutilsdemo;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("Unit-level testing for StripStartExample")
class StripStartExampleTest {

   @DisplayName("Should transform by using stripStart method as expected")
   @Test
   public void shouldTransformOwnStripStartAsExpected() {
       //given
       String value = ", , books";
       String expectedTransformedValue = "books";

       //when
       String transformedValue = StripStartExample.ownStripStart(value);

       //then
       Assertions.assertEquals(expectedTransformedValue, transformedValue);
   }

   @DisplayName("Should transform by using StringUtils method as expected")
   @Test
   public void shouldTransformStringUtilsStripStartAsExpected() {
       //given
       String value = ", , books";
       String expectedTransformedValue = "books";

       //when
       String transformedValue = StripStartExample.apacheCommonLeftPad(value);

       //then
       Assertions.assertEquals(expectedTransformedValue, transformedValue);
   }
}

  • isEmpty方法

當然,這種方法要簡單得多,但這並沒有降低它的用處。它擴展了String.isEmpty()方法的功能,該方法還添加了對 null 的檢查。為了什麼?避免 NullPointerException,即避免對null變數呼叫方法。因此,為了不寫:
if(value != null && value.isEmpty()) {
   //doing something
}
你可以簡單地這樣做:
if(StringUtils.isEmpty(value)) {
   //doing something
}
這種方法的優點是立即清楚哪裡使用了哪一種方法。

2、StringUtils類別的其他方法分析

現在我們來談談那些我認為也值得關注的方法。一般來說,關於StringUtils,值得一提的是,它提供了與String類別中的方法類似的 null 安全方法(就像isEmpty方法的情況一樣)。讓我們來看看它們:

  • 比較法

String中存在這樣的方法,如果在比較兩個字串時其中一個為 null,則會拋出 NullPointerException。為了避免程式碼中出現醜陋的檢查,我們可以使用StringUtils.compare(String str1, String str2)方法:它傳回一個 int 作為比較結果。這些值是什麼意思?如果它們相同(或均為 null),則 int = 0。如果 str1 小於 str2,則 int < 0。如果 str1 大於 str2,則 int > 0。另外,如果您查看他們的文檔,則該方法的 Javadoc 會呈現以下場景:
StringUtils.compare(null, null)   = 0
StringUtils.compare(null , "a")   < 0
StringUtils.compare("a", null)    > 0
StringUtils.compare("abc", "abc") = 0
StringUtils.compare("a", "b")     < 0
StringUtils.compare("b", "a")     > 0
StringUtils.compare("a", "B")     > 0
StringUtils.compare("ab", "abc")  < 0

  • 包含...方法

公用事業開發商在這裡玩得很開心。你想要什麼方法都有。我決定將它們放在一起:
  1. contains是一種檢查預期字串是否在另一個字串內部的方法。這有什麼用?如果需要確定文本中是否存在某個單詞,可以使用此方法。

    例子:

    StringUtils.contains(null, *)     = false
    StringUtils.contains(*, null)     = false
    StringUtils.contains("", "")      = true
    StringUtils.contains("abc", "")   = true
    StringUtils.contains("abc", "a")  = true
    StringUtils.contains("abc", "z")  = false

    再次強調,NPE(空指標異常)安全性是存在的。

  2. containsAny是一種檢查字串中是否存在任何字元的方法。還有一件有用的事情:你經常必須這樣做。

    文件中的範例:

    StringUtils.containsAny(null, *)                  = false
    StringUtils.containsAny("", *)                    = false
    StringUtils.containsAny(*, null)                  = false
    StringUtils.containsAny(*, [])                    = false
    StringUtils.containsAny("zzabyycdxx", ['z', 'a']) = true
    StringUtils.containsAny("zzabyycdxx", ['b', 'y']) = true
    StringUtils.containsAny("zzabyycdxx", ['z', 'y']) = true
    StringUtils.containsAny("aba", ['z'])             = false

  3. containsIgnoreCase是contains方法的有用擴充。事實上,要在沒有這種方法的情況下檢查這種情況,您將必須經歷幾個選項。所以只有一種方法會被和諧地使用。

  4. 文件中的一些範例:

    StringUtils.containsIgnoreCase(null, *) = false
    StringUtils.containsIgnoreCase(*, null) = false
    StringUtils.containsIgnoreCase("", "") = true
    StringUtils.containsIgnoreCase("abc", "") = true
    StringUtils.containsIgnoreCase("abc", "a") = true
    StringUtils.containsIgnoreCase("abc", "z") = false
    StringUtils.containsIgnoreCase("abc", "A") = true
    StringUtils.containsIgnoreCase("abc", "Z") = false

  5. containsNone - 從名稱來看,您已經可以了解正在檢查的內容。裡面不應該有任何線條。絕對是有用的東西。快速搜尋一些不需要的字元;)。在我們的電報機器人中,我們將過濾淫穢內容,並且不會忽略這些有趣的方法。

    舉個例子,如果沒有它們我們會怎麼樣:

    StringUtils.containsNone(null, *)       = true
    StringUtils.containsNone(*, null)       = true
    StringUtils.containsNone("", *)         = true
    StringUtils.containsNone("ab", '')      = true
    StringUtils.containsNone("abab", 'xyz') = true
    StringUtils.containsNone("ab1", 'xyz')  = true
    StringUtils.containsNone("abz", 'xyz')  = false

  • 預設字串方法

一系列方法有助於避免在字串為空並且需要設定一些預設值時添加額外資訊。有多種選擇可滿足各種口味。其中最主要的是StringUtils.defaultString(final String str, Final String defaultStr) - 如果 str 為 null,我們將簡單地傳遞defaultStr值。文件中的範例:
StringUtils.defaultString(null, "NULL")  = "NULL"
StringUtils.defaultString("", "NULL")    = ""
StringUtils.defaultString("bat", "NULL") = "bat"
當你創建帶有資料的POJO類別時使用起來非常方便。

  • 刪除空白方法

這是一個有趣的方法,儘管其應用選項並不多。同時,如果出現這樣的情況,這個方法肯定會非常有用。它刪除字串中的所有空格。無論這個間隙在哪裡,都不會留下任何痕跡)))文件中的範例:
StringUtils.deleteWhitespace(null)         = null
StringUtils.deleteWhitespace("")           = ""
StringUtils.deleteWhitespace("abc")        = "abc"
StringUtils.deleteWhitespace("   ab  c  ") = "abc"

  • 結束於方法

不言而喻。這是一個非常有用的方法:它檢查字串是否以建議的字串結尾。這通常是必要的。當然,你可以自己寫支票,但使用現成的方法顯然更方便、更好。例子:
StringUtils.endsWith(null, null)      = true
StringUtils.endsWith(null, "def")     = false
StringUtils.endsWith("abcdef", null)  = false
StringUtils.endsWith("abcdef", "def") = true
StringUtils.endsWith("ABCDEF", "def") = false
StringUtils.endsWith("ABCDEF", "cde") = false
StringUtils.endsWith("ABCDEF", "")    = true
正如你所看到的,一切都以空行結束)))我認為這個例子(StringUtils.endsWith(“ABCDEF”,“”)= true)只是一個獎勵,因為這是荒謬的)還有一種方法忽略大小寫。

  • 等於方法

比較兩個字串的空安全方法的一個很好的例子。無論我們輸入什麼,答案都會在那裡,而且不會有錯誤。例子:
StringUtils.equals(null, null)   = true
StringUtils.equals(null, "abc")  = false
StringUtils.equals("abc", null)  = false
StringUtils.equals("abc", "abc") = true
StringUtils.equals("abc", "ABC") = false
當然,還有equalsIgnoreCase - 一切都以完全相同的方式完成,只是我們忽略大小寫。讓我們來看看?
StringUtils.equalsIgnoreCase(null, null)   = true
StringUtils.equalsIgnoreCase(null, "abc")  = false
StringUtils.equalsIgnoreCase("abc", null)  = false
StringUtils.equalsIgnoreCase("abc", "abc") = true
StringUtils.equalsIgnoreCase("abc", "ABC") = true

  • 等於任何方法

讓我們繼續擴充equals方法。假設我們不想執行多次相等性檢查,而是執行一次。為此,我們可以傳遞一個字串,將與一組字串進行比較;如果其中任何一個與建議的字串相同,則為 TRUE。我們傳遞一個字串和一個字串集合來將它們相互比較(第一個字串與集合中的字串)。難的?以下是文件中的範例,可協助您理解其含義:
StringUtils.equalsAny(null, (CharSequence[]) null) = false
StringUtils.equalsAny(null, null, null)    = true
StringUtils.equalsAny(null, "abc", "def")  = false
StringUtils.equalsAny("abc", null, "def")  = false
StringUtils.equalsAny("abc", "abc", "def") = true
StringUtils.equalsAny("abc", "ABC", "DEF") = false
還有equalsAnyIgnoreCase。以及它的例子:
StringUtils.equalsAnyIgnoreCase(null, (CharSequence[]) null) = false
StringUtils.equalsAnyIgnoreCase(null, null, null)    = true
StringUtils.equalsAnyIgnoreCase(null, "abc", "def")  = false
StringUtils.equalsAnyIgnoreCase("abc", null, "def")  = false
StringUtils.equalsAnyIgnoreCase("abc", "abc", "def") = true
StringUtils.equalsAnyIgnoreCase("abc", "ABC", "DEF") = true

底線

因此,我們了解了StringUtils是什麼以及它有哪些有用的方法。好吧,意識到有如此有用的東西,並且無需每次都用拐杖在可以藉助現成解決方案解決問題的地方進行圍欄。總的來說,我們只分析了部分方法。如果你願意,我可以繼續:這樣的人還有很多,而且確實值得關注。如果您對如何呈現此內容有任何想法,請寫信 - 我總是樂於接受新想法。這些方法的文檔寫得很好,並添加了帶有結果的測試範例,這有助於更好地理解該方法的操作。因此,我們不會迴避閱讀文件:它將消除您對該實用程式功能的疑慮。為了獲得新的編碼經驗,我建議您了解實用程式類別是如何製作和編寫的。這在將來會很有用,因為通常每個項目都有自己的廢料類,編寫它們的經驗會派上用場。傳統上,我建議您在 Github 上訂閱我的帳戶)對於那些不了解我的電報機器人專案的人,這裡是第一篇文章的連結。感謝大家的閱讀。我在下面添加了一些有用的連結。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION