Dharmvir Tiwari
Dharmvir Tiwari

Reputation: 916

Java 8 - Stream with Objects and primitive wrappers

I am working with java 8 stream and trying to modify the object content in the forEach terminal operation.

The issues which i am facing here is that i am able to modify the List<Employee> object contents but not able to modify the contents of List<Integer>

The code snippet is as follows:

public static void streamExample() {

    List<Employee> listEmp = Arrays.asList(new Employee());
    listEmp.stream().forEach(a -> a.setEmptName("John Doe"));
    listEmp.stream().forEach(System.out::println);
    List<Integer> listInteger = Arrays.asList(2, 4, 6, 8, 12,17, 1234);
    listInteger.stream().filter(v -> v % 2 == 0).forEach(a -> a=a+1);
    listInteger.stream().forEach(System.out::println);

}

I am wondering the change is not reflecting back in the list because of unboxing the Integer object while performing the a=a+1 operation but not sure.

Upvotes: 3

Views: 1311

Answers (2)

Oleg Cherednik
Oleg Cherednik

Reputation: 18245

You use not optimal approach of Stream. Do think of each step in Stream as modify existed (or create new) element and return it back to the Stream. Finally you receive final result and you can use one of final method to finalize (and actually run the whole stream working) the Stream:

List<Integer> listInteger = Arrays.asList(2, 4, 6, 8, 12, 17, 1234);
listInteger.stream().filter(v -> v % 2 == 0).forEach(a -> a = a + 1);
listInteger.stream().forEach(System.out::println);

Here you have initial array. You want to do following:

  1. Filter out some elements (this is not final step);
  2. Print filtered elements out (this is final step).

To do so, you do not have to create Streams two times. Do use one:

Stream.of(2, 4, 6, 8, 12, 17, 1234)    // create stream (there're many way to do it)
      .filter(v -> v % 2 == 0)         // filter out required elements
      .map(v -> v + 1)                 // transform elements using given rule
      .forEach(System.out::println);   // finalize stream with printing out each element separately

Note: Stream.of(...) creates a Stream, then we add two steps to the stream filter and map and then finalize or START created stream with forEach.

Upvotes: 3

Eran
Eran

Reputation: 393781

You are assigning a new value to a local variable (a), so that has no affect on the source of the second Stream (your List<Integer>). Note that this is not what you are doing with your List<Employee>, where you are calling a setter method to mutate the elements of the List.

Since Integers are immutable, you can't mutate the elements of your input List<Integer>.

Instead, you can create a new List:

List<Integer> newList = 
    listInteger.stream()
               .map(v -> v % 2 == 0 ? v + 1 : v)
               .collect(Collectors.toList());

Or you can stream over the indices of your List, and replace some of the elements of that List:

IntStream.range(0,listInteger.size())
         .filter(i -> listInteger.get(i) % 2 == 0)
         .forEach(i -> listInteger.set(i, listInteger.get(i + 1));

Upvotes: 3

Related Questions