字符串拼接新姿式——Java 8 StringJoiner
前言
日常工作中拼接字符串肯定是我们少不了的操作,最近工作中正好用到了,然后想起前几天看到的Java 8的一个新类:StringJoiner类,所以今天正好来看一看它的源码。
正文
用法简介
这个类的用法其实很简单,我们可以看到源码中给出的例子:
StringJoiner sj = new StringJoiner(":", "[", "]"); sj.add("George").add("Sally").add("Fred"); String desiredString = sj.toString();
我们把这个字符串最终打印出来:
[George:Sally:Fred]
所以基本上能看出一点用法了: 通过带参构造器构造出一个StringJoiner的对象,调用add方法开始拼接字符串,构造器中的参数会决定拼接的字符串的前后缀以及中间的连接符,最终调用toString方法转换为String对象。
一张图总览下这个类里都有些什么,后面逐一解释。
参数
StringJoiner总共有五个参数:
private final String prefix; //前缀 private final String delimiter; //分隔符 private final String suffix; //后缀 private StringBuilder value; private String emptyValue;
后两个参数很有意思
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总共有两个构造器:
先看参数多的
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的对象就是你的前缀+后缀。 例子:
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而已嘛。不过有人帮你封装好了加减后缀和连接符的方法也是好的!

浙公网安备 33010602011771号