Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

non-interference requirement on Java 8 streams

I am a beginner in Java 8.

Non-interference is important to have consistent Java stream behaviour. Imagine we are process a large stream of data and during the process the source is changed. The result will be unpredictable. This is irrespective of the processing mode of the stream parallel or sequential.

The source can be modified till the statement terminal operation is invoked. Beyond that the source should not be modified till the stream execution completes. So handling the concurrent modification in stream source is critical to have a consistent stream performance.

The above quotations are taken from here.

Can someone do some simple example that would shed lights on why mutating the stream source would give such big problems?

like image 985
Francesco Gerardo Marra Avatar asked Jun 01 '17 11:06

Francesco Gerardo Marra


People also ask

Does Java 8 support streams?

Java 8 offers the possibility to create streams out of three primitive types: int, long and double. As Stream<T> is a generic interface, and there is no way to use primitives as a type parameter with generics, three new special interfaces were created: IntStream, LongStream, DoubleStream.

Does Java 8 stream improve performance?

Java 8 introduced streams. Not to be confused with input/output streams, these Java 8+ streams can also process data that goes through them. It was hailed as a great new feature that allowed coders to write algorithms in a more readable (and therefore more maintainable) way.

Is Java 8 stream thread-safe?

In general no. If the Spliterator used has the CONCURRENT characteristic, then the stream is thread-safe. Save this answer.

Which of the following is correct about streams in Java 8?

i) Stream represents a sequence of objects from a source, which supports aggregate operations.


1 Answers

Well the oracle example is self-explanatory here. First one is this:

List<String> l = new ArrayList<>(Arrays.asList("one", "two"));
 Stream<String> sl = l.stream();
 l.add("three");
 String s = l.collect(Collectors.joining(" "));

If you change l by adding one more elements to it before you call the terminal operation (Collectors.joining) you are fine; but notice that the Stream consists of three elements, not two; at the time you created the Stream via l.stream().

On the other hand doing this:

  List<String> list = new ArrayList<>();
  list.add("test");
  list.forEach(x -> list.add(x));

will throw a ConcurrentModificationException since you can't change the source.

And now suppose you have an underlying source that can handle concurrent adds:

ConcurrentHashMap<String, Integer> cMap = new ConcurrentHashMap<>();
cMap.put("one", 1);
cMap.forEach((key, value) -> cMap.put(key + key, value + value));
System.out.println(cMap);

What should the output be here? When I run this it is:

 {oneoneoneoneoneoneoneone=8, one=1, oneone=2, oneoneoneone=4}

Changing the key to zx (cMap.put("zx", 1)), the result is now:

{zxzx=2, zx=1}

The result is not consistent.

like image 188
Eugene Avatar answered Oct 28 '22 15:10

Eugene