Q: Java streams perform different operations by multiple filters I want to return different error messages minimum and maximum constraints on the values in a given list. I was hoping to use Java streams but i am having to filter the same list twice. Whereas using a for loop i would only have to go over the list once. Is there a better way to achieve this via streams?
My code looks something like this:
list.stream().filter(i -> i < 0).findAny().ifPresent(i -> System.out.println("below min"));

list.stream().filter(i -> i > 100).findAny().ifPresent(i -> System.out.println("above max"));

Using a for loop i can place two if conditions while traversing over the list once,
In actual implementation there are other constraints as well and I'm adding an error to a list, if it not already exists, depending on each violation.
Will i have to filter the list each time for each violation?
Help would be appreciated!

A: If you are using Java 12+ you can utilize teeing collector to achieve what you want using Java Streams API:
list.stream()
    .collect(Collectors.teeing(
        Collectors.minBy(Comparator.<Integer>naturalOrder()),
        Collectors.maxBy(Comparator.<Integer>naturalOrder()),
            (min, max) -> {
              min.ifPresent(i -> System.out.println("below min"));
              max.ifPresent(i -> System.out.println("above max"));
              return 0;
            }
    ));

You can collect those elements as well:
list.stream()
    .collect(Collectors.teeing(
        Collectors.filtering(i -> i < 0, Collectors.toList()),
        Collectors.filtering(i -> i > 100, Collectors.toList()),
            (l1, l2) -> {
              System.out.printf("%s %s%n", l1, l2);
              return 0;
            }
    ));


Though, whether such approach with streams should be used in place of a for loop needs careful consideration. For this specific question, the code using the for loop will probably be more readable.

A: You can simply stream and use a forEach loop to filter out elements in a single loop:
        List<Integer> smaller = new ArrayList<>();
        List<Integer> larger = new ArrayList<>();
        List<Integer> intList = Arrays.asList(200, 345, -132, -2, -34, null);

        intList.stream().filter(Objects::nonNull).forEach(element -> {
            if (element < 0) {
                smaller.add(element);
            } else if (element > 100) {
                larger.add(element);
            }
        });
        System.out.println("Smaller:-" + smaller);
        System.out.println("Larger:-" + larger);

The real focus should be on code readability even if it takes some more code line to write logic.
