Search code examples
javajava-streamcollectors

In collect() terminal operation of Stream, what will happen if supplier is an immutable object like a String?


collect() method of Stream is a mutable reduction. Based on Java Documenation:

A mutable reduction operation accumulates input elements into a mutable result container, such as a Collection or StringBuilder, as it processes the elements in the stream.

I tried the following and it compiles without issue.

Stream<String> stream1 = Stream.of("w", "o", "l", "f");
String word = stream1.collect(String::new, String::concat, String::concat);
System.out.println(word);

If the supplier is a StringBuffer, I view the collect operation as elements will be appended to the supplied StringBuffer.

How does mutable reduction works here since String is an immutable object? Will it be the same as reduce operation where a new object is created everytime the accumulator is implemented?


Solution

  • How does mutable reduction works here since String is an immutable object?

    It doesn't. When you run that you will get an empty String (the result of the Supplier only). The compiler can not enforce checking if the Supplier returns an immutable object, that is absolutely something it can not do. And since your container is immutable, updates to it are simply ignored. It's like doing:

    String s = "abc";
    s.concat("def"); // the result is ignored here
    

    May be if you write that as a lambda it will make a lot more sense:

    Stream<String> stream1 = Stream.of("w", "o", "l", "f");
        String word = stream1.collect(
                String::new,
                (left, right) -> {
                    left.concat(right); // result is ignored
                },
                String::concat);
    

    On the other hand, when you use reduce, you are forced to return something:

    String word = stream1.reduce(
                "",
                (x, y) -> {
                    return x.concat(y);
                },
                (x, y) -> {
                    return x.concat(y);
                });
    

    Of course, you could still do:

    String word = stream1.reduce(
                "",
                (x, y) -> {
                    x.concat(y);
                    return x; // kind of stupid, but you could
                },
                (x, y) -> {
                    return x.concat(y);
                });
    

    If you wanted to break it; but that is not the point.