Java 8 threads - every step in the chain, evaluated for all input or passing element?

Tell me if I have this trivial program

List<String> input = Arrays.asList("1", "2", "3"); List<String> result = input.stream() .map(x -> x + " " + x) .filter(y -> !y.startsWith("1")) .collect(Collectors.toList()); 

Behind the scenes it works like a) or b)

BUT

 map "1" + " " + "1" "2" + " " + "2" "3" + " " + "3" filter "1 1" does not begin with "1"? = false "2 2" does not begin with "1"? = true "3 3" does not begin with "1"? = true collect add "2 2" to list add "3 3" to list result = List("2 2", "3 3") 

IN

 map "1" + " " + "1" filter "1 1" does not begin with "1"? = false map "2" + " " + "2" filter "2 2" does not begin with "1"? = true collect add "2 2" to list map "3" + " " + "3" filter "3 3" does not begin with "1"? = true collect add "3 3" to list result = List("2 2", "3 3") 
+8
java java-8 java-stream
source share
2 answers

It works as an option B, and not necessarily in that exact order, but moreover, it performs each operation one element at a time.

The rationale is that the variables only transmit the stream once , so you need to perform all the actions when you have this element right now, because once the element has passed, it disappeared forever (from the point of view of the stream).

Your linear setup code is very very similar to the following code, this is a very simplified version, but I hope you understand:

 Collection<String> input = Arrays.asList("1", "2", "3"); Function<String, String> mapper = x -> x + " " + x; Predicate<String> filter = y -> !y.startsWith("1"); Collector<String, ?, List<String>> toList = Collectors.toList(); List<String> list = ((Supplier<List<String>>)toList.supplier()).get(); for (String in : input) { in = mapper.apply(in); if (filter.test(in)) { ((BiConsumer<List<String>, String>)toList.accumulator()).accept(list, in); } } 

What you see here:

  • As input to the Collection<String> enter your input.
  • A Function<String, String> corresponding to your map() .
  • A Predciate<String> matches your filter() .
  • A Collector<String, ?, List<String>> , corresponding to your collect() , is it a collector that works with elements of type String , uses intermediate storage ? and gives a List<String> .

What does he do then:

  • Get a new list from the supplier (type: Supplier<List<String>> ) of the collector.
  • Iterate over each input element that is executed internally when working with Stream<String> , I use Collection<String> for clarity, so that we still have a connection to the old Java 7 world.
  • Apply your matching function.
  • Check the filter predicate.
  • To get the drive (type: BiConsumer<List<String>, String> ) of the toList collector, this is a binary consumer that takes as its arguments the List<String> that it already has and the String that it wants to add.
  • Download our list and in to the battery.

Please pay particular attention to the fact that real implementations are much more advanced, since operations can occur in any order, and several, and much more, can happen.

+8
source share

One of the advantages of threads is lazy evaluation of intermediate operations . This means that when the terminal operation collect() in this case is performed, it requests an element from the previous intermediate operation - filter() , which in turn receives an element from map() , which in turn works with the first element from list.stream() . For all elements, the same thread is executed. So yes, execution is more like option B.

In addition, since the customer returned by Collectors.toList() is ordered, the elements are guaranteed to be in order. In some cases, an assessment may fail when a UNORDERED chararacteristic is set for the collector.

+5
source share

All Articles