简体   繁体   English

Java String.join 还要在末尾添加分隔符

[英]Java String.join but also add delimiter to the end

I have the array ["a", "b", "c"] and I want to join them together to form "a#b#c#".我有数组["a", "b", "c"]并且我想将它们连接在一起形成“a#b#c#”。 String.join will only get me "a#b#c". String.join 只会让我“a#b#c”。 I can't just do str += "#" either because that is slow (Java has to create a new string to do that).我不能只做str += "#" ,因为这很慢(Java 必须创建一个新字符串才能做到这一点)。 So instead I have to rewrite the whole thing using StringBuilder .因此,我必须使用StringBuilder重写整个过程。 Is there some method Java has that is basically String.join but also appends the delimiter to the end? Java 是否有一些方法基本上是 String.join,但还将分隔符附加到末尾?

For a little more context, I'm trying to create a Suffix Array data structure with a group of strings, so this part of it is actually a bottleneck.对于更多的上下文,我正在尝试使用一组字符串创建一个后缀数组数据结构,因此这部分实际上是一个瓶颈。

You can use Stream API Collectors.joining() There are prefix and suffix arguments like that:您可以使用 Stream API Collectors.joining() 有这样的前缀和后缀参数:

    Stream.of("a", "b", "c")
        .collect(Collectors.joining("#", "", "#"));

Where joining arguments is delimiter, prefix, suffix respectively.其中加入参数分别是定界符、前缀、后缀。

Also, you can just add an empty String to your array like says @Wander Nauta in the comment above此外,您可以像上面评论中的@Wander Nauta 所说的那样,将一个空字符串添加到您的数组中

I've started JMH, also and reproduce performance differences which wrote bellow :我已经启动了 JMH,并重现了如下写的性能差异:

public class Benchmarks {

private static final String[] arr = {"a", "b", "c"};

@Benchmark
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(value = 1, warmups = 1)
@BenchmarkMode(Mode.AverageTime)
public String joinAndConcat() {
    return String.join("#", arr) + "#";
}

@Benchmark
@Fork(value = 1, warmups = 1)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public String streamsJoining() {
    return Stream.of(arr)
            .parallel()
            .collect(Collectors.joining("#", "", "#"));
}

@Benchmark
@Fork(value = 1, warmups = 1)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public String stringJoiner() {
    StringJoiner joiner = new StringJoiner("#", "", "#");
    for (String el : arr) {
        joiner.add(el);
    }
    return joiner.toString();
  }
}

Results:结果:

> Benchmark                  Mode  Cnt   Score   Error  Units
> Benchmarks.joinAndConcat   avgt    5  46,670 ± 0,139  ns/op
> Benchmarks.streamsJoining  avgt    5  73,336 ± 0,180  ns/op
> Benchmarks.stringJoiner    avgt    5  27,236 ± 0,386  ns/op

But you must understand that 46 nSec is a very small difference for most applications.但是您必须明白,对于大多数应用程序来说,46 nSec只是一个很小的差异。

Here are the performance measures using JMH :以下是使用JMH的性能指标:

Benchmark       Mode   Cnt         Score        Error  Units
StringJoiner    thrpt  100  23641181.522 ± 237176.955  ops/s
JoinAndConcat   thrpt  100  14197523.377 ± 130873.538  ops/s
StreamsJoining  thrpt  100   9538282.522 ± 156729.920  ops/s

The solution with streams takes around 2.5x longer compared to the solution with StringJoiner .使用StringJoiner解决方案相比,使用流解决方案需要大约2.5 倍的时间。 In the midfield is as expected the join with concatenation (see question).在中场正如预期的那样连接连接(见问题)。 However, we are talking about nanoseconds here.然而,我们在这里谈论的是纳秒。

A graphical overview showing the performance with recalculated values ( ops/s => ns/op ):显示重新计算值的性能的图形概览 ( ops/s => ns/op ): 结果


# JMH version: 1.32
# VM version: JDK 11.0.11, OpenJDK 64-Bit Server VM, 11.0.11+9
# VM invoker: /Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home/bin/java
# VM options: <none>
# Blackhole mode: full + dont-inline hint
# Warmup: 10 iterations, 1 s each
# Measurement: 10 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
import java.util.StringJoiner;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openjdk.jmh.annotations.Benchmark;

public class Benchmarks {

    private static final String[] arr = {"a", "b", "c"};

    @Benchmark
    public String joinAndConcat() {
        return String.join("#", arr) + "#";
    }

    @Benchmark
    public String streamsJoining() {
        return Stream.of(arr)
                .collect(Collectors.joining("#", "", "#"));
    }

    @Benchmark
    public String stringJoiner() {
        StringJoiner joiner = new StringJoiner("#", "", "#");
        for (String el : arr) {
            joiner.add(el);
        }
        return joiner.toString();
    }
}

String.join() uses StringJoiner behind the scenes so you can create one and specify suffix parameter as # in the constructor: String.join()在幕后使用StringJoiner ,因此您可以创建一个并在构造函数中将suffix参数指定为#

String[] array = { "a", "b", "c" };
StringJoiner joiner = new StringJoiner("#", "", "#");
for (String el : array) {
  joiner.add(el);
}
System.out.println(joiner.toString()); // a#b#c#

However this feels like micro optimizing.然而,这感觉就像微优化。 Unless your joining code is critical it's way more readable to write:除非您的加入代码很重要,否则编写起来更具可读性:

String[] array = { "a", "b", "c" };
System.out.println(String.join("#", array) + "#"); // a#b#c#

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM