My question has to do with when one of the parameters in the reduce function of Streams is used, I will need to explain my setup first before to describe the problem more fully.
Suppose I have a Person class with String name and int age as fields, I make a few people in the following static method:
public static List<Person> createPeople() {
return List.of(new Person("Sara", 20),
new Person("Sara", 22),
new Person("Bob", 20),
new Person("Paula", 32),
new Person("Paul", 32),
new Person("Jack", 3),
new Person("Jack", 72),
new Person("Jill", 11));
}
Now, I want to get a List of the names of people over 30 years of age. I know I can achieve this using the collect function easily, but I wanted to explore one aspect of doing it with the reduce function. I have the following code:
List<String> namesOfOlderThan30 = createPeople().stream()
.filter(person -> person.getAge() > 30)
.map(Person::getName)
.map(String::toUpperCase)
.reduce(new ArrayList<String>(),
(names, name) -> {
names.add(name);
System.out.println(names);
return names;
},
(names1, names2) -> {
System.out.println("Before: "+ names1);
names1.addAll(names2);
System.out.println("After: "+ names1);
return names1;
});
According to the source, I see that the method signature for reduce when there are three arguments is:
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
When I run this code above, I get the output:
[PAULA]
[PAULA, PAUL]
[PAULA, PAUL, JACK]
Since I coded each of the functions to print, this means that the BinaryOperator combiner parameter was not used at all.
However, when I run the same code using parallelStream() instead of just stream(), I get:
[JACK, PAUL]
Before: [JACK, PAUL, PAULA]
[JACK, PAUL, PAULA]
[JACK, PAUL]
After: [JACK, PAUL, PAULA, JACK, PAUL, PAULA]
Before: [JACK, PAUL, PAULA]
Before: [JACK, PAUL, PAULA, JACK, PAUL, PAULA]
After: [JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA]
Before: [JACK, PAUL, PAULA, JACK, PAUL, PAULA]
After: [JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA]
After: [JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA, JACK, PAUL, PAULA]
...
Exception in thread "main" java.util.ConcurrentModificationException: java.util.ConcurrentModificationException
This makes me think that the third parameter in the reduce method is related to some parallel function of streams, but I do not understand how it is related. Further, when I remove the lines for printing, the error no longer occurs when using parallelStream.
Can someone help explain what is happening here for me in more detail?
Thank you.