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

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

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

正文

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

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

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

StringUtils.split 的坑

也是因?yàn)椴攘诉@個(gè)坑,索性寫下一篇文章好好介紹下 Apache Commons Lang 工具庫中字符串操作相關(guān) API。

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

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

可能是因?yàn)?String 類中的 split 方法的影響,我一直以為 StringUtils.split 的效果應(yīng)該相同,但其實(shí)完全不同,可以試著分析下面的三個(gè)方法輸出結(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 方法的預(yù)期是 aab 和 cdd ,但是實(shí)際上這個(gè)方法的運(yùn)行結(jié)果是:

// testA 輸出
aa
dd

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

驗(yàn)證代碼:

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é)果和預(yù)期的一致了。

StringUtils.split 源碼分析

點(diǎn)開源碼一眼看下去,發(fā)現(xiàn)在方法注釋中就已經(jīng)進(jìn)行提示了:返回的字符串?dā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 分割字符串時(shí)入?yún)⒂兴膫€(gè)。

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

根據(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. 用于截取的開始下標(biāo)置為 0 ,逐字符讀取字符串。

b. 碰到分割的目標(biāo)字符,把截取的開始下標(biāo)到當(dāng)前字符之前的字符串截取出來。

c. 然后用于截取的開始下標(biāo)置為下一個(gè)字符,等到下一次使用。

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

2. 分隔符為單個(gè)字符

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

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

3. 分隔符為字符串

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

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

如何解決?

1. 使用 splitByWholeSeparator 方法。

我們想要的是按整個(gè)字符串分割,StringUtils 工具類中已經(jīng)存在具體的實(shí)現(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 工具庫

關(guān)于 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 方法可以實(shí)現(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避坑詳解的詳細(xì)內(nèi)容,更多關(guān)于java開發(fā)StringUtils.split避坑的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    springboot整合security和vue的實(shí)踐

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

    淺談Java基準(zhǔn)性能測試之JMH

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

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

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

最新評論

霍邱县| 应用必备| 长顺县| 嘉禾县| 楚雄市| 左云县| 依安县| 昆山市| 紫金县| 枣庄市| 昆山市| 广河县| 库车县| 阳城县| 神木县| 墨竹工卡县| 祁东县| 台湾省| 十堰市| 乌兰察布市| 西乌珠穆沁旗| 安国市| 玉环县| 新营市| 赣榆县| 全州县| 永寿县| 伊通| 长汀县| 化隆| 成武县| 武乡县| 吉木乃县| 万荣县| 中山市| 福建省| 临清市| 宣恩县| 临夏县| 南投市| 从化市|