Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Operations on a stream produce a result, but do not modify its underlying data source

Unable to understand how "Operations on a stream produce a result, but do not modify its underlying data source" with reference to java 8 streams.

shapes.stream() 
      .filter(s -> s.getColor() == BLUE)
      .forEach(s -> s.setColor(RED));

As per my understanding, forEach is setting the color of object from shapes then how does the top statement hold true?

like image 366
Prateek Gupta Avatar asked Dec 02 '25 20:12

Prateek Gupta


2 Answers

The value s isn't being altered in this example, however no deep copy is taken, and there is nothing to stop you altering the object referenced.

Are able to can alter an object via a reference in any context in Java and there isn't anything to prevent it. You can only prevent shallow values being altered.

NOTE: Just because you are able to do this doesn't mean it's a good idea. Altering an object inside a lambda is likely to be dangerous as functional programming models assume you are not altering the data being process (always creating new object instead)

If you are going to alter an object, I suggest you use a loop (non functional style) to minimise confusion.


An example of where using a lambda to alter an object has dire consequences is the following.

map.computeIfAbsent(key, k -> {
    map.computeIfAbsent(key, k -> 1);
    return 2;
});

The behaviour is not deterministic, can result in both key/values being added and for ConcurrentHashMap, this will never return.

like image 107
Peter Lawrey Avatar answered Dec 05 '25 13:12

Peter Lawrey


As mentioned Here

Most importantly, a stream isn’t a data structure.

You can often create a stream from collections to apply a number of functions on a data structure, but a stream itself is not a data structure. That’s so important, I mentioned it twice! A stream can be composed of multiple functions that create a pipeline that data that flows through. This data cannot be mutated. That is to say the original data structure doesn’t change. However the data can be transformed and later stored in another data structure or perhaps consumed by another operation.

AND as per Java docs

This is possible only if we can prevent interference with the data source during the execution of a stream pipeline.

And the reason is :

Modifying a stream's data source during execution of a stream pipeline can cause exceptions, incorrect answers, or nonconformant behavior.


That's all theory, live examples are always good.

So here we go :

Assume we have a List<String> (say :names) and stream of this names.stream(). We can apply .filter(), .reduce(), .map() etc but we can never change the source. Meaning if you try to modify the source (names) you will get an java.util.ConcurrentModificationException .

public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("Joe");
        names.add("Phoebe");
        names.add("Rose");
        names.stream().map((obj)->{
            names.add("Monika"); //modifying the source of stream, i.e. ConcurrentModificationException
             /**
              * If we comment the above line, we are modifying the data(doing upper case)
              * However the original list still holds the lower-case names(source of stream never changes)
              */
            return obj.toUpperCase(); 
        }).forEach(System.out::println);
    }

I hope that would help!

like image 34
Mehraj Malik Avatar answered Dec 05 '25 11:12

Mehraj Malik



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!