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(","));