欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

正文

在日常的 Java 開發(fā)中,由于 JDK 未能提供足夠的常用的操作類庫,通常我們會引入 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)行操作的,不會把分割字符串作為一個(gè)整體來看,返回的結(jié)果中不也會包含用于分割的字符。

驗(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)文章

  • 基于SpringBoot實(shí)現(xiàn)動態(tài)配置數(shù)據(jù)庫的加載

    基于SpringBoot實(shí)現(xiàn)動態(tài)配置數(shù)據(jù)庫的加載

    這篇文章主要介紹了Spring?Boot?如何動態(tài)配置數(shù)據(jù)庫的加載,現(xiàn)項(xiàng)目有一個(gè)需求,期望通過在application.yml配置文件中設(shè)置一個(gè)開關(guān),來決定是否加載數(shù)據(jù)庫,文中通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2024-10-10
  • SpringBoot中的RabbitMQ用法詳解

    SpringBoot中的RabbitMQ用法詳解

    RabbitMQ是一個(gè)開源的消息隊(duì)列系統(tǒng),它通過AMQP(高級消息隊(duì)列協(xié)議)來實(shí)現(xiàn)消息的傳遞,SpringBoot是目前非常流行的Java開發(fā)框架,它提供了很多便利性的功能,其中就包括對RabbitMQ的支持,在本文中,我們將介紹如何在SpringBoot中使用RabbitMQ
    2023-07-07
  • java 基礎(chǔ)之final、finally和finalize的區(qū)別

    java 基礎(chǔ)之final、finally和finalize的區(qū)別

    這篇文章主要介紹了java 基礎(chǔ)之final、finally和finalize的區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 鑒權(quán)認(rèn)證+aop+注解+過濾feign請求的實(shí)例

    鑒權(quán)認(rèn)證+aop+注解+過濾feign請求的實(shí)例

    這篇文章主要介紹了鑒權(quán)認(rèn)證+aop+注解+過濾feign請求的實(shí)例講解,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java用棧實(shí)現(xiàn)綜合計(jì)算器

    Java用棧實(shí)現(xiàn)綜合計(jì)算器

    棧(stack)又名堆棧,它是一種運(yùn)算受限的線性表,下面看一下如何在Java中,利用數(shù)組實(shí)現(xiàn)模擬一個(gè)棧,感興趣的朋友跟隨小編一起看看吧
    2022-06-06
  • JavaApi實(shí)現(xiàn)更新刪除及讀取節(jié)點(diǎn)

    JavaApi實(shí)現(xiàn)更新刪除及讀取節(jié)點(diǎn)

    這篇文章主要介紹了JavaApi實(shí)現(xiàn)更新刪除及讀取節(jié)點(diǎn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • jetty運(yùn)行時(shí)無法保存文件的解決方法

    jetty運(yùn)行時(shí)無法保存文件的解決方法

    這篇文章主要為大家詳細(xì)介紹了jetty運(yùn)行時(shí)無法保存文件的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • 在SpringBoot項(xiàng)目中使用JetCache緩存的詳細(xì)教程

    在SpringBoot項(xiàng)目中使用JetCache緩存的詳細(xì)教程

    Spring Boot是一個(gè)非常流行的Java開發(fā)框架,JetCache是一個(gè)基于注解的高性能緩存框架,本文將介紹如何在Spring Boot項(xiàng)目中使用JetCache緩存,并提供一個(gè)詳細(xì)案例來說明如何配置和使用JetCache,需要的朋友可以參考下
    2024-06-06
  • 基于指針pointers和引用references的區(qū)別分析

    基于指針pointers和引用references的區(qū)別分析

    本篇文章介紹了,基于指針pointers和引用references的區(qū)別分析。需要的朋友參考下
    2013-05-05
  • SpringMVC文件上傳及查看的示例代碼

    SpringMVC文件上傳及查看的示例代碼

    本篇文章主要介紹了SpringMVC文件上傳及查看的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-01-01

最新評論