既然我们已经有了 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?的主要内容,如果未能解决你的问题,请参考以下文章

当我们已经有了一阶逻辑时,为啥还需要 PDDL?

为啥我们已经有了 mapDispatchToProps 还需要 redux-thunk

浅析StringStringBuilderStringBuffer

有字符串时为啥要使用 StringBuilder?

C# stringbuilder为啥高效

为啥使用 StringBuilder? StringBuffer 可以与多个线程以及一个线程一起使用吗?