平常工做中拼接字符串確定是咱們少不了的操做,最近工做中正好用到了,而後想起前幾天看到的Java 8的一個新類:StringJoiner類,因此今天正好來看一看它的源碼。bash
這個類的用法其實很簡單,咱們能夠看到源碼中給出的例子:app
StringJoiner sj = new StringJoiner(":", "[", "]");
sj.add("George").add("Sally").add("Fred");
String desiredString = sj.toString();
複製代碼
咱們把這個字符串最終打印出來:less
[George:Sally:Fred]
複製代碼
因此基本上能看出一點用法了: 經過帶參構造器構造出一個StringJoiner的對象,調用add方法開始拼接字符串,構造器中的參數會決定拼接的字符串的先後綴以及中間的鏈接符,最終調用toString方法轉換爲String對象。ide
一張圖總覽下這個類裏都有些什麼,後面逐一解釋。ui
StringJoiner總共有五個參數:this
private final String prefix; //前綴
private final String delimiter; //分隔符
private final String suffix; //後綴
private StringBuilder value;
private String emptyValue;
複製代碼
後兩個參數頗有意思spa
private StringBuilder value;
實際上是Joiner的底層,說到底StringJoiner仍是調用的StringBuiler方法,只是這層封裝里加上了有關於前綴,後綴和鏈接符的操做,讓咱們能夠方便一些。
複製代碼
private String emptyValue;
emptyValue 你能夠把它看做是當你的StringJoiner對象沒有進行任何add的操做時,調用toString() 方法會return 這個字符串而不是空。具體的用法後面看到setEmptyValue的時候再舉例子。
複製代碼
看下源碼註釋:指針
/*
* 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.
*/
複製代碼
從大綱裏能夠看到StringJoiner總共有兩個構造器:code
先看參數多的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;
}
複製代碼
這裏面三個參數分別是前綴後綴和鏈接符,而後這裏有一個操做就是將emptyValue賦值了前綴+後綴的字符串。也就是說當你用了這個構造器的時候,emptyValue就已經有值了,就是前綴+後綴拼接。當你StringJoiner不執行add方法直接toString()時,會return的對象就是你的前綴+後綴。 例子:cdn
public static void main (String [] args) {
StringJoiner sj = new StringJoiner(":", "[", "]");
String desiredString = sj.toString();
System.out.println(desiredString);
}
複製代碼
這裏打印結果就是[]
。
再看只有一個參數的構造器:
public StringJoiner(CharSequence delimiter) {
this(delimiter, "", "");
}
複製代碼
其實仍是調用的三參構造器,只不過先後綴默認值爲"",也就是沒有先後綴。這種狀況下emptyValue是什麼呢? 其實和上面同樣的,""+""就是"",不難理解。
先看上面提到最多的toString().
@Override
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爲空)時,會return emptyVaule, 若是不爲空,就會加上一個給你加後綴的操做。固然這裏加後綴你能夠看做一次性的,他在加以前會取一個長度,無論你後綴多長,加完以後會set到初始長度。
知道了後綴是這裏加的,那前綴呢。
來看最核心的 add方法:
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement);
return this;
}
複製代碼
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter);
} else {
value = new StringBuilder().append(prefix);
}
return value;
}
複製代碼
前綴就是在你調用第一個add的時候就加上了,爲何是第一個呢,由於第一次調用add的時候,你的value確定是空的,因此它會走else的邏輯給你構造一個StringBuilder出來,這個時候會把前綴加好。因此你後面無論有幾個add,都是基於一個StringBuilder上在加字符串。當你的value不爲空了,就會給你拼接上鍊接符,最後再拼接上add()方法裏的參數。完美。
再結合toString方法來看,當你沒有調用過add方法而直接toString時,value爲空,它就會return emptyValue了。
再來看個和emptyValue有關的方法setEmptyValue(CharSequence emptyValue):
public StringJoiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue = Objects.requireNonNull(emptyValue,
"The empty value must not be null").toString();
return this;
}
複製代碼
這個方法實際上是暴露給開發者主動設置emptyValue值的方法,也就是說,當你沒有調用set方法,emptyValue默認值爲前綴+後綴,無論先後綴是否爲空;當你調用了set方法,emptyValue就是設置的值。 舉個例子:
public static void main (String [] args) {
StringJoiner sj = new StringJoiner(":", "[", "]");
sj.setEmptyValue("anson");
String desiredString = sj.toString();
System.out.println(desiredString);
}
複製代碼
這裏的打印結果就是anson
,注意不是[anson]
哦。
還有一個有關字符串操做的方法 merge(StringJoiner)
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;
}
複製代碼
這裏面調用了一個StringBuilder的append()重載方法:
public StringBuilder append(CharSequence s, int start, int end) {
super.append(s, start, end);
return this;
}
複製代碼
也就是說merge操做是把另外一個StringJoiner(簡稱sj2)的從前綴開始(不包括前綴)包括鏈接符可是不包括後綴的字符串加進去sj1裏面。
上個例子:
public static void main (String [] args) {
StringJoiner sj1 = new StringJoiner(":","[","]");
StringJoiner sj2 = new StringJoiner(",","{","}");
sj1.add("b");
sj2.add("a").add("c");
sj1.merge(sj2);
String desiredString = sj1.toString();
System.out.println(desiredString);
}
複製代碼
打印結果:[b:a,c]
先後綴都是sj1的,ac間的鏈接符是sj2的。
最後再看個簡單的方法收尾
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方法也就是沒有初始化StringBuilder時,調用這個方法不會空指針,由於有默認的emptyValue。
總結一下,Java 8的新類StringJoiner用法很簡單,其實就是一個披着StringJoiner皮的StringBuilder而已嘛。不過有人幫你封裝好了加減後綴和鏈接符的方法也是好的!