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

JavaJava 8Java Stream

Java Problem Overview


With Java-8 I can easily treat a String (or any CharSequence) as an IntStream using either the chars or the codePoints method.

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

I can then manipulate the contents of the stream

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

I have been hunting for a tidy way to print the results and I cant even find a simple way. How do I put this stream of ints back into a form that can be printed like I can a String.

From the above stars I hope to print

***** ******

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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.

Solution 3 - Java

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.

Solution 4 - Java

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.

Solution 5 - Java

If we must, we can make a one-liner this extremely ugly way:

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

It performs the exact same version as my other answer but it uses streaming all the way. Some function to convert a single code point to a string is obviously needed:

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

which places these functions in the class Stars of course.

Solution 6 - Java

The way I do it is by using reduce. To get * for each character and space for each space it will look like this

    String hello = "hello world";
    String result = hello.chars()
        .map(val -> (val == ' ') ?  ' ' : '*')
        .mapToObj(val -> String.valueOf((char) val))
        .reduce("",(s1, s2) -> s1+s2);

The point is do whatever you want with the integers than cast it to characters then map it to String then concatenate it, you can use reduce or Collectors.joining()

Solution 7 - Java

You can do it directly with the following code :-

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

Solution 8 - Java

How about this.

  System.out.println(stars.mapToObj(c -> String.format("%c", c)).collect(
	        Collectors.joining()));

  or

  String s = stars.mapToObj(c -> String.format("%c", c)).reduce("",
	        (a, b) -> a + b);

Solution 9 - Java

  IntStream charStream = "hello".chars();
  charStream.mapToObj(c -> (char)c).forEach(System.out::println);

This works for me.

Solution 10 - Java

You can do:

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

Another example:

The following examples return the original string. But these can be combined with other intermediate operations such as filter().

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

"abc".chars().mapToObj(i -> "" + (char) i)).collect(Collectors.joining()));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOldCurmudgeonView Question on Stackoverflow
Solution 1 - JavaHolgerView Answer on Stackoverflow
Solution 2 - JavaLukasz WiktorView Answer on Stackoverflow
Solution 3 - JavaLiiView Answer on Stackoverflow
Solution 4 - JavaMaarten BodewesView Answer on Stackoverflow
Solution 5 - JavaMaarten BodewesView Answer on Stackoverflow
Solution 6 - JavaAhmadView Answer on Stackoverflow
Solution 7 - JavaMaster Za'imView Answer on Stackoverflow
Solution 8 - JavaWJSView Answer on Stackoverflow
Solution 9 - JavafoureverhhView Answer on Stackoverflow
Solution 10 - JavaGayan WeerakuttiView Answer on Stackoverflow