StringJoiner是java.util包下的一個工具類,jdk1.8出來的
作用是在構造字符串時,可以自動添加前綴、后綴及分隔符,而不需要自己去實現這些添加字符的邏輯
先看一個簡單的demo
StringJoiner sj1 = new StringJoiner(",");
StringJoiner sj2 = new StringJoiner(",", "[", "]");
System.out.println(sj1.add("a").add("b").add("c"));
System.out.println(sj2.add("a").add("b").add("c"));
System.out.println(sj1.merge(sj2));
System.out.println(sj2.merge(sj1));
System.out.println(sj1.length());

StringJoiner有兩個構造方法
-
只傳入分隔符
public StringJoiner(CharSequence delimiter) { // 這里只是調用了第二個構造方法,前綴和后綴傳入空字符串,表示沒有前后綴 this(delimiter, "", ""); } -
傳入分隔符,還有前綴和后綴
public StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix) { // 做了以下判斷,如果分隔符,前后綴為null,則拋出NullPointerException異常 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"); // 賦值給當前對象的屬性 this.prefix = prefix.toString(); this.delimiter = delimiter.toString(); this.suffix = suffix.toString(); this.emptyValue = this.prefix + this.suffix; }
成員屬性,其實StringJoiner主要是通過維護了一個StringBuilder對象value去添加元素的
// 當前StringJoiner對象前綴
private final String prefix;
// 每個添加元素的分隔符
private final String delimiter;
// 當前StringJoiner對象后綴
private final String suffix;
// 前綴+元素+分隔符+后綴的值,如果沒有添加元素,那么value是null
private StringBuilder value;
// 前綴+后綴的值,如果沒有前后綴,那么這個值為空字符串,可以理解為value的副本,在value為null時,用它來代替
private String emptyValue;
方法描述及源碼分析
-
public StringJoiner add(CharSequence newElement):添加一個元素,初始化value的工作也是在這里做的,如果當前StringJoiner沒有調用過一次add方法,那么value為nullpublic StringJoiner add(CharSequence newElement) { // 在此調用prepareBuilder方法,prepareBuilder會自動判斷value是否已經初始化,並添加好分隔符 prepareBuilder().append(newElement); return this; } -
private StringBuilder prepareBuilder():在調用add方法時會自動調用,判斷value是否為null,如果不為null,直接添加分隔符。如果為null,構造一個StringBuilder對象,初始值為prefix。private StringBuilder prepareBuilder() { // 如果不為null,在添加元素前添加分隔符 if (value != null) { value.append(delimiter); } else { // 反之,構建StringBuilder對象,初始值為prefix value = new StringBuilder().append(prefix); } return value; } -
public StringJoiner merge(StringJoiner other):合並一個StringJoiner對象到當前StringJoiner對象public StringJoiner merge(StringJoiner other) { Objects.requireNonNull(other); if (other.value != null) { final int length = other.value.length(); StringBuilder builder = prepareBuilder(); // 將傳過來的StringJoiner對象拼接到末尾 builder.append(other.value, other.prefix.length(), length); } return this; } -
public int length():如果value不為null,當前值=value的長度+suffix的長度,如果為null,返回emptyValue的長度public int length() { // 如果value為null,返回emptyValue的長度,反之返回value的長度 return (value != null ? value.length() + suffix.length() : emptyValue.length()); } -
public String toString():如果value不為null,返回value+suffix的值,如果為null,返回emptyValue@Override public String toString() { // value為null用emptyValue來代替 if (value == null) { return emptyValue; } else { // 沒有后綴直接返回value字符串 if (suffix.equals("")) { return value.toString(); } else { // 有后綴需要在toString里面再補上,把當前對象作為字符串使用時,toString方法會自動調用 int initialLength = value.length(); String result = value.append(suffix).toString(); // reset value to pre-append initialLength value.setLength(initialLength); return result; } } }
如果是想將一個list中的元素快速的以這種方式添加,可以通過String.join來實現
// 第一個參數是分隔符,第二個參數是list
System.out.println(String.join(",", Arrays.asList("a", "b", "c")));
// 第二個參數是可變數組
System.out.println(String.join(",", "a", "b", "c"));

String.join方法也是jdk1.8出來的
查看String.join的源碼可以看見,里面其實就是構建了一個StringJoiner對象,它只指定了分隔符,所以String.join不能實現有前后綴的情況
public static String join(CharSequence delimiter,
Iterable<? extends CharSequence> elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
// 構建了一個指定分隔符的StringJoiner對象
StringJoiner joiner = new StringJoiner(delimiter);
// 循環添加list中的元素
for (CharSequence cs: elements) {
joiner.add(cs);
}
return joiner.toString();
}
如果想處理list添加前后綴的問題,可以通過list的stream流的collect方法來處理,需要配合Collectors.joining方法
Collectors.joining(CharSequence delimiter);
Collectors.joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix);
將list通過stream方法轉成流之后調用collect來返回想要的結果集
List<String> list1 = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("a", "b", "c");
System.out.println(list1.stream().collect(Collectors.joining(",")));
System.out.println(list2.stream().collect(Collectors.joining(",", "[", "]")));

查看Collectors.joining源碼實現,發現其中也是維護了一個StringJoiner實例去做這些事
public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix) {
return new CollectorImpl<>(
() -> new StringJoiner(delimiter, prefix, suffix),
StringJoiner::add, StringJoiner::merge,
StringJoiner::toString, CH_NOID);
}
