既然我们已经有了 StringBuilder,为什么还要用 StringJoiner 呢?

我最近遇到了一个 Java 8类 StringJoiner,它使用分隔符添加字符串,并为其添加前缀和后缀,但我不能理解这个类的需要,因为它在后端也使用 StringBuilder,并且还执行非常简单的附加字符串的操作。

我没有真正理解这门课的真正目的,是不是遗漏了什么?

47971 次浏览

The examples on the StringJoiner Javadoc are very good at covering this. The whole point to to abstract away the choice of seperator from the act of adding entries. e.g. you can create a joiner, specify the seperator to use and pass it to a library to do the adding of elements or visa versa.

The String "[George:Sally:Fred]" may be constructed as follows:

StringJoiner sj = new StringJoiner(":", "[", "]");
sj.add("George").add("Sally").add("Fred");
String desiredString = sj.toString();

A StringJoiner may be employed to create formatted output from a Stream using Collectors.joining(CharSequence). For example:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String commaSeparatedNumbers = numbers.stream()
.map(i -> i.toString())
.collect(Collectors.joining(", "));

StringJoiner is a kind of a Collector, although it doesn't implement the Collector interface. It just behaves as such. Besides you can pass delimiter, prefix and suffix, the StringJoiner may be employed to create formatted output from a Stream invoking Collectors.joining(CharSequence).

This is especially useful when working with parallel streams, because at some point the batches that are being process in parallel will need to be joined and this is where the StringJoiner takes place.

It may simplify your code in some use cases:

List<String> list = // ...;


// with StringBuilder
StringBuilder builder = new StringBuilder();
builder.append("[");
if (!list.isEmpty()) {
builder.append(list.get(0));
for (int i = 1, n = list.size(); i < n; i++) {
builder.append(",").append(list.get(i));
}
}
builder.append("]");


// with StringJoiner
StringJoiner joiner = new StringJoiner(",", "[", "]");
for (String element : list) {
joiner.add(element);
}

StringJoiner is very useful, when you need to join Strings in a Stream.

As an example, if you have to following List of Strings:

final List<String> strings = Arrays.asList("Foo", "Bar", "Baz");

It is much more simpler to use

final String collectJoin = strings.stream().collect(Collectors.joining(", "));

as it would be with a StringBuilder:

final String collectBuilder =
strings.stream().collect(Collector.of(StringBuilder::new,
(stringBuilder, str) -> stringBuilder.append(str).append(", "),
StringBuilder::append,
StringBuilder::toString));

EDIT 6 years later As noted in the comments, there are now much simpler solutions like String.join(", ", strings), which were not available back then. But the use case is still the same.

StringJoiner is far simpler than using StringBuilder. A very simple code is like

StringJoiner sj = new StringJoiner(",");
sj.add("aaa");
sj.add("bbb");
sj.add("ccc");
String result = sj.toString(); //aaa,bbb,ccc