将`IntStream`打印为`String`的最简单方法

问题描述 投票:39回答:7

使用Java-8,我可以使用StringCharSequence方法轻松地将IntStream(或任何chars)视为codePoints

IntStream chars = "Hello world.".codePoints();

然后我可以操纵流的内容

IntStream stars = chars.map(c -> c == ' ' ? ' ': '*');

我一直在寻找一种整洁的方式来打印结果,我甚至找不到一个简单的方法。我怎么把这个ints流回到一个可以打印的形式,就像我可以String

从上面的stars我希望打印

***** ******
java java-8 java-stream
7个回答
32
投票
String result = "Hello world."
  .codePoints()
//.parallel()  // uncomment this line for large strings
  .map(c -> c == ' ' ? ' ': '*')
  .collect(StringBuilder::new,
           StringBuilder::appendCodePoint, StringBuilder::append)
  .toString();

但是,"Hello world.".replaceAll("[^ ]", "*")更简单。并非一切都受益于lambdas。


18
投票

Holger的效率稍低但更简洁的解决方案:

String result = "Hello world."
    .codePoints()
    .mapToObj(c -> c == ' ' ? " ": "*")
    .collect(Collectors.joining());

Collectors.joining()内部使用StringBuilder,至少在OpenJDK sources


6
投票

其他答案显示如何将字符串流收集到单个字符串以及如何从IntStream收集字符。此答案显示如何在字符流上使用自定义收集器。

如果你想将一个int流收集到一个字符串中,我认为最干净,最通用的解决方案是创建一个返回收集器的静态实用程序方法。然后你可以像往常一样使用Stream.collect方法。

可以像这样实现和使用此实用程序:

public static void main(String[] args){
    String s = "abcacb".codePoints()
        .filter(ch -> ch != 'b')
        .boxed()
        .collect(charsToString());

    System.out.println("s: " + s); // Prints "s: acac"
}

public static Collector<Integer, ?, String> charsToString() {
    return Collector.of(
        StringBuilder::new,
        StringBuilder::appendCodePoint,
        StringBuilder::append,
        StringBuilder::toString);
}

标准库中没有类似的东西,这有点令人惊讶。

这种方法的一个缺点是它需要将字符装箱,因为IntStream接口不能与收集器一起使用。

一个未解决的难题是应该命名实用程序方法。收集器实用程序方法的惯例是将它们称为toXXX,但toString已经被采用。


1
投票

如果必须的话,我们可以用这种非常丑陋的方式制作一个单行:

public static String stars(String t) {
    return t.codePoints().map(c -> c == ' ' ? ' ': '*').mapToObj(i -> new String(new int[] { i }, 0, 1)).collect(Collectors.joining());
}

它执行与my other answer完全相同的版本,但它一直使用流式传输。显然需要一些将单个代码点转换为字符串的函数:

public static String stars(String t) {
    return t.codePoints().map(c -> c == ' ' ? ' ': '*').mapToObj(Stars::codePointToString).collect(Collectors.joining());
}

private static String codePointToString(int codePoint) {
    return new String(new int[] { codePoint }, 0, 1);
}

当然,这些函数放在类Stars中。


0
投票

您可以使用以下代码直接执行此操作: -

"Hello world".codePoints().forEach(n -> System.out.print(n == ' ' ? ' ':'*'));

0
投票

有一个简单的答案,不太倾向于使用流媒体做所有事情。因此它不是单行,但它可能更有效,更容易阅读:

public static String stars(String t) {
    StringBuilder sb = new StringBuilder(t.length());
    t.codePoints().map(c -> c == ' ' ? ' ' : '*').forEach(sb::appendCodePoint);
    return sb.toString();
}

有时简短与简洁不一样,我认为没有人不得不怀疑上述功能是如何运作的。

此解决方案可确保代码点永远不会转换回字符。因此,它比这里列出的其他解决方案更通用。


-1
投票

你可以做:

chars.mapToObj(c -> c == ' ' ?  " ": "*").collect(joining());

另一个例子:

以下示例返回原始字符串。但这些可以与其他中间操作结合使用,例如filter()

chars.mapToObj(i -> String.valueOf((char) i)).collect(Collectors.joining()));

"abc".chars().mapToObj(i -> "" + (char) i)).collect(Collectors.joining()));
© www.soinside.com 2019 - 2024. All rights reserved.