This question already has an answer here:
- Stream intermediate operations ordering 2 answers
I have been trying to find clear contract from official Java documentation as to in which order Java streams, once a terminal operation is called, process the elements and call intermediate operations.
For example lets look at these examples that use both Java stream version and plain iteration version (both producing same outcome) .
Example1:
List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5);
Function<Integer, Integer> map1 = i -> i;
Predicate<Integer> f1 = i -> i > 2;
public int findFirstUsingStreams(List<Integer> ints){
return ints.stream().map(map1).filter(f1).findFirst().orElse(-1);
}
public int findFirstUsingLoopV1(List<Integer> ints){
for (int i : ints){
int mappedI = map1.apply(i);
if ( f1.test(mappedI) ) return mappedI;
}
return -1;
}
public int findFirstUsingLoopV2(List<Integer> ints){
List<Integer> mappedInts = new ArrayList<>( ints.size() );
for (int i : ints){
int mappedI = map1.apply(i);
mappedInts.add(mappedI);
}
for (int mappedI : mappedInts){
if ( f1.test(mappedI) ) return mappedI;
}
return -1;
}
Will the Java stream in findFirstUsingStreams
method after findFirst
is called run map1
in the order described in findFirstUsingLoopV1
(map
is not run for all elements) or as described in findFirstUsingLoopV2
(map
is run for all elements)?
And will that order change in future versions of Java or there is an official documentation that guarantees us the order of map1
calls?
Example2:
Predicate<Integer> f1 = i -> i > 2;
Predicate<Integer> f2 = i -> i > 3;
public List<Integer> collectUsingStreams(List<Integer> ints){
return ints.stream().filter(f1).filter(f2).collect( Collectors.toList() );
}
public List<Integer> collectUsingLoopV1(List<Integer> ints){
List<Integer> result = new ArrayList<>();
for (int i : ints){
if ( f1.test(i) && f2.test(i) ) result.add(i);
}
return result;
}
public List<Integer> collectUsingLoopV2(List<Integer> ints){
List<Integer> result = new ArrayList<>();
for (int i : ints){
if ( f2.test(i) && f1.test(i) ) result.add(i);
}
return result;
}
Again will the Java stream in collectUsingStreams
method after collect
is called run f1
and f2
in the order described in collectUsingLoopV1
(f1
is evaluated before f2
) or as described in collectUsingLoopV2
(f2
is evaluated before f1
)?
And will that order change in future versions of Java or there is an official documentation that guarantees us the order of f1
and f2
calls?
Edit
Thanks for all the answers and comment but unfortunately I still dont see good explanation on the ordering of processing the elements. The docs do say that the encounter order will be preserved for lists but they dont specify how those elements will be processed. For example in case of findFirst
the docs guarantees that map1
will first see 1 then 2 but it does not say that map1
wont be executed for 4 and 5. Does it mean that we cant guarantee that our order of processing will be as we expect the in fure versions of Java? Probably yes.