Java stream – collection combiner
Why the following codes:
StringBuilder sb22 = IntStream .range(1,101) .filter(x -> x > 50) .@R_911_2419@ed() .parallel() .collect(// object that is used in accumulator to do accumulating on StringBuilder::new,// use object from above and call append on it with each stream element as argument (sb,a) -> sb.append(":" + a),// (executes only when using parallel!) (sb1,sb2) -> { System.out.println(Thread.currentThread().getId() + " " + "sb1=" + sb1 + " AND " + "sb2=" + sb2); sb1.append("-"+sb2); });
This result:
------------------:51:52:53-:54:55:56-:57:58:59-:60:61:62-:63:64:65-:66:67:68-:69:70:71-:72:73-:74:75-:76:77:78-:79:80:81-:82:83:84-:85:86:87-:88:89:90-:91:92:93-:94:95:96-:97:98-:99:100
Should part (--) not be excluded from the output first?
In addition, I understand that the combiner in the collection may be called out of order, so it can be changed to: 76:77:78 -: 79:80:81, for example: 63:64:65 -: 79:80:81?
Update (@ Holger replies)
This is the tree generated using the code he linked to this case:
[51..100] _________________________________________________________________________________/\______________________________________________________________________ | | (empty) [51..100] ___________________________________/\__________________________________ ________________________________________/\______________________________________ | | | | (empty) (empty) [51..75] [76..100] ___________________/\______________ ___________________/\______________ ______________________/\________________ ______________________/\________________ | | | | | | | | (empty) (empty) (empty) (empty) [51..62] [63..75] [76..87] [88..100] _______/\______ ___________/\______ _______/\______ ___________/\______ ________/\_______ _____________/\_______ ________/\_______ _____________/\_______ | | | | | | | | | | | | | | | | (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) [51..56] [57..62] [63..68] [69..75] [76..81] [82..87] [88..93] [94..100] ___/\__ ___/\__ ___/\__ _______/\__ ___/\__ ___/\__ ___/\__ _______/\__ ___/\___ ___/\___ ___/\___ ________/\__ ___/\___ ___/\___ ___/\___ ________/\___ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) (empty) [51..53] [54..56] [57..59] [60..62] [63..65] [66..68] [69..71] [72..75] [76..78] [79..81] [82..84] [85..87] [88..90] [91..93] [94..96] [97..100] ___/\__ ___/\__ ___/\___ ____/\__ | | | | | | | | (empty) (empty) (empty) (empty) [72..73] [74..75] [97..98] [99..100]
Solution
Workload splitting occurs before any processing, so the stream implementation splits the range [1101] into sub ranges to be processed At this point, it does not know that the filter will completely delete the first half, it cannot know without evaluating predicates, and should have occurred in parallel after workload splitting
Therefore, each sub scope is processed in the same way, including collecting results into containers and then combining these containers, even if they happen to be empty The specification does not say that the composition step will be skipped when no element reaches the collector. You should not expect this Although it is theoretically possible to track whether any elements arrive at the collector, this tracking can only be used in specific situations, and it is not even clear whether combining containers with empty containers (such as adding an empty list or attaching an empty StringBuilder) is more expensive than tracking
Of course, if it preserves semantics, for example, nothing can prevent you from optimizing your compositor Replace (SB1, SB2) – > SB1 Append (SB2), you can use (SB1, SB2) – > SB1 length()== 0? sb2:sb1. append(sb2)
You can check this Q & A, "visualization of Java stream parallelism" for more details