平常工做中拼接字符串确定是咱们少不了的操做,最近工做中正好用到了,而后想起前几天看到的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而已嘛。不过有人帮你封装好了加减后缀和链接符的方法也是好的!