Java stream operation sequence executed by the terminal

See English answers > stream intermediate operations ordering 2

For example, let's look at these examples using the Java stream version and the normal iterative Version (both produce the same results)

Example 1:

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;
    }

Whether the Java flow in the findfirstusingstreams method after findfirst is requested to run MAP1 in the order described in findfirstusingloopv1 (mapping does not run for all elements) or as described in findfirstusingloopv2 (running map for all elements)?

And will this order change in future Java versions, or is there an official document to ensure the order of MAP1 calls?

Example 2:

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;
}

The Java flow in the collectusingstreams method after collection calls run F1 and F2 again in the order described in collectusingloopv1 (F1 is evaluated before F2) or as described in collectusingloopv2 (F1 is evaluated before F1)?

And will this order change in future Java versions, or is there an official document to ensure the order of our F1 and F2 calls?

edit

Thanks for all the answers and comments, but unfortunately, I still don't see a good explanation of the order of processing elements The documents do say that the encounter order will be reserved for the list, but they do not specify how to deal with these elements For example, in the case of findfirst, docs guarantees that MAP1 will first see 1 and then 2, but it does not say that MAP1 will not be executed 4 and 5 Does this mean that we cannot guarantee that our processing order will be in the fixed version of Java as we expect? Probably

Solution

Javadoc, including package summaries (which people often ignore), is an API contract Observable behavior not defined by Javadoc should generally be considered as implementation details that may change in future versions

Therefore, if it cannot be found in JavaDocs, there is no guarantee

In which order the flow pipeline phase is called and interleaving is not specified What is specified is the case under which the so-called flow's encounterorder is retained Assuming an ordered flow, the implementation is still allowed to perform any interleaving, batch and internal reordering that will preserve the order encountered For example Sorted (comparator) Filter (predicate) Findfirst() can use filters (predicates) internally Min (comparator) substitution, which of course significantly affects the way predicates and comparators are called, but produces the same results, even in an ordered flow

Yes, this should not be a problem, because most stream APIs require callbacks to be state and free of side effects, which means, among other things, that they should not care about the internal execution order of the stream pipeline. The result should be the same. Modularize the flow granted by disorder

Explicit requirements and lack of assurance provide JDK developers with flexibility in how to implement flows

If you have any special circumstances to consider, you should ask a more specific question about performing reordering you want to avoid

You should always keep in mind that streams can be parallel, such as an instance passed by third-party code, or contain a source or intermediate stream operation, which is less lazy than theory (such as the current flatmap operation) If someone extracts and re splits the splitter or uses a custom implementation of the stream interface, the stream pipeline can also contain custom behavior

Therefore, when a particular flow implementation uses them in a particular way, it may show some predictable behavior, and future optimization for that particular case may be considered very unlikely, which will not be extended to all possible flow pipelines, so the API cannot provide such a general guarantee

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>