中午躺在床上,閑來無事草草看了一眼微信,無意間發現了一篇技術文章,講的是StringJoiner的運用。
當時第一反應就是這玩意大概又是java8以上版本新出的東西吧?細看發現並不是,居然是java8中存在的一個用於構建字符串的類。以前居然完全沒聽說過... ...驚嘆之余,決定必須學一波。
由於這個類比較簡單,所以可以直接看着源碼學習。
private final String prefix; private final String delimiter; private final String suffix; private StringBuilder value; private String emptyValue;
首先來看一下類中存在的五個成員變量,依次為前綴、分隔符、后綴、用於處理字符串的StringBuilder、和空值(是這么翻譯吧?)
看到這里大概就反應過來了,原來這個類是對於StringBuilder的再次封裝。
然后,會發現緊隨其后的是兩個構造方法
public StringJoiner(CharSequence delimiter) { this(delimiter, "", ""); } 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(); this.emptyValue = this.prefix + this.suffix; }
可見第一個構造器內部調用了第二個構造器,將第二個構造器的兩個參數設為默認值“”,第二個構造器實際上就是需要使用者傳入分隔符、前綴、后綴,並且空值被設為前綴加后綴。
看到這里大概可以猜測到空值的作用就是在StringJoiner沒有添加任何字符串的情況下,得到的最終值。
public StringJoiner setEmptyValue(CharSequence emptyValue) { this.emptyValue = Objects.requireNonNull(emptyValue, "The empty value must not be null").toString(); return this; }
設置空值,這個方法沒什么好說的
public String toString() { if (value == null) { return emptyValue; } else { 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是StringBuilder對象,如果為null,那么直接返回空值。
如果后綴為“”,直接返回value的toString(),如果后綴不為“”,那么需要將后綴拼接好然后一並返回。
public StringJoiner add(CharSequence newElement) { prepareBuilder().append(newElement); return this; }
然后是比較常用的add方法,內部調用了prepareBuilder()方法,最后返回對象本身,也就實現了鏈式調用。
private StringBuilder prepareBuilder() { if (value != null) { value.append(delimiter); } else { value = new StringBuilder().append(prefix); } return value; }
prepareBuilder()方法也比較簡單,如果沒有StringBuilder對象,那么就創建一個然后添加前綴,如果有,則添加分隔符,返回StringBuilder對象本身。
public StringJoiner merge(StringJoiner other) { Objects.requireNonNull(other); if (other.value != null) { final int length = other.value.length(); // 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; }
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());
}
這兩個方法好像也沒啥好說的... ...
既然StringJoiner實際上使用的仍然是StringBuilder,而在源碼中沒有發現對於線程安全的處理,那么它應該也是非線程安全的。