[英]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.