<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          不用StringBuilder!Java8的StringJoiner,也很香!

          共 11336字,需瀏覽 23分鐘

           ·

          2021-09-26 08:04

          上一篇:字節(jié)實習生開發(fā)的 AI 竟然被網(wǎng)友用在了王冰冰身上!

          在閱讀項目代碼是,突然看到了StringJoiner這個類的使用,感覺很有意思,對實際開發(fā)中也有用,實際上是運用了StringBuilder的一個拼接字符串的封裝處理。


          為什么會新增這樣一個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, 默認情況下的emptyValue是前綴加后綴, 用戶可自定義emptyValue

          • merge(StringJoiner other),合并另外一個joiner

          • length, 當前長度,為空看emptyValue的長度

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

          維護一個List,最后toString的時候join一下就好了
          優(yōu)勢:實現(xiàn)非常方便
          缺點:list太浪費空間(擴容時都是按照系數(shù)擴容的)
          在StringBuilder基礎上改造(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;

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

          構造函數(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();
                  // ?。?!構造時就直接將emptyValue拼接好了。
                  this.emptyValue = this.prefix + this.suffix;
              }

          為什么要一開始就構造好呢?如果我想直接自定義emptyValue直接用構造函數(shù)初始化不是更方便嗎?是因為絕大多數(shù)場景下都不會自定義emptyValue的場景嗎?不對啊,感覺這個場景非常必要啊。。。

          添加元素

          public StringJoiner add(CharSequence newElement{
                  prepareBuilder().append(newElement);
                  return this;
          }

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

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

          關鍵的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的思路是用當前的striingBuilder去append other的value(必須去掉前綴),源碼注釋中的merge 'this'問題是什么呢?prepareBuilder()的時候可能會先append(delimiter),如果other就是this,那么length其實就多了一個delimiter,此時append還是得以添加前的length為準。

          merge的實現(xiàn)方式?jīng)Q定了toString時不能直接value.append(suffix).toString(),因為
          builder.append(other.value, other.prefix.length(), length);這行代碼,默認加上suffix后這里的merge的length得減去suffix的length(嗯,看來作者是想得多好多),而且merge時得把另外一個sj的內容append到當前這個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,還有前后綴。

          總結

          基于StringBuilder實現(xiàn),add時就把prefix和分隔符給加上了,suffix永遠都不加,知道toString和length調用時才加入計算。這樣帶來的merge操作實現(xiàn)的極大便利性?。。。?!學到了,真的不錯

          emptyValue這個一定要構造時就生成嗎?用戶想有自己的默認值還需要先構造實例再注入嗎。。。。這個覺得還是有點奇怪

          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;
          }


          感謝您的閱讀,也歡迎您發(fā)表關于這篇文章的任何建議,關注我,技術不迷茫!小編到你上高速。

              · END ·
          最后,關注公眾號互聯(lián)網(wǎng)架構師,在后臺回復:2T,可以獲取我整理的 Java 系列面試題和答案,非常齊全


          正文結束


          推薦閱讀 ↓↓↓

          1.不認命,從10年流水線工人,到谷歌上班的程序媛,一位湖南妹子的勵志故事

          2.如何才能成為優(yōu)秀的架構師?

          3.從零開始搭建創(chuàng)業(yè)公司后臺技術棧

          4.程序員一般可以從什么平臺接私活?

          5.37歲程序員被裁,120天沒找到工作,無奈去小公司,結果懵了...

          6.IntelliJ IDEA 2019.3 首個最新訪問版本發(fā)布,新特性搶先看

          7.這封“領導痛批95后下屬”的郵件,句句扎心!

          8.15張圖看懂瞎忙和高效的區(qū)別!

          一個人學習、工作很迷茫?


          點擊「閱讀原文」加入我們的小圈子!

          瀏覽 28
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  蜜臀VA| 日日操日日擦 | 毛片电影在线香 | 中国黄色操逼大片 | 国产精品久久久久久吹潮 |