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

我有数组["a", "b", "c"],我想将它们连接在一起形成“a#b#c#”。String.join 只会让我“a#b#c”。我不能只是这样做str += "#",因为这很慢(Java 必须创建一个新字符串才能做到这一点)。因此,我必须使用StringBuilder. Java 是否有一些方法基本上是 String.join,但还将分隔符附加到末尾?

对于更多的上下文,我正在尝试使用一组字符串创建一个后缀数组数据结构,因此这部分实际上是一个瓶颈。

回答

您可以使用 Stream API Collectors.joining() 有这样的前缀和后缀参数:

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

其中加入参数分别是定界符、前缀、后缀。

此外,您可以像上面评论中的@Wander Nauta 所说的那样,将一个空字符串添加到您的数组中

我已经启动了 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();
  }
}

结果:

> 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

但是您必须明白,nSec对于大多数应用程序来说,46是一个非常小的差异。

  • 我喜欢这个解决方案,但如果 OP 担心 `+=` 比我假设的 Stream 与收集器也太慢。
  • @KarolDowbecki 你认为收集器在内部使用什么?它实际上与您的答案相同。
  • @DmitriiBykov 当然可以/应该采用相同的方法进行直接连接。

回答

以下是使用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

在与流解决方案需要大约2.5倍相比,长与解决方案StringJoiner。在中场正如预期的那样连接连接(见问题)。然而,我们在这里谈论的是纳秒。

显示具有重新计算值 ( 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();
    }
}


以上是JavaString.join还要在末尾添加分隔符的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>