既然我们已经有了 StringBuilder,为啥还要使用 StringJoiner?
Posted
技术标签:
【中文标题】既然我们已经有了 StringBuilder,为啥还要使用 StringJoiner?【英文标题】:Why StringJoiner when we already have StringBuilder?既然我们已经有了 StringBuilder,为什么还要使用 StringJoiner? 【发布时间】:2015-02-15 19:44:39 【问题描述】:我最近遇到了一个 Java 8 类 StringJoiner
,它使用分隔符添加字符串并为其添加前缀和后缀,但我无法理解此类的需要,因为它还在后端使用 StringBuilder
并且还执行非常简单的附加字符串操作。
我是不是因为没有真正理解这门课的真正目的而错过了什么?
【问题讨论】:
实现简单并不排除作为一个类单独执行时有用。尤其是考虑到多久应用程序程序员必须手动(或通过第 3 方库)进行类似操作。 【参考方案1】:StringJoiner
非常有用,当您需要在Stream
中加入字符串时。
例如,如果您必须遵循字符串列表:
final List<String> strings = Arrays.asList("Foo", "Bar", "Baz");
使用起来更简单
final String collectJoin = strings.stream().collect(Collectors.joining(", "));
就像StringBuilder
一样:
final String collectBuilder =
strings.stream().collect(Collector.of(StringBuilder::new,
(stringBuilder, str) -> stringBuilder.append(str).append(", "),
StringBuilder::append,
StringBuilder::toString));
6 年后编辑
正如 cmets 中所述,现在有更简单的解决方案,例如 String.join(", ", strings)
,当时还没有这些解决方案。但是用例还是一样的。
【讨论】:
请注意,这两个示例不相同!第一个生成字符串"foo, Bar, Baz"
,第二个生成"foo, Bar, Baz, "
。
@PaulWagland 是的,这就是.joining
的额外美感。通常,您不需要最后一个逗号...
@Koshinae 完全同意,在流式传输的情况下修复它也会使已经很复杂的语句变得更加复杂!
String.join(", ", strings)
是strings.stream().collect(Collectors.joining(", "))
的更快版本
怎么样:list.stream().map(Util::quote).collect(Collectors.joining(","))
?【参考方案2】:
StringJoiner Javadoc 上的示例非常擅长涵盖这一点。整个要点是从添加条目的行为中抽象出分隔符的选择。例如您可以创建一个连接器,指定要使用的分隔符并将其传递给库以添加元素,反之亦然。
字符串“[George:Sally:Fred]”可以如下构造:
StringJoiner sj = new StringJoiner(":", "[", "]"); sj.add("George").add("Sally").add("Fred"); String desiredString = sj.toString();
StringJoiner 可用于使用 Collectors.joining(CharSequence) 从 Stream 创建格式化输出。例如:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4); String commaSeparatedNumbers = numbers.stream() .map(i -> i.toString()) .collect(Collectors.joining(", "));
【讨论】:
Peter,您对 StringBuilder 与 StringJoiner 的性能进行了基准测试吗?从这方面来说,你更喜欢哪一个? @Simeon 如果我想要在我附加的每个内容之间使用隐式分隔符,我会使用字符串连接器,如果不是,则使用字符串构建器。这与性能无关,而是使期望的操作更清晰。【参考方案3】:它可能会在某些用例中简化您的代码:
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 有一个接收 List 或 Collection 的方法并在内部进行迭代 + 添加每个元素,那就太好了。【参考方案4】:StringJoiner
是一种收集器,尽管它没有实现Collector
接口。它只是表现得如此。除了可以传递分隔符、前缀和后缀之外,StringJoiner
还可以用于从 Stream
调用 Collectors.joining(CharSequence)
创建格式化输出。
这在处理并行流时特别有用,因为在某些时候并行处理的批次需要加入,这就是@ 987654326@ 发生。
【讨论】:
不完全是。它是一个适合在 Collector 中使用的低级实用程序组件(joining() 实际上确实使用它),但也适用于 Streams 世界之外。人们一直在编写这类循环。【参考方案5】:StringJoiner 比使用 StringBuilder 简单得多。一个很简单的代码就像
StringJoiner sj = new StringJoiner(",");
sj.add("aaa");
sj.add("bbb");
sj.add("ccc");
String result = sj.toString(); //aaa,bbb,ccc
【讨论】:
以上是关于既然我们已经有了 StringBuilder,为啥还要使用 StringJoiner?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我们已经有了 mapDispatchToProps 还需要 redux-thunk