Java 以更优雅的方式重复并连接已知字符串未知次数

Java 以更优雅的方式重复并连接已知字符串未知次数,java,java-8,Java,Java 8,我的目标是使用分隔符连接已知字符串,连接次数未知 因此,如果我知道字符串是?,分隔符是,,并且我知道我希望它重复5次,我会得到,,,,,,,,,,,,,,,,,,, 此代码将执行以下操作: int n = 5; ArrayList<String> al = new ArrayList<>(n); for (int i = 0; i < n; ++i) al.add("?"); String s = String.join(",", al); int n=5; Ar

我的目标是使用分隔符连接已知字符串,连接次数未知

因此,如果我知道字符串是
,分隔符是
,并且我知道我希望它重复
5次,我会得到
,,,,,,,,,,,,,,,,,,,

此代码将执行以下操作:

int n = 5;
ArrayList<String> al = new ArrayList<>(n);
for (int i = 0; i < n; ++i) al.add("?");
String s = String.join(",", al);
int n=5;
ArrayList al=新的ArrayList(n);
对于(int i=0;i

但这太冗长了。我是否缺少Java8库中的某些内容?请不要附加依赖项。

这在Java 8中不是新的,但您可以使用创建一个
列表
,您可以将其传递到
String.join
。自从在Java1.2中创建CollectionsAPI以来,它就一直存在

String s = String.join(",", Collections.nCopies(5, "?"));

基于流的解决方案,仅为了完整性:

String s = Stream.generate(() -> "?").limit(5).collect(joining(","));
如果需要性能,可以手动设计速度更快(最多10倍)的解决方案:

public static String nCopies(String symbol, String delimiter, int count) {
    if(count <= 0) return "";
    char[] result = new char[(symbol.length()+delimiter.length())*count-delimiter.length()];
    fill(result, symbol, delimiter, count);
    return new String(result);
}

private static void fill(char[] result, String symbol, String delimiter, int count) {
    if(count == 1) {
        symbol.getChars(0, symbol.length(), result, 0);
        return;
    }
    int half = count/2;
    int filled = (symbol.length()+delimiter.length())*half-delimiter.length();
    if(count % 2 == 0) {
        fill(result, symbol, delimiter, half);
        delimiter.getChars(0, delimiter.length(), result, filled);
        System.arraycopy(result, 0, result, filled+delimiter.length(), filled);
        return;
    }
    fill(result, symbol, delimiter, half);
    int offset = filled;
    delimiter.getChars(0, delimiter.length(), result, offset);
    offset+=delimiter.length();
    symbol.getChars(0, symbol.length(), result, offset);
    offset+=symbol.length();
    delimiter.getChars(0, delimiter.length(), result, offset);
    offset+=delimiter.length();
    System.arraycopy(result, 0, result, offset, filled);
}

无需具体化
集合
(且并行化效果优于生成/限制示例):


我的观点有些可疑:对于
n=10000
limit版本,其性能优于range版本,但对于
n=1000000
range版本,其性能优于range版本。请注意,为了获得最佳并行性能,您需要显式指定
unordered()
(这在limit版本中不是必需的)。如果有人真的关心性能,那么就有可能设计出一个顺序解决方案,这个解决方案的速度要快很多(参见基线测试,使用不安全的字符串创建会更快)。@TagirValeev再次查看规范,这是因为
generate()
生成了一个无序流,而
limit()
(通常会同时导致灾难)的常见缺陷通过无序性得到缓解。所以这两种方法相互抵消了。实现管道阶段真的有那么难吗?要理解前一个阶段是否是无限的(这意味着limit()会将它们变成一个完美大小的流)?在我看来,这似乎是一个疏忽,类似于在调用
count()
时不使用Size属性…@Holger您需要一个已知的流标志;仅仅看前一阶段是不够的。这样的旗帜被考虑过。(本质上,这只是为了提高极限())@Brian Goetz:这就是我的意思,这就是特征。但是每个阶段都可能会修改它们,例如
limit()
将假设的
KNOWN\u INFINITE
转换为
size
。当它被考虑时,为什么它会被丢弃?这似乎不会给实现带来巨大的成本。我希望这是未来jdk中
String.join
的签名之一。
String s = nCopies("?", ",", 5);
IntStream.range(0, 5).mapToObj(i -> "?").collect(joining(","));