If I call collect on a sequential stream (eg. from calling Collection.stream()) then will it use the combiner parameter I pass to collect? I presume not but I see nothing in the documentation. If I'm correct, then it seems unfortunate to have to supply something that I know will not be used (if I know it is a sequential stream).

  • 2
    What happens when you pass null for the combiner? What do you deduce from this experiment? – JB Nizet Jun 13 '14 at 10:05
  • @JBNizet It will throw NullPointerException. – johnlinp May 27 at 3:46

Keep in mind to develop against interface specifications -- not against the implementation. The implementation might change with the next Java version, whereas the specification should remain stable.

The specification does not differentiate between sequential and parallel streams. For that reason, you should assume, that the combiner might be used. Actually, there are good examples showing that combiners for sequential streams can improve the performance. For example, the following reduce operation concatenates a list of strings. Executing the code without combiner has quadratic complexity. A smart execution with combiner can reduce the runtime by magnitudes.

List<String> tokens = ...;
String result = tokens.stream().reduce("", String::concat, String::concat);
| improve this answer | |
  • 4
    It would be very smart if the Stream implementation recognizes if using the combiner can improve performance. However, the bigger risk is that the developer him/herself changes a stream to parallel at a time (s)he has forgotten about the omitted combiner… – Holger Jun 13 '14 at 14:36
  • 3
    @Holger Right, or another developer passes a stream to your code, and that stream might change to be parallel in the future. – Stuart Marks Jun 13 '14 at 15:34
  • 3
    Thanks for your answer. I had the same problem, and while always adhering to develop against the interface, I find it a pity that there is no "simple" version of a collector with no combiner. That would make things MUCH easier. They could have made a Collector.Characteristics to indicate this, or a simpler version of the Collector interface... – glglgl Sep 3 '14 at 12:31
  • 1
    One more question: Here I found the sentence A sequential implementation of a reduction using a collector would create a single result container using the supplier function, and invoke the accumulator function once for each input element. Doesn't that already indicate that the combiner isn't used in this situation? – glglgl Sep 3 '14 at 12:35
  • 2
    @GeekFactory you are overlooking the costs of “just concat them”. String concatenation implies creating a new string that is a copy of both argument strings. The longer the string, the more overhead. And the intermediate result of multiple string concatenations is a string that grows longer and longer. You may search for “Shlemiel the Painter's Algorithm” for an intuitive picture. See also ideone.com/0kRRnt Just to make it clear, collect(joining()) still is even better, but I hope you see, utilizing the combiner reduces the overhead in this example. – Holger Nov 21 '19 at 11:36

Your Answer

