最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java開發(fā)使用StringUtils.split避坑詳解

 更新時間:2022年11月04日 17:03:37   作者:程序猿阿朗  
這篇文章主要為大家介紹了java開發(fā)使用StringUtils.split避坑詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

在日常的 Java 開發(fā)中,由于 JDK 未能提供足夠的常用的操作類庫,通常我們會引入 Apache Commons Lang 工具庫或者 Google Guava 工具庫簡化開發(fā)過程。兩個類庫都為 java.lang API 提供了很多實用工具,比如經(jīng)常使用的字符串操作,基本數(shù)值操作、時間操作、對象反射以及并發(fā)操作等。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>
</dependency>

但是,最近在使用 Apache Commons Lang 工具庫時踩了一個坑,導致程序出現(xiàn)了意料之外的結(jié)果。

StringUtils.split 的坑

也是因為踩了這個坑,索性寫下一篇文章好好介紹下 Apache Commons Lang 工具庫中字符串操作相關 API。

先說坑是什么,我們都知道 String 類中到的 split 方法可以分割字符串,比如字符串 aabbccdd 根據(jù) bc 分割的結(jié)果應該是 aab 和 cdd 才對,這樣的結(jié)果也很容易驗證。

String str = "aabbccdd";
for (String s : str.split("bc")) {
    System.out.println(s);
}
// 結(jié)果
aab
cdd

可能是因為 String 類中的 split 方法的影響,我一直以為 StringUtils.split 的效果應該相同,但其實完全不同,可以試著分析下面的三個方法輸出結(jié)果是什么,StringUtils 是 Commons Lang 類庫中的字符串工具類。

 public static void testA() {
    String str = "aabbccdd";
    String[] resultArray = StringUtils.split(str, "bc");
    for (String s : resultArray) {
        System.out.println(s);
    }
}

我對上面 testA 方法的預期是 aab 和 cdd ,但是實際上這個方法的運行結(jié)果是:

// testA 輸出
aa
dd

可以看到 b 和 c 字母都不見了,只剩下了 a 和 b,這是已經(jīng)發(fā)現(xiàn)問題了,查看源碼后發(fā)現(xiàn) StringUtils.split 方法其實是按字符進行操作的,不會把分割字符串作為一個整體來看,返回的結(jié)果中不也會包含用于分割的字符。

驗證代碼:

public static void testB() {
    String str = "abc";
    String[] resultArray = StringUtils.split(str, "ac");
    for (String s : resultArray) {
        System.out.println(s);
    }
}
// testB 輸出
b
public static void testC() {
    String str = "abcd";
    String[] resultArray = StringUtils.split(str, "ac");
    for (String s : resultArray) {
        System.out.println(s);
    }
}
// testC 輸出
b
d

輸出結(jié)果和預期的一致了。

StringUtils.split 源碼分析

點開源碼一眼看下去,發(fā)現(xiàn)在方法注釋中就已經(jīng)進行提示了:返回的字符串數(shù)組中不包含分隔符。

The separator is not included in the returned String array. Adjacent separators are treated as one separator. For more control over the split use the StrTokenizer class....

繼續(xù)追蹤源碼,可以看到最終 split 分割字符串時入?yún)⒂兴膫€。

private static String[] splitWorker(
final String str, // 原字符串 
final String separatorChars,  // 分隔符
final int max,  // 分割后返回前多少個結(jié)果,-1 為所有
final boolean preserveAllTokens // 暫不關注
) {
}

根據(jù)分隔符的不同又分了三種情況。

1. 分隔符為 null

final int len = str.length();
if (len == 0) {
    return ArrayUtils.EMPTY_STRING_ARRAY;
}
final List<String> list = new ArrayList<>();
int sizePlus1 = 1;
int i = 0;
int start = 0;
boolean match = false;
boolean lastMatch = false;
if (separatorChars == null) {
    // Null separator means use whitespace
    while (i < len) {
        if (Character.isWhitespace(str.charAt(i))) { 
            if (match || preserveAllTokens) {
                lastMatch = true;
                if (sizePlus1++ == max) {
                    i = len;
                    lastMatch = false;
                }
                list.add(str.substring(start, i));
                match = false;
            }
            start = ++i;
            continue;
        }
        lastMatch = false;
        match = true;
        i++;
    }
}
// ...
if (match || preserveAllTokens && lastMatch) {
            list.add(str.substring(start, i));
}

可以看到如果分隔符為 null ,是按照空白字符 Character.isWhitespace() 分割字符串的。分割的算法邏輯為:

a. 用于截取的開始下標置為 0 ,逐字符讀取字符串。

b. 碰到分割的目標字符,把截取的開始下標到當前字符之前的字符串截取出來。

c. 然后用于截取的開始下標置為下一個字符,等到下一次使用。

d. 繼續(xù)逐字符讀取字符串、

2. 分隔符為單個字符

邏輯同上,只是判斷邏輯 Character.isWhitespace() 變?yōu)榱酥付ㄗ址袛唷?/p>

// Optimise 1 character case
final char sep = separatorChars.charAt(0);
while (i < len) {
    if (str.charAt(i) == sep) { // 直接比較
      ...

3. 分隔符為字符串

總計邏輯同上,只是判斷邏輯變?yōu)榘袛唷?/p>

 // standard case
while (i < len) {
    if (separatorChars.indexOf(str.charAt(i)) >= 0) { // 包含判斷
        if (match || preserveAllTokens) {

如何解決?

1. 使用 splitByWholeSeparator 方法。

我們想要的是按整個字符串分割,StringUtils 工具類中已經(jīng)存在具體的實現(xiàn)了,使用 splitByWholeSeparator 方法。

String str = "aabbccdd";
String[] resultArray = StringUtils.splitByWholeSeparator(str, "bc");
for (String s : resultArray) {
    System.out.println(s);
}
// 輸出
aab
cdd

2. 使用 Google Guava 工具庫

關于 Guava 工具庫的使用,之前也寫過一篇文章,可以參考:Guava - 拯救垃圾代碼

String str = "aabbccdd";
Iterable<String> iterable = Splitter.on("bc")
    .omitEmptyStrings() // 忽略空值
    .trimResults() // 過濾結(jié)果中的空白
    .split(str);
iterable.forEach(System.out::println);
// 輸出
aab
cdd

3. JDK String.split 方法

使用 String 中的 split 方法可以實現(xiàn)想要效果。

String str = "aabbccdd";
String[] res = str.split("bc");
for (String re : res) {
    System.out.println(re);
}
// 輸出
aab
cdd

但是 String 的 split 方法也有一些坑,比如下面的輸出結(jié)果。

String str = ",a,,b,";
String[] splitArr = str.split(",");
Arrays.stream(splitArr).forEach(System.out::println);
// 輸出
a
b

開頭的逗號,前出現(xiàn)了空格,末尾的逗號,后卻沒有空格。

一如既往,文章中代碼存放在 Github.com/niumoo/javaNotes.

以上就是java開發(fā)使用StringUtils.split避坑詳解的詳細內(nèi)容,更多關于java開發(fā)StringUtils.split避坑的資料請關注腳本之家其它相關文章!

相關文章

  • java eclipse 中文件的上傳和下載示例解析

    java eclipse 中文件的上傳和下載示例解析

    這篇文章主要介紹了eclipse java中文件的上傳和下載示例解析,文件上傳,瀏覽器在上傳的過程中是將文件以流的形式提交到服務器端的。對此感興趣的小伙伴可以了解一下
    2020-07-07
  • Spring之AOP兩種代理機制對比分析(JDK和CGLib動態(tài)代理)

    Spring之AOP兩種代理機制對比分析(JDK和CGLib動態(tài)代理)

    這篇文章主要介紹了Spring之AOP兩種代理機制對比分析(JDK和CGLib動態(tài)代理),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • Java字符串格式化功能?String.format用法詳解

    Java字符串格式化功能?String.format用法詳解

    String類的format()方法用于創(chuàng)建格式化的字符串以及連接多個字符串對象,熟悉C語言的同學應該記得C語言的sprintf()方法,兩者有類似之處,format()方法有兩種重載形式
    2024-09-09
  • Spring之兩種任務調(diào)度Scheduled和Async詳解

    Spring之兩種任務調(diào)度Scheduled和Async詳解

    這篇文章主要介紹了Spring之兩種任務調(diào)度Scheduled和Async,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Java實現(xiàn)手寫線程池的示例代碼

    Java實現(xiàn)手寫線程池的示例代碼

    在我們的日常的編程當中,并發(fā)是始終離不開的主題,而在并發(fā)多線程當中,線程池又是一個不可規(guī)避的問題。本文就來分享一下如何自己手寫一個線程池,需要的可以參考一下
    2022-08-08
  • Scala中如何中斷循環(huán)詳解

    Scala中如何中斷循環(huán)詳解

    在Scala中,可以使用break和continue語句來中斷循環(huán)。break語句可以在滿足某個條件時中斷循環(huán),而continue語句可以在滿足某個條件時跳過當前循環(huán)迭代,直接執(zhí)行下一次迭代
    2023-04-04
  • reactor-logback的AsyncAppender執(zhí)行流程源碼解讀

    reactor-logback的AsyncAppender執(zhí)行流程源碼解讀

    這篇文章主要為大家介紹了reactor-logback的AsyncAppender執(zhí)行流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • springboot整合security和vue的實踐

    springboot整合security和vue的實踐

    本文主要介紹了springboot整合security和vue的實踐,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 淺談Java基準性能測試之JMH

    淺談Java基準性能測試之JMH

    JMH是Java Microbenchmark Harness的簡稱,一個針對Java做基準測試的工具。想準確的對一段代碼做基準性能測試并不容易,因為JVM層面在編譯期、運行時對代碼做很多優(yōu)化,當代碼塊處于整個系統(tǒng)中運行時并不一定會生效,產(chǎn)生錯誤的基準測試結(jié)果,這個問題就是JMH要解決的
    2021-06-06
  • Spring中@Value注解獲取不到配置值問題及解決

    Spring中@Value注解獲取不到配置值問題及解決

    這篇文章主要介紹了Spring中@Value注解獲取不到配置值問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09

最新評論

诸暨市| 鄂伦春自治旗| 富平县| 凤城市| 闽侯县| 福州市| 景宁| 读书| 阜新市| 米脂县| 浦城县| 垦利县| 扶沟县| 尚志市| 三原县| 山西省| 得荣县| 云南省| 西华县| 邵武市| 绵竹市| 阳信县| 津市市| 溧水县| 石门县| 根河市| 文昌市| 漠河县| 贺兰县| 新竹县| 林甸县| 醴陵市| 旺苍县| 武冈市| 庆城县| 璧山县| 龙胜| 无极县| 石家庄市| 和龙市| 泊头市|