StringJoiner

為什么會新增這樣一個string輔助類?

原有的stringbuilder太死板弃酌,不支持分割,如果想讓最終的字符串以逗號隔開儡炼,需要這樣寫


StringBuilder sb = new StringBuilder();
IntStream.range(1,10).forEach(i->{
    sb.append(i+"");
    if( i < 10){
        sb.append(",")
    } 
});

是不是太死板了妓湘,不好用,StringJoiner怎樣寫呢乌询?

StringJoiner sj = new StringJoiner(",");
IntStream.range(1,10).forEach(i->sj.add(i+""));

有哪些平時用的還比較少的功能:

  • setEmptyValue, 默認(rèn)情況下的emptyValue是前綴加后綴榜贴, 用戶可自定義emptyValue
  • merge(StringJoiner other),合并另外一個joiner
  • length, 當(dāng)前長度,為空看emptyValue的長度

讓我實現(xiàn)StringJoiner妹田,我會怎么辦呢唬党?

  • 維護一個List,最后toString的時候join一下就好了
    優(yōu)勢:實現(xiàn)非常方便
    缺點:list太浪費空間(擴容時都是按照系數(shù)擴容的)
  • 在StringBuilder基礎(chǔ)上改造(jdk實現(xiàn)方式就是以組合的形式增強的StringBuilder)

jdk實現(xiàn)的源碼分析

  • 成員變量
    private final String prefix;
    private final String delimiter;
    private final String suffix;

    /*
     * StringBuilder value -- at any time, the characters constructed from the
     * prefix, the added element separated by the delimiter, but without the
     * suffix, so that we can more easily add elements without having to jigger
     * the suffix each time.
     */
    private StringBuilder value;

    /*
     * By default, the string consisting of prefix+suffix, returned by
     * toString(), or properties of value, when no elements have yet been added,
     * i.e. when it is empty.  This may be overridden by the user to be some
     * other value including the empty String.
     */
    private String emptyValue;

其實從成員變量的注釋里就能看出他們的作用和需要注意的點了

  • 構(gòu)造函數(shù)
public StringJoiner(CharSequence delimiter,
                        CharSequence prefix,
                        CharSequence suffix) {
        Objects.requireNonNull(prefix, "The prefix must not be null");
        Objects.requireNonNull(delimiter, "The delimiter must not be null");
        Objects.requireNonNull(suffix, "The suffix must not be null");
        // make defensive copies of arguments
        this.prefix = prefix.toString();
        this.delimiter = delimiter.toString();
        this.suffix = suffix.toString();
        // >楣病!初嘹!構(gòu)造時就直接將emptyValue拼接好了及汉。
        this.emptyValue = this.prefix + this.suffix;
    }

為什么要一開始就構(gòu)造好呢?如果我想直接自定義emptyValue直接用構(gòu)造函數(shù)初始化不是更方便嗎屯烦?是因為絕大多數(shù)場景下都不會自定義emptyValue的場景嗎坷随?不對啊赢底,感覺這個場景非常必要啊糊治。片拍。斋泄。

  • 添加元素
public StringJoiner add(CharSequence newElement) {
        prepareBuilder().append(newElement);
        return this;
}

private StringBuilder prepareBuilder() {
        // 從構(gòu)造函數(shù)和類變量的聲明可以看出,沒有添加元素前stringbuilder是沒有初始化的
        if (value != null) {
            // 已經(jīng)有元素存在的情況下楼雹,添加元素前先將分隔符添加進去
            value.append(delimiter);
        } else {
            // 沒有元素存在的情況下先把前綴加進去
            value = new StringBuilder().append(prefix);
        }
        return value;
}

可以看出再添加元素的過程中就已經(jīng)把前綴和分割字符什么的都處理好了辞做,全部都在stringbuilde中了莺掠,唯一沒有處理的就是后綴露懒。 為什么闯冷?這樣做tostring什么的時候真的超級方便的有木有。懈词。蛇耀。。坎弯。

  • 關(guān)鍵的toString
public String toString() {
        if (value == null) {
            // 這里如果沒有自定義空值就是前綴+后綴咯纺涤。。
            return emptyValue;
        } else {
            // 為什么不直接value.toString()+suffix?????
            if (suffix.equals("")) {
                return value.toString();
            } else {
     
                int initialLength = value.length();
                String result = value.append(suffix).toString();
                // reset value to pre-append initialLength
                value.setLength(initialLength);
                return result;
            }
        }
    }

為什么不直接value.toString()+suffix抠忘?答案在merge方法

  • merge
public StringJoiner merge(StringJoiner other) {
        Objects.requireNonNull(other);
        if (other.value != null) {
            final int length = other.value.length();
            // 下面這段注釋是說避免merge(this)時受影響撩炊,為什么?
            // lock the length so that we can seize the data to be appended
            // before initiate copying to avoid interference, especially when
            // merge 'this'
            StringBuilder builder = prepareBuilder();
            builder.append(other.value, other.prefix.length(), length);
        }
        return this;
    }

    private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);
        }
        return value;
    }

merge的思路是用當(dāng)前的striingBuilder去append other的value(必須去掉前綴)崎脉,源碼注釋中的merge 'this'問題是什么呢拧咳? prepareBuilder()的時候可能會先append(delimiter),如果other就是this囚灼,那么length其實就多了一個delimiter呛踊,此時append還是得以添加前的length為準(zhǔn)。

merge的實現(xiàn)方式?jīng)Q定了toString時不能直接value.append(suffix).toString(),因為
builder.append(other.value, other.prefix.length(), length);這行代碼啦撮,默認(rèn)加上suffix后這里的merge的length得減去suffix的length(嗯,看來作者是想得多好多)汪厨,而且merge時得把另外一個sj的內(nèi)容append到當(dāng)前這個sj的suffix之前(想想就麻煩多了赃春。。劫乱。织中。)

  • length
public int length() {
        // Remember that we never actually append the suffix unless we return
        // the full (present) value or some sub-string or length of it, so that
        // we can add on more if we need to.
        return (value != null ? value.length() + suffix.length() :
                emptyValue.length());
    }

沒什么好說的锥涕,記住length不只是add的元素的length,還有前后綴狭吼。

總結(jié)

  • 基于StringBuilder實現(xiàn)层坠,add時就把prefix和分隔符給加上了,suffix永遠都不加刁笙,知道toString和length調(diào)用時才加入計算破花。 這樣帶來的merge操作實現(xiàn)的極大便利性!FNW俊!摘悴!學(xué)到了峭梳,真的不錯

  • emptyValue這個一定要構(gòu)造時就生成嗎?用戶想有自己的默認(rèn)值還需要先構(gòu)造實例再注入嗎蹂喻。葱椭。。口四。這個覺得還是有點奇怪

  • Objects這個工具方法是返回的校驗的值本身孵运,不錯。

public StringJoiner setEmptyValue(CharSequence emptyValue) {
// 注意這個Objects.requireNonNull方法是return的第一個參數(shù)窃祝。掐松。。
        this.emptyValue = Objects.requireNonNull(emptyValue,
            "The empty value must not be null").toString();
        return this;
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粪小,一起剝皮案震驚了整個濱河市大磺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌探膊,老刑警劉巖杠愧,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異逞壁,居然都是意外死亡流济,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門腌闯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绳瘟,“玉大人,你說我怎么就攤上這事姿骏√巧” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蘸泻。 經(jīng)常有香客問我琉苇,道長,這世上最難降的妖魔是什么悦施? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任并扇,我火速辦了婚禮,結(jié)果婚禮上抡诞,老公的妹妹穿的比我還像新娘穷蛹。我一直安慰自己,他們只是感情好沐绒,可當(dāng)我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布俩莽。 她就那樣靜靜地躺著,像睡著了一般乔遮。 火紅的嫁衣襯著肌膚如雪扮超。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天蹋肮,我揣著相機與錄音出刷,去河邊找鬼。 笑死坯辩,一個胖子當(dāng)著我的面吹牛馁龟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播漆魔,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼坷檩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了改抡?” 一聲冷哼從身側(cè)響起矢炼,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎阿纤,沒想到半個月后句灌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡欠拾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年胰锌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片藐窄。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡资昧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荆忍,到底是詐尸還是另有隱情榛搔,我是刑警寧澤诺凡,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站践惑,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嘶卧。R本人自食惡果不足惜尔觉,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芥吟。 院中可真熱鬧侦铜,春花似錦、人聲如沸钟鸵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棺耍。三九已至贡未,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蒙袍,已是汗流浹背俊卤。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留害幅,地道東北人消恍。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像以现,于是被迫代替她去往敵國和親狠怨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 最先接觸編程的知識是在大學(xué)里面,大學(xué)里面學(xué)了一些基礎(chǔ)的知識无宿,c語言茵汰,java語言,單片機的匯編語言等孽鸡;大學(xué)畢...
    oceanfive閱讀 3,087評論 0 7
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蹂午,服務(wù)發(fā)現(xiàn),斷路器彬碱,智...
    卡卡羅2017閱讀 134,665評論 18 139
  • StringJoiner源碼閱讀 昨天看到一個非常有意思的類StringJoiner豆胸。 今天就來看下是怎么實現(xiàn)的。...
    cocalrush閱讀 1,293評論 0 0
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法巷疼,類相關(guān)的語法晚胡,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法估盘,線程的語...
    子非魚_t_閱讀 31,641評論 18 399
  • 前一年多我們都沒有太多交集瓷患。我為了他去他的物理老師那里補課。見他一眼都笑嘻嘻的遣妥。后來有一天擅编,我們接吻了。關(guān)系密切了...
    里漾33閱讀 189評論 0 0