假设我有一个文本表示为单词行的集合。我希望将单词与空格连接在一起,并使用换行符连接行:
class Word {
String value;
}
public static String toString(List <List <Word>> lines) {
return lines.stream().map(
l -> l.stream().map(w -> w.value).collect(Collectors.joining(" "))
).collect(Collectors.joining("\n"));
}
这很好用,但我最终为每一行创建了一个中间String对象。在没有开销的情况下,有没有一种简洁的方法来做同样的事情?
答案 0 :(得分:5)
String s = List.of(
List.of(new Word("a"), new Word("b")),
List.of(new Word("c"), new Word("d")),
List.of(new Word("e"), new Word("f")))
.stream()
.collect(Collector.of(
() -> new StringJoiner(""),
(sj, list) -> {
list.forEach(x -> sj.add(x.getValue()).add(" "));
sj.add("\n");
},
StringJoiner::merge,
StringJoiner::toString));
修改强>
我可以解决这个问题,但不能告诉你是否同意额外的冗长与创建该字符串:
.stream()
.collect(Collector.of(
() -> new StringJoiner(""),
(sj, list) -> {
int i;
for (i = 0; i < list.size() - 1; ++i) {
sj.add(list.get(i).getValue()).add(" ");
}
sj.add(list.get(i).getValue());
sj.add("\n");
},
StringJoiner::merge,
x -> {
String ss = x.toString();
return ss.substring(0, ss.length() - 1);
}));
答案 1 :(得分:3)
您可以使用
public static String toString(List<List<Word>> lines) {
return lines.stream()
.map(l -> l.stream()
.map(w -> w.value)
.collect(() -> new StringJoiner(" "),
StringJoiner::add,
StringJoiner::merge))
.collect(() -> new StringJoiner("\n"),
StringJoiner::merge,
StringJoiner::merge).toString();
}
内部collect
基本上执行Collectors.joining(" ")
所做的事情,但省略了最后的StringJoiner.toString()
步骤。
然后,外部collect
与普通Collectors.joining("\n")
的不同之处在于它接受StringJoiner
作为输入并使用merge
组合它们。这取决于a documented behavior:
如果另一个
StringJoiner
使用不同的分隔符,则另一个StringJoiner
中的元素与该分隔符连接,结果作为单个元素附加到此StringJoiner
。< / p>
这是在StringBuilder
/字符数据级别内部完成的,无需创建String
实例,同时保留预期的语义。