BiFunction - apply method should always return the second argument. Why?

Wall :

I am trying to identify the numbers from a list whose predecessor is greater than its value.

In the lambda expression if I return b, it behaves as expected but if I return a, it gives wrong output.

What is the difference between these two return statements?

    List<Integer> list = Arrays.asList(1,2,3,4,5,8,7);
    List<Integer> result = new ArrayList<>();
    list.stream().reduce((a,b) -> {if (a < b) result.add(a);return b;});
    System.out.println(result);

    result.clear();
    list.stream().reduce((a,b) -> {if (a < b) result.add(a);return a;});
    System.out.println(result);

Output:

[1, 2, 3, 4, 5]

[1, 1, 1, 1, 1, 1]

Eran :

The reduction you are performing - using Optional<T> java.util.stream.Stream.reduce(BinaryOperator<T> accumulator) - is equivalent to the following pseudo code (taken from the Javadoc):

boolean foundAny = false;
T result = null;
for (T element : this stream) {
    if (!foundAny) {
        foundAny = true;
        result = element;
    } else {
        result = accumulator.apply(result, element);
    }
}
return foundAny ? Optional.of(result) : Optional.empty();

As you can see, the intermediate result of the reduction is passed as the first argument of the accumulator and the current element of the Stream is passed as the second argument.

Hence, when your lambda expression returns the second argument b (first snippet), the intermediate result becomes the current element of the Stream, which you add to the List on the next iteration.

When your lambda returns the first argument a (second snippet), the intermediate result remains unchanged (always 1, the first element of the Stream), and you keep adding that value to the List.

Let's verify this with the actual numbers:

result is initialized to the first element of the Stream 1.

Then, the first snippet calls accumulator.apply(1,2), adding 1 to the List and returning 2 (which becomes the new intermediate result). The next iteration will add 2 to the List and return 3. And so on...

The second snippet calls accumulator.apply(1,2), adding 1 to the List and returning 1 (which remains the new intermediate result). The next iteration will add 1 to the List again and return 1 again. And so on...

To summarize, your two accumulation functions have a different functionality:

The first results in the last element of the Stream (since it keeps discarding the current result and replacing it with the current element).

The second results in the first element of the Stream (since it keeps the first element and ignores all other elements).

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=125889&siteId=1