Java中连接字符串集合的首选习惯用法

Java中连接字符串集合的首选习惯用法,java,string,collections,Java,String,Collections,给定一组字符串,在不使用外部库的情况下,如何在纯Java中连接它们 考虑到这些变量: Collection<String> data = Arrays.asList("Snap", "Crackle", "Pop"); String separator = ", "; String joined; // let's create this, shall we? 以及: 但在普通Java中,真的没有比这更好的方法了吗 StringBuilder sb = new StringBuil

给定一组字符串,在不使用外部库的情况下,如何在纯Java中连接它们

考虑到这些变量:

Collection<String> data = Arrays.asList("Snap", "Crackle", "Pop");
String separator = ", ";
String joined; // let's create this, shall we?
以及:

但在普通Java中,真的没有比这更好的方法了吗

StringBuilder sb = new StringBuilder();
for(String item : data){
    if(sb.length()>0)sb.append(separator);
    sb.append(item);
}
joined = sb.toString();

您的建议是一个可能的解决方案,另一个常见的解决方案是:

for (String item: data) {
    sb.append(item)
    sb.append(separator);
}
String joined = sb.substring(0, sb.length() - separator.length())
爪哇8+
joined=

Java 7及以下版本
可能不是在循环中一次又一次地调用sb.length(),我稍微修改了一下

StringBuilder sb = new StringBuilder();
String separator = "";
for(String item : data){
    sb.append(separator);
    separator=",";
    sb.append(item);
}
joined = sb.toString();
不同的意图:

对于第三方工具,例如Guava的
Joiner
,它速度不快,但非常灵活。有许多选项方法可以自定义联接行为,例如
skipNulls()

普通Java速度很快,但它需要你自己编写几行代码。

我想说,不使用Guava的最好方法(如果你不是说“最简洁”)是使用Guava内部使用的技术,在你的示例中,它看起来像这样:

Iterator<String> iter = data.iterator();
StringBuilder sb = new StringBuilder();
if (iter.hasNext()) {
  sb.append(iter.next());
  while (iter.hasNext()) {
    sb.append(separator).append(iter.next());
  }
}
String joined = sb.toString();
Iterator iter=data.Iterator();
StringBuilder sb=新的StringBuilder();
if(iter.hasNext()){
sb.append(iter.next());
while(iter.hasNext()){
sb.append(分隔符).append(iter.next());
}
}
连接的字符串=sb.toString();
这不必在迭代时进行布尔检查,也不必对字符串进行任何后处理。

在Java 8中:

String.join (separator, data)
如果您想
过滤
映射
您的数据,可以加入该功能,这非常有用

String joined = Stream.of("Snap", "Crackle", "Pop")
        .map(String::toUpperCase)
        .collect(Collectors.joining(", "));
要从集合中获取流,请调用它:


看,@Sébastien这些问题没有一个答案比我的短,也没有使用外部图书馆。上的公认答案确实回答了你的问题:没有,除了第三方库之外,没有更好的方法可以做到这一点。事实上,没有简单干净的方法可以做到这一点,这就解释了为什么必须将它添加到所有这些库中。@Kevin,所有人都知道:-)更像:
sb.substring(0,sb.length()-separator.length())
。但我认为这是一个糟糕的黑客行为。事实上,您必须在黑客(通常是无用的测试)和使用迭代器提取列表的第一个成员之间进行选择。没有完美的解决方案。我不喜欢使用
if(first)
,因为它不必要地冗长,但我必须同意
if(!first | |(first=false))
很漂亮(+1)我本来打算给@Suresh s打勾,但我不喜欢当前的编辑,所以这里不再使用第一个示例,您可以这样做:
joined=data.toString().substring(1,joined.length()-2)
@DanKing,在为
已加入的
分配有意义的数据之前,不能使用
已加入的.length()
。完全正确@aioobe-我去拿外套!;-)虽然我注意到,自从我发表评论以来,你已经完全改变了你的答案,所以不管怎么说,它不再有意义了——如果它一开始是正确的,但事实并非如此……为什么要编辑?旧的基于字符串的版本更灵活,新版本在开头添加了不必要的空间。对不起,过早优化太多:)我也是这样做的。它避免了额外的
if
,而支持额外的非条件语句,这使得它在Bob-Martin的“转换优先级前提”(Transformation-Priority-Premise)框架中更可取。它的执行速度也可能更快(分支在处理器中会有性能损失,而重复赋值的成本可能很小;循环展开器也可能更容易优化这种形式的额外语句)。我想说,
Joiner
非常快,特别是如果您对特定分隔符重复使用预构建的
连接符
。它使用一个
StringBuilder
来构建建筑,并且它有一个非常有趣的方法来确保它只在正确的位置添加一个分隔符,而不需要每次迭代都进行任何布尔检查。
Iterator<String> iter = data.iterator();
StringBuilder sb = new StringBuilder();
if (iter.hasNext()) {
  sb.append(iter.next());
  while (iter.hasNext()) {
    sb.append(separator).append(iter.next());
  }
}
String joined = sb.toString();
String.join (separator, data)
String joined = Stream.of("Snap", "Crackle", "Pop")
        .map(String::toUpperCase)
        .collect(Collectors.joining(", "));
Arrays.asList("Snap", "Crackle", "Pop").stream()