3

Have the following codes with breaking behavior in a for loop:

package test;

import java.util.Arrays;
import java.util.List;

public class Test {

    private static List<Integer> integerList = Arrays.asList(1, 2, 3, 4);

    public static void main(String[] args) {
        countTo2(integerList);
    }

    public static void countTo2(List<Integer> integerList) {

        for (Integer integer : integerList) {
            System.out.println("counting " + integer);
            if (integer >= 2) {
                System.out.println("returning!");
                return;
            }
        }
    }
}

trying to express it with Lambda using forEach() will change the behavior as the for loop is not breaking anymore:

public static void countTo2(List<Integer> integerList) {

    integerList.forEach(integer -> {
        System.out.println("counting " + integer);
        if (integer >= 2) {
            System.out.println("returning!");
            return;
        }
    });
}

This actually makes sense as the return; statements are only enforced within the lambda expression itself (within the internal iteration) and not for the whole execution sequence, so is there a way to get the desired behavior (breaking the for loop) using the lambda expression?

3 Answers 3

3

The following code is logically equivalent to yours:

public static void countTo2(List<Integer> integerList) {
    integerList.stream()
               .peek(i -> System.out.println("counting " + i))
               .filter(i -> i >= 2)
               .findFirst()
               .ifPresent(i -> System.out.println("returning!"));
}

If you're confused about anything, please let me know!

Sign up to request clarification or add additional context in comments.

Comments

2

What you are looking for is a short-circuit terminal operation and while this is the way to do it:

integerList.stream()
            .peek(x -> System.out.println("counting = " + x))
            .filter(x -> x >= 2)
            .findFirst()
            .ifPresent(x -> System.out.println("retunrning"));

That's an equivalent only when dealing with sequential stream. As soon as you add parallel that peek might show elements that you would not expect, because there is no defined processing order, but there is encounter order - meaning that elements will be correctly fed to the terminal operation.

1 Comment

Sure, it has to be sequential as the logic is short-circuiting when the condition matches on the smallest value.
1

One way I could think of doing that would be using anyMatch and the inverse:

if (integerList.stream().noneMatch(val -> val >= 2)) {
    System.out.println("counting " + val);
}

if (integerList.stream().anyMatch(val -> val >= 2)) {
    System.out.println("returning!");
}

but internally that would iterate over the list twice and wouldn't be very optimal I believe.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.