Java8流:IntStream到字符串

Java8流:IntStream到字符串,java,java-8,java-stream,Java,Java 8,Java Stream,在Java8StreamsAPI中,对任何String对象调用chars()将返回一个包含所有字符的IntStream对象 将返回的IntStream对象转换回字符串的正确方法是什么?调用toArray()会给我一个int[],这是任何字符串构造函数都不接受的。您可以使用toArray(),然后使用构造函数。这并不完全令人满意,因为指定了chars()返回UTF-16代码单元,基本上: 返回一个int zero流,扩展此序列中的字符值。映射到代理代码点的任何字符都会通过unexported传递

在Java8StreamsAPI中,对任何
String
对象调用
chars()
将返回一个包含所有字符的
IntStream
对象

将返回的
IntStream
对象转换回
字符串的正确方法是什么?调用
toArray()
会给我一个
int[]
,这是任何
字符串
构造函数都不接受的。

您可以使用
toArray()
,然后使用构造函数。这并不完全令人满意,因为指定了
chars()
返回UTF-16代码单元,基本上:

返回一个int zero流,扩展此序列中的字符值。映射到代理代码点的任何字符都会通过unexported传递

改用将更符合此构造函数,它需要代码点而不是UTF-16代码单元。否则(使用
chars
)如果原始字符串确实包含代理项对,您可能会发现出现错误-我没有尝试过,但这是有意义的

我不知道有哪种简单的方法可以不首先转换为数组就完成这项工作

这是另一个想法:

@Test
public void testIntStreamSequential() {
    final String testString = "testmesoftly";
    IntStream is = testString.chars();
    String result = is.collect(
        StringBuilder::new,
        (sb, i) -> sb.append((char)i),
        StringBuilder::append
        ).toString();
    assertEquals(testString, result);
}

@Test
public void testIntStreamParallel() {
    final String testString = "testmesoftly";
    IntStream is = testString.chars();
    String result = is.parallel().collect(
        StringBuilder::new,
        (sb, i) -> sb.append((char)i),
        StringBuilder::append
        ).toString();
    assertEquals(testString, result);
}

请注意,使用@Lii建议的专用
采集器
效率不高,因为它是装箱式的,所以您应该使用这个三参数结构(感谢@holger)

我很确定一定有很多方法可以做到这一点,但另一种方法是使用
StringWriter

IntStream in = "It was the best of times".chars();
StringWriter sw = new StringWriter();
in.forEach(sw::write); 
System.out.println(sw.toString());
这一切也可以在收集器中表示为:

IntStream in = "It was the best of times".chars();
String text = in.collect(
    StringWriter::new, 
    StringWriter::write, 
    (swl, swr) -> swl.write(swr.toString())).toString();
System.out.println(text);

使用
StringBuilder
appendCodePoint
方法也可以做到这一点

IntStream in = "Convert me to a String".codePoints();

String intStreamToString = in.collect(StringBuilder::new,
        StringBuilder::appendCodePoint, StringBuilder::append)
        .toString();

System.out.println(intStreamToString);

哪个类包含
chars()
方法?该方法在
CharSequence
接口中定义,该接口由
String
实现。使用
codePoints()
而不是
chars()
似乎更安全,尽管这对我来说并不重要,因为我只是在ASCII范围内工作。不管怎样,谢谢。我确实考虑过这个方向,但它看起来太复杂了。不过,我有一个简短的问题。为什么第三个参数
(sb1,sb2)->{}
?这到底意味着什么?这个零件根本不用吗?也许它只在使用并行流时才相关?它是组合器,“一个接受两个部分结果并合并它们的函数。”。使用“顺序”时不使用它。然而,我的示例很难看,因此我对其进行了改进,删除了关于并行支持的警告
IntStream
不支持专用的
Collector
s,因此使用三个arg
collect
方法是唯一的选择(除非你想框选每个
int
。@holger你说得对!编辑了我的答案是的,但这一个也有代码单元/代码点不匹配的问题@jon skeet指出。
chars()
返回代码单元流,而
appendCodePoint
希望得到代码点,顾名思义。问题是StringBuilder对象会创建多次。@不,只会创建一个
StringBuilder
,请参见@cdalxndr您说得对!我很困惑。在TerminalOp中只调用了一次。没有想过将其与IO库结合。谢谢。@nullstein,正如我的版本所示,它也可以作为收藏家来写,尽管我怀疑它是否更容易阅读。好的一面是,它确实具有更好的引用透明度,因为副作用对流用户是隐藏的。不过,这最终与StringBuilder的答案类似。请注意,StringWriter是StringBuffer(StringBuilder的同步版本)的包装器,因此(相对而言)比使用StringBuilder慢得多