Simplest way to print an `IntStream` as a `String`

A bit less efficient but more concise solution to Holger's:

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

Collectors.joining() internally uses StringBuilder, at least in OpenJDK sources.


Other answers show how to collect a stream of strings into a single string and how to collect characters from an IntStream. This answer shows how to use a custom collector on a stream of characters.

If you want to collect a stream of ints into a string, I think the cleanest and most general solution is to create a static utility method that returns a collector. Then you can use the Stream.collect method as usual.

This utility can be implemented and used like this:

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);
}

It's a bit surprising that there isn't something like this in the standard library.

One disadvantage of this approach is that it requires the chars to be boxed since the IntStream interface does not work with collectors.

An unsolved and hard problem is what the utility method should be named. The convention for collector utility methods is to call them toXXX, but toString is already taken.


String result = "Hello world."
  .codePoints()
//.parallel()  // uncomment this line for large strings
  .map(c -> c == ' ' ? ' ': '*')
  .collect(StringBuilder::new,
           StringBuilder::appendCodePoint, StringBuilder::append)
  .toString();

But still, "Hello world.".replaceAll("[^ ]", "*") is simpler. Not everything benefits from lambdas.


There is a simple answer that is slightly less inclined to doing everything with streaming. Hence it is not a one-liner, but it is probably more efficient and very easy to read:

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

Sometimes short is not the same as concise, I don't think anybody has to wonder how the above function operates.

This solution makes sure that the code points are never converted back to characters. It is therefore somewhat more generic than some other solutions listed here.