Search code examples
javaforeachjava-8java-streamconsumer

Conditions for a List with Java8 with Consumer or Filter, which way is better


I have tried this

    List<Integer> numbers = Arrays.asList(1, 1, 0, -1, -1);
    List<Integer> positiveNum2 = new ArrayList<>();
    List<Integer> negativeNum2 = new ArrayList<>();
    List<Integer> zeroNumbers2 = new ArrayList<>();
    List<Integer> positiveNumbers = numbers.stream().filter(number -> number > 0).collect(Collectors.toList());
    List<Integer> negativeNumbers = numbers.stream().filter(number -> number < 0).collect(Collectors.toList());
    List<Integer> zeroNumbers = numbers.stream().filter(number -> number.equals(0)).collect(Collectors.toList());
    positiveNumbers.forEach(System.out::println);
    negativeNumbers.forEach(System.out::println);
    zeroNumbers.forEach(System.out::println);
    System.out.println("*********with Consumer******************");
    Consumer<Integer> determineNumber = number -> {
        if (number > 0) {
            positiveNum2.add(number);
        } else if (number < 0) {
            negativeNum2.add(number);
        } else {
            zeroNumbers2.add(number);
        }

    };
    numbers.forEach(determineNumber);
    positiveNum2.forEach(System.out::println);
    negativeNum2.forEach(System.out::println);
    zeroNumbers2.forEach(System.out::println);

but I dont know which one is better, I think the forEach with the Consumer, but the Consumer does three validations, therefore, does not have single responsability


Solution

  • The consumer only takes one iteration, so it's more efficient, and it does have a single responsibility: dividing the numbers over three lists based on their sign.

    For this case, I'd probably use a simple for loop though.

    If you really want to over-engineer things, you can define an enum to represent the sign, and use a grouping collector to group into a map:

    import java.util.Arrays;
    import java.util.List;
    import java.util.Map;
    
    import static java.util.stream.Collectors.groupingBy;
    
    public class Test {
        public static void main(String[] args) {
            List<Integer> numbers = Arrays.asList(1, 1, 0, -1, -1);
    
            Map<Sign, List<Integer>> map = numbers
                    .stream()
                    .collect(groupingBy(i -> i > 0
                                        ? Sign.POSITIVE
                                        : i < 0 
                                            ? Sign.NEGATIVE
                                            : Sign.ZERO));
    
            System.out.println(map);
        }
    }
    
    enum Sign {POSITIVE, NEGATIVE, ZERO}
    

    This yields the following output:

    {ZERO=[0], POSITIVE=[1, 1], NEGATIVE=[-1, -1]}
    

    Note: If you want peak performance for future lookups in your map, you can use an EnumMap instead. Take a look at this answer to see how.