can't change item value in parallelStream().forEach()?

Viewed 426
List<String> items = Arrays.asList("a", "b", "c");
items.parallelStream().forEach(e -> e = e + "fff");
System.out.println("case1 " + items);

items = items.parallelStream().map(e -> {
        e = e + "fff";
        return e;
}).collect(Collectors.toList());
System.out.println("case2 " + items);

Why items value not changed in case1 ?

if items contains many DTOs, and I just want to change one field in DTO , then must use parallelStream().map().collect()? why can't just use parallelStream().forEach() ?

3 Answers

Reassignment in the forEach consumer will not change the object your items list references. All that does is change e from referencing your list element to referencing a new string.

This will work since you're changing the object instead of reassigning the consumer argument's reference.

import java.util.Arrays;
import java.util.List;

public final class StackOverflow {

    private static class ItemHolder<T> {
        private T item;

        ItemHolder(T item) {
            this.set(item);
        }

        public void set(T item) {
            this.item = item;
        }

        public T get() {
            return item;
        }

        @Override
        public String toString() {
            return item.toString();
        }
    }

    public static void main(String[] args) {
        List<ItemHolder<String>> items = Arrays.asList(
                new ItemHolder<>("a"),
                new ItemHolder<>("b"),
                new ItemHolder<>("c")
        );

        items.parallelStream().forEach(item -> {
            String value = item.get();
            item.set(value + "fff");
        });

        System.out.println(items);
    }
}

Which prints: [afff, bfff, cfff]

forEach will just execute the method with each element. It does not replace the element in the list. In fact no operation of the stream API will replace an element in the list.

map will transform the stream to the return of the function, you need the collect method to create the new List that will hold this elements. Again remember no stream API method will mutate your original list.

To apply a lambda expression to change all elements of a list, use replaceAll():

List<String> items = Arrays.asList("a", "b", "c");
items.replaceAll(e -> e + "fff");
System.out.println("case1 " + items);

Output

case1 [afff, bfff, cfff]
Related