StringJoiner 类,是 Java 8 新增的一个 API,它基于 StringBuilder 构建,用于实现对字符串之间通过分隔符拼接的场景。
String 类也于 Java 8 新增了两个静态重载方法:join(CharSequence delimiter, CharSequence... elements) : String
、join(CharSequence delimiter,Iterable<? extends CharSequence> elements) : String
,而这两个方法的实现使用的就是 StringJoiner。
API介绍及使用
构造方法
StringJoiner 有两个构造方法,第一个构造要求依次传入分隔符,前缀,后缀。第二个构造则只要求传入分隔符即可,没有前缀和后缀(前缀和后缀默认为空字符串)
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;
}
使用效果如下:
public static void main(String[] args) {
StringJoiner stringJoiner1 = new StringJoiner(" - ");
StringJoiner stringJoiner2 = new StringJoiner(" - ","(",")");
}
add方法
创建好对象之后,我们主要使用的是 StringJoiner 的 add 方法,通过它可以追加要拼接的元素。
add(CharSequence newElement) : StringJoiner
public static void main(String[] args) {
StringJoiner stringJoiner1 = new StringJoiner(" - ");
StringJoiner stringJoiner2 = new StringJoiner(" - ","(",")");
StringJoiner result1 = stringJoiner1.add("hello").add("world"); // hello - world
StringJoiner result2 = stringJoiner1.add("hello").add("world"); // (hello - world)
}
merge方法
如果我们需要合并两个 StringJoiner 的内容,可以使用 merge 方法。
merge(StringJoiner other) : StringJoiner
public static void main(String[] args) {
StringJoiner stringJoiner1 = new StringJoiner(" - ");
StringJoiner stringJoiner2 = new StringJoiner(" - ","(",")");
stringJoiner1.add("hello").add("world");
stringJoiner2.add("hello").add("world");
// hello1 - world1 - hello2 - world2
StringJoiner merge1 = stringJoiner1.merge(stringJoiner2);
// (hello2 - world2 - hello1 - world1 - hello2 - world2)
StringJoiner merge2 = stringJoiner2.merge(stringJoiner1);
}
谁调用则合并时以谁为主
源码解析
首先,在使用 StringJoiner 时,我们会先调用 构造方法 来创建对象,这时候 StringJoiner 会拿着构造参数来初始化它的前缀、分隔符、后缀三个属性,然后将前缀和后缀拼接一下用来初始化 emptyValue 属性,这个属性是用来表示一个元素也未添加过的情况(空值)。
public final class StringJoiner {
// 前缀
private final String prefix;
// 分隔符
private final String delimiter;
// 后缀
private final String suffix;
// StringJoiner本质在使用StringBuilder实现字符串拼接
private StringBuilder value;
// 空值
private String emptyValue;
// 不带前缀和后缀,只指定分隔符来创建StringJoiner
public StringJoiner(CharSequence delimiter) {
this(delimiter, "", "");
}
// 依次指定分隔符、前缀、后缀来创建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;
}
}
随后,当我们执行 add 方法 来添加元素时,有两种不同的处理情况。
如果是添加第一个元素,StringJoiner 会先初始化内部的 StringBuilder,然后用 StringBuilder 依次追加好前缀及第一个元素。
如果不是添加第一个元素,StringJoiner 内部的 StringBuilder 则会依次追加好分隔符及元素。
// 使用StringBuilder追加元素
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement);
return this;
}
// 对内部的StringBuilder进行预处理
// 第一次调用该方法时,初始化StringBuilder并追加前缀
// 第二次及后续调用该方法时,追加分隔符
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter);
} else {
value = new StringBuilder().append(prefix);
}
return value;
}
当我们调用 toString 方法 来获取 StringJoiner 内存储的字符串时,也有两种不同的处理情况。
如果是没有添加过元素,StringJoiner 会直接返回给我们 emptyValue(空值) 属性值。
如果添加过元素,StringJoiner 会判断后缀是否为空字符串,如果后缀为空字符串则直接将内部 StringBuilder 转换为字符串即可;但如果后缀不是空字符串,则首先在 StringBuilder 内追加后缀元素并转换为字符串返回,再之后有点意思的是,StringJoiner 为了让我们调用完 toString 方法后依然可以正常添加元素,它会将 StringBuilder 刚添加的后缀再去除。
// 将StringJoiner内容转换为字符串
@Override
public String toString() {
// 如果StringBuilder为null,说明没有添加过元素
// 返回默认空值
if (value == null) {
return emptyValue;
} else {
// 如果StringBuilder不为null,说明添加过元素
// 判断后缀是否为空字符串
if (suffix.equals("")) {
// 直接返回StringBuilder的字符串内容即可
return value.toString();
} else {
// 如果后缀不是空字符串
// 获取当前StringBuilder的字符串长度
int initialLength = value.length();
// StringBuilder拼接后缀并转换为字符串
String result = value.append(suffix).toString();
// 将StringBuilder拼接的后缀再去除,为了可以后续继续添加元素
value.setLength(initialLength);
return result;
}
}
}
其他方法源码
// 合并其他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;
}
// 获取StringJoiner长度
public int length() {
// 如果StringBuilder不为空,StringBuilder长度 + 后缀长度就是StringJoiner长度
// 后缀在调用toString()方法时才会追加,之所以如此设定,是因为提前拼接后缀会导致无法再追加新元素
return (value != null ? value.length() + suffix.length() :
emptyValue.length());
}
// 设置空值
public StringJoiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue = Objects.requireNonNull(emptyValue,
"The empty value must not be null").toString();
return this;
}
String的join方法
Java 8 中不仅提供了 StringJoiner ,还在 String 类中提供了两个新方法,这两个新方法内部的实现也是通过 StringJoiner
// 将可变参中的元素们通过指定分隔符拼接为字符串
String message = String.join("-", "Java", "is", "cool");
System.out.println(message); // Java-is-cool
// 将集合中的元素通过指定分隔符拼接为字符串
List<String> strings1 = new LinkedList<>();
strings1.add("Java");strings1.add("is");
strings1.add("cool");
String message1 = String.join(" ", strings1);
System.out.println(message1); // Java is cool
Set<String> strings2 = new LinkedHashSet<>();
strings2.add("Java"); strings2.add("is");
strings2.add("very"); strings2.add("cool");
String message2 = String.join("-", strings2);
System.out.println(message2); // Java-is-very-cool
源码解析
String 类新增的两个静态方法,内部实现代码也非常简单,它们都利用的是 StringJoiner 提供的传入分隔符的单参构造,然后通过遍历传入的可变参数或集合来向 StringJoiner 内添加元素,最后将 StringJoiner 转换为字符串返回。
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
// 对字符串列表通过指定分隔符拼接
public static String join(CharSequence delimiter, CharSequence... elements) {
// 参数判空
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
// 创建StringJoiner对象,指定分隔符
StringJoiner joiner = new StringJoiner(delimiter);
// 遍历 可变参 数组,并将元素添加到StringJoiner
for (CharSequence cs: elements) {
joiner.add(cs);
}
// 将StringJoiner转换为字符串
return joiner.toString();
}
// 对集合中的所有元素通过指定分隔符拼接
public static String join(CharSequence delimiter,
Iterable<? extends CharSequence> elements) {
// 参数判空
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
// 创建StringJoiner对象,指定分隔符
StringJoiner joiner = new StringJoiner(delimiter);
// 遍历集合,并将元素添加到StringJoiner
for (CharSequence cs: elements) {
joiner.add(cs);
}
// 将StringJoiner转换为字符串
return joiner.toString();
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/95913.html