Find Even and Odd Numbers in a List Using Java Streams

In this tutorial, I will demonstrate how to find even and odd numbers in a List using the Java Stream API. This is a common Java coding interview question that helps you understand stream filtering, lambda expressions, and collection processing.

An even number is an integer that is divisible by 2 without leaving a remainder. An odd number is an integer that leaves a nonzero remainder when divided by 2.

Java Streams make it easy to separate even and odd numbers without writing traditional loops. You can use the filter() method to select values that match a condition or Collectors.partitioningBy() to divide a list into two groups.

In this tutorial, you will learn how to identify even and odd numbers using Streams, how to separate them using different approaches, and how to handle negative numbers, duplicates, and empty lists.

1. Problem Statement

Write a Java program to find even and odd numbers from a List of integers using the Stream API.

Example:

Input:
[10, 15, 20, 25, 30, 35, 40]

Output:
Even Numbers: [10, 20, 30, 40]
Odd Numbers: [15, 25, 35]

Explanation: Numbers divisible by 2 are classified as even, while the remaining integers are classified as odd.

The original order of elements is preserved in both resulting lists.

2. Method 1: Find Even and Odd Numbers Using Stream.filter()

The simplest way to find even and odd numbers using Java Streams is to use the filter() method.

The filter() method accepts a Predicate, which determines whether each element should be included in the result.

For even numbers, the condition is:

number % 2 == 0

For odd numbers, the condition is:

number % 2 != 0

Java Program Using Stream.filter()

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class EvenOddNumbersUsingStreams {

    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(
                10, 15, 20, 25, 30, 35, 40
        );

        // Find even numbers
        List<Integer> evenNumbers = numbers.stream()
                .filter(number -> number % 2 == 0)
                .collect(Collectors.toList());

        // Find odd numbers
        List<Integer> oddNumbers = numbers.stream()
                .filter(number -> number % 2 != 0)
                .collect(Collectors.toList());

        System.out.println("Original List: " + numbers);
        System.out.println("Even Numbers: " + evenNumbers);
        System.out.println("Odd Numbers: " + oddNumbers);
    }
}

Output

Original List: [10, 15, 20, 25, 30, 35, 40]
Even Numbers: [10, 20, 30, 40]
Odd Numbers: [15, 25, 35]

3. Step-by-Step Explanation

Step 1: Create a List of Integers

List<Integer> numbers = Arrays.asList(
        10, 15, 20, 25, 30, 35, 40
);

This statement creates a List containing seven integers.

The list includes both even and odd numbers.

Step 2: Convert the List into a Stream

numbers.stream()

The stream() method creates a sequential stream that allows you to process the list elements using Stream API operations.

Step 3: Filter Even Numbers

.filter(number -> number % 2 == 0)

The filter() method evaluates each element using the lambda expression.

The modulus operator % calculates the remainder after division.

  • If number % 2 == 0, the number is even.
  • If the condition is false, the number is excluded from the even-number stream.

Step 4: Filter Odd Numbers

.filter(number -> number % 2 != 0)

This condition selects numbers whose remainder after division by 2 is not zero.

For example:

  • 15 % 2 produces 1, so 15 is odd.
  • 20 % 2 produces 0, so 20 is even.
  • -7 % 2 produces -1, so -7 is odd.

Using != 0 is important because it correctly identifies negative odd numbers.

Step 5: Collect the Results into Lists

.collect(Collectors.toList());

The collect() operation gathers the filtered values into a List.

The original list remains unchanged.

4. Method 2: Find Even and Odd Numbers Using Collectors.partitioningBy()

The Collectors.partitioningBy() method provides another way to separate even and odd numbers.

Instead of filtering the original list twice, this method divides the elements into two groups based on a boolean condition during a single stream traversal.

The result is a Map<Boolean, List<Integer>> containing two entries:

  • true contains elements that satisfy the predicate.
  • false contains elements that do not satisfy the predicate.

If the predicate checks whether a number is even, the true group contains even numbers and the false group contains odd numbers.

Java Program Using partitioningBy()

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class EvenOddUsingPartitioning {

    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(
                10, 15, 20, 25, 30, 35, 40
        );

        // Partition numbers into even and odd groups
        Map<Boolean, List<Integer>> partitioned =
                numbers.stream()
                        .collect(Collectors.partitioningBy(
                                number -> number % 2 == 0
                        ));

        List<Integer> evenNumbers = partitioned.get(true);
        List<Integer> oddNumbers = partitioned.get(false);

        System.out.println("Original List: " + numbers);
        System.out.println("Even Numbers: " + evenNumbers);
        System.out.println("Odd Numbers: " + oddNumbers);
    }
}

Output

Original List: [10, 15, 20, 25, 30, 35, 40]
Even Numbers: [10, 20, 30, 40]
Odd Numbers: [15, 25, 35]

How partitioningBy() Works

Consider this statement:

Map<Boolean, List<Integer>> partitioned =
        numbers.stream()
                .collect(Collectors.partitioningBy(
                        number -> number % 2 == 0
                ));

The predicate number % 2 == 0 checks whether each integer is even.

Based on the result, the collector places each number into the appropriate group.

Conceptually, the resulting map contains:

true  = [10, 20, 30, 40]
false = [15, 25, 35]

Retrieve the two lists using:

List<Integer> evenNumbers = partitioned.get(true);

List<Integer> oddNumbers = partitioned.get(false);

This approach is especially useful when your program needs both groups.

5. Method 3: Find Even and Odd Numbers Using Stream.toList() in Java 16+

If you use Java 16 or later, you can simplify the filtering code by using the Stream.toList() method.

This method collects stream elements into an unmodifiable List.

Java Program

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

public class EvenOddUsingToList {

    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(
                10, 15, 20, 25, 30, 35, 40
        );

        // Even numbers
        List<Integer> evenNumbers = numbers.stream()
                .filter(number -> number % 2 == 0)
                .toList();

        // Odd numbers
        List<Integer> oddNumbers = numbers.stream()
                .filter(number -> number % 2 != 0)
                .toList();

        System.out.println("Even Numbers: " + evenNumbers);
        System.out.println("Odd Numbers: " + oddNumbers);
    }
}

Output

Even Numbers: [10, 20, 30, 40]
Odd Numbers: [15, 25, 35]

The toList() method makes the code concise, but remember that the returned lists cannot be modified.

For Java 8 compatibility, use collect(Collectors.toList()) instead.

6. Dry Run: Separating Even and Odd Numbers

Let's understand how the filtering condition works with the following list:

Input:
[10, 15, 20, 25, 30]

For each number, the algorithm calculates the remainder after division by 2.

Number number % 2 Classification Selected Group
10 0 Even Even List
15 1 Odd Odd List
20 0 Even Even List
25 1 Odd Odd List
30 0 Even Even List

Final result:

Even Numbers: [10, 20, 30]
Odd Numbers: [15, 25]

7. Find Even and Odd Numbers Including Negative Values

Even and odd classification works with negative integers as well.

However, you should use number % 2 != 0 when checking for odd numbers instead of number % 2 == 1.

The second condition does not correctly identify negative odd numbers in Java.

Java Program

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class EvenOddWithNegativeNumbers {

    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(
                -10, -7, -4, -3, 0, 5, 8, 11
        );

        Map<Boolean, List<Integer>> result =
                numbers.stream()
                        .collect(Collectors.partitioningBy(
                                number -> number % 2 == 0
                        ));

        System.out.println("Even Numbers: " + result.get(true));
        System.out.println("Odd Numbers: " + result.get(false));
    }
}

Output

Even Numbers: [-10, -4, 0, 8]
Odd Numbers: [-7, -3, 5, 11]

Notice that zero is classified as an even number because it is divisible by 2 with a remainder of zero.

8. Count Even and Odd Numbers Using Streams

Sometimes, an interview question asks you to count even and odd numbers instead of returning their values.

You can use the count() terminal operation to determine how many elements match each condition.

Java Program

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

public class CountEvenOddNumbers {

    public static void main(String[] args) {

        List<Integer> numbers = Arrays.asList(
                10, 15, 20, 25, 30, 35, 40
        );

        long evenCount = numbers.stream()
                .filter(number -> number % 2 == 0)
                .count();

        long oddCount = numbers.stream()
                .filter(number -> number % 2 != 0)
                .count();

        System.out.println("Even Count: " + evenCount);
        System.out.println("Odd Count: " + oddCount);
    }
}

Output

Even Count: 4
Odd Count: 3

The count() method returns a long representing the number of elements in the filtered stream.

9. Time and Space Complexity

Let's compare the main approaches.

Approach Time Complexity Result Storage List Traversals
Two filter() operations O(n) O(n) 2
Collectors.partitioningBy() O(n) O(n) 1
Two count() operations O(n) O(1) 2

Here, n represents the number of elements in the input list.

Filtering or partitioning requires checking each element, so the overall time complexity is O(n).

When you collect even and odd numbers into lists, the results require O(n) additional storage because every input element appears in one of the output lists.

If you only count matching elements, the counting results require constant additional space.

Which Approach Is More Efficient?

If you need only even numbers or only odd numbers, filter() is a natural choice.

If you need both lists, Collectors.partitioningBy() is generally preferable because it classifies the elements in one traversal.

10. Handling Important Edge Cases

Case 1: Empty List

Input:
[]

Output:
Even Numbers: []
Odd Numbers: []

Both filtering and partitioning handle empty lists.

Case 2: All Numbers Are Even

Input:
[2, 4, 6, 8]

Output:
Even Numbers: [2, 4, 6, 8]
Odd Numbers: []

Case 3: All Numbers Are Odd

Input:
[1, 3, 5, 7]

Output:
Even Numbers: []
Odd Numbers: [1, 3, 5, 7]

Case 4: List Contains Duplicate Values

Input:
[2, 3, 2, 4, 3, 5]

Output:
Even Numbers: [2, 2, 4]
Odd Numbers: [3, 3, 5]

Duplicate values are preserved. Filtering does not remove duplicates unless you also apply distinct().

Case 5: List Contains Zero

Input:
[0, 1, 2, 3]

Output:
Even Numbers: [0, 2]
Odd Numbers: [1, 3]

Zero is an even number.

Case 6: List Contains Null Elements

The examples assume that every list element is a non-null Integer.

If null values are possible, filter them out before applying the modulus operation:

List<Integer> evenNumbers = numbers.stream()
        .filter(number -> number != null)
        .filter(number -> number % 2 == 0)
        .toList();

This prevents a NullPointerException caused by unboxing a null Integer.

11. Common Mistakes to Avoid

Mistake 1: Using number % 2 == 1 for Odd Numbers

A common mistake is checking odd numbers using:

number % 2 == 1

This condition fails for negative odd numbers because Java can produce a negative remainder.

Use the following condition instead:

number % 2 != 0

Mistake 2: Assuming filter() Modifies the Original List

The filter() method produces a stream containing matching elements. It does not remove elements from the original collection.

Use a terminal operation such as collect(), toList(), or count() to obtain the result.

Mistake 3: Reusing the Same Stream

A Stream cannot be reused after a terminal operation has consumed it.

For example, you cannot call collect() twice on the same stream instance.

Create a new stream for each filtering operation, or use partitioningBy() to produce both groups in a single pipeline.

Mistake 4: Confusing partitioningBy() Keys

When you use number % 2 == 0 as the predicate:

  • true represents even numbers.
  • false represents odd numbers.

If you change the predicate, the meanings of the keys may change accordingly.

12. Frequently Asked Questions

Q1. How do I find even numbers using Java Streams?

Use the filter() method with the condition number % 2 == 0.

List<Integer> even = numbers.stream()
        .filter(number -> number % 2 == 0)
        .toList();

Q2. How do I find odd numbers using Java Streams?

Use number % 2 != 0 as the filtering condition.

List<Integer> odd = numbers.stream()
        .filter(number -> number % 2 != 0)
        .toList();

Q3. How can I separate even and odd numbers in a single Stream?

Use Collectors.partitioningBy() with the condition number % 2 == 0. It divides the elements into two groups during one traversal.

Q4. What is the difference between filter() and partitioningBy()?

The filter() method selects elements that satisfy a condition. The partitioningBy() collector separates all elements into two groups based on whether the condition is true or false.

Q5. Does Java Stream filtering preserve the original order?

Yes. For a sequential ordered stream created from a List, filtering and collecting preserve the encounter order of the selected elements.

Q6. Can I find even and odd numbers from negative integers?

Yes. The modulus operator works with negative numbers. Use % 2 == 0 for even numbers and % 2 != 0 for odd numbers.

Q7. What is the time complexity of finding even and odd numbers using Streams?

The overall time complexity is O(n), where n is the number of elements.

Q8. Is zero an even or odd number?

Zero is an even number because dividing it by 2 produces a remainder of zero.

13. Conclusion

In this tutorial, you learned how to find even and odd numbers from a List using the Java Stream API.

  • Stream.filter(): Selects even or odd numbers based on a condition.
  • Collectors.partitioningBy(): Separates even and odd numbers into two groups in one traversal.
  • Stream.toList(): Provides a concise way to collect results in Java 16 and later.
  • Stream.count(): Counts matching even or odd numbers.

For Java coding interviews, I recommend learning the filter() approach first because it is simple and clearly demonstrates stream filtering with lambda expressions.

Once you understand filtering, practice Collectors.partitioningBy(). It is especially useful when you need to divide a collection into two groups based on a boolean condition.

These techniques are also helpful for more advanced Java Stream problems involving filtering, grouping, partitioning, and counting collection elements.

14. Official Java Documentation

For more information about the Java APIs used in this tutorial, refer to the official Oracle documentation:

Continue Learning with Java Guides

Want to take your programming skills to the next level? Explore my practical Udemy courses on Java, Spring Boot, Microservices, Full-Stack Development, Docker, and Generative AI. You can also follow my structured learning roadmaps to become a professional developer.

By Ramesh Fadatare - Udemy Instructor Partner

Comments