Sitemap
Anuj Singh

Anuj Singh

Backend Developer at TCS

Press enter or click to view image in full size

Java Stream API: 10 Practical Problems I Practiced

5 min readSep 29, 2026

--

While learning Java Streams, I found that understanding individual methods like filter(), map(), reduce(), and collect() is not enough.

The real understanding comes when you start solving small problems using them.

In this post, I’m sharing some Stream API problems I practiced, along with the approach and code for each one.

Note: Most of these examples work with Java 8. Where I use .toList(), remember that Stream.toList() was introduced in Java 16 and it return unmodifiable list . In Java 8, use collect(Collectors.toList()).

1. Find Strings Starting With “A”

Problem

Given a list of names, find names starting with the character A.

List<String> names =
List.of("Anuj", "Amit", "Rahul", "Ankit", "Raj");

List<String> result =
names.stream()
.filter(n -> n.startsWith("A"))
.toList();
System.out.println(result);

Output

[Anuj, Amit, Ankit]

We can also write:

.filter(n -> n.charAt(0) == 'A')

Both approaches work.

However, for this particular requirement:

startsWith("A")

is more readable because the requirement itself is “starts with A”.

2. Remove Duplicates and Sort in Descending Order

Problem

Remove duplicate numbers and sort the result in descending order.

List<Integer> numbers =
List.of(10, 20, 10, 30, 20, 40, 50);

List<Integer> result =
numbers.stream()
.distinct()
.sorted(Comparator.reverseOrder())
.toList();
System.out.println(result);

Output

[50, 40, 30, 20, 10]

Important operations

distinct():

.distinct()

removes duplicate elements.

So:

10, 20, 10, 30, 20, 40, 50

becomes:

10, 20, 30, 40, 50

Then:

.sorted(Comparator.reverseOrder())

sorts the elements in descending order.

You might see:

.sorted((a, b) -> b - a)

This works for many normal integer values, but subtraction-based comparators can cause integer overflow.

For example, with extreme integer values, b - a may overflow.

A safer approach is:

.sorted(Comparator.reverseOrder())

or:

.sorted((a, b) -> Integer.compare(b, a))

3. Find the Sum of Numbers Greater Than 25

Problem

Find the sum of all numbers greater than 25.

List<Integer> numbers =
List.of(10, 20, 30, 40, 50);

int result =
numbers.stream()
.filter(n -> n > 25)
.mapToInt(Integer::intValue)
.sum();
System.out.println(result);

Output

120

Because:

30 + 40 + 50 = 120

Another approach using reduce()

We can also write:

Integer result =
numbers.stream()
.filter(n -> n > 25)
.reduce(0, (a, b) -> a + b);

Here:

reduce(0, (a, b) -> a + b)

starts with 0 and repeatedly combines the values.

For a simple sum, however:

.mapToInt(Integer::intValue)
.sum()

is more readable.

4. Find the First Number Greater Than 25

Problem

Find the first number greater than 25.

List<Integer> numbers =
List.of(10, 20, 30, 40, 50);

Optional<Integer> result =
numbers.stream()
.filter(n -> n > 25)
.findFirst();
System.out.println(result.orElse(null));

Output

30

Why Optional?

findFirst() returns:

Optional<Integer>

Because there might be no matching element.

For example:

List<Integer> numbers =
List.of(10, 20, 15);

There is no number greater than 25.

Instead of returning null, Java uses Optional to represent the possibility that a value may not exist.

You can also directly write:

Integer result =
numbers.stream()
.filter(n -> n > 25)
.findFirst()
.orElse(null);

5. Check Whether Any Number Is Greater Than 18

Problem

Check whether at least one number is greater than 18.

List<Integer> numbers =
List.of(5, 8, 12, 15, 20);

boolean result =
numbers.stream()
.anyMatch(n -> n > 18);
System.out.println(result);

Output

true

anyMatch() answers:

Does at least one element satisfy this condition?

In this case:

20 > 18

So the answer is true.

6. Check Whether All Numbers Are Positive

Problem

Check whether every number in the list is greater than zero.

List<Integer> numbers =
List.of(10, 20, 30, 40);

boolean result =
numbers.stream()
.allMatch(n -> n > 0);
System.out.println(result);

Output

true

allMatch() answers:

Do all elements satisfy this condition?

For example:

List<Integer> numbers =
List.of(10, 20, -5, 40);

Then:

.allMatch(n -> n > 0)

returns:

false

because -5 is not greater than zero.

7. Find the Longest String

Problem

Find the longest name from a list.

List<String> names =
List.of("Anuj", "Amit", "Rahul", "Ankit", "Raj");

Optional<String> result =
names.stream()
.max(Comparator.comparingInt(String::length));
System.out.println(result.orElse(null));

Output

Rahul

Here:

Comparator.comparingInt(String::length)

compares the Strings based on their length.

So:

Anuj   → 4
Amit → 4
Rahul → 5
Ankit → 5
Raj → 3

The maximum length is 5.

8. Find the Second Largest Number

Problem

Find the second largest distinct number.

List<Integer> numbers =
List.of(10, 50, 20, 50, 30, 40);

Optional<Integer> result =
numbers.stream()
.distinct()
.sorted(Comparator.reverseOrder())
.skip(1)
.findFirst();
System.out.println(result.orElse(null));

Output

40

Let’s understand the pipeline:

Get Anuj Singh’s stories in your inbox

Join Medium for free to get updates from this writer.

Original:

10, 50, 20, 50, 30, 40

After distinct():

10, 50, 20, 30, 40

After descending sort:

50, 40, 30, 20, 10

After:

.skip(1)

we skip 50:

40, 30, 20, 10

Then:

.findFirst()

returns:

40

9. Find Numbers That Occur Exactly Twice

This is a slightly more interesting problem.

Problem

Given:

List<Integer> numbers =
List.of(10, 50, 10, 50, 30, 40, 10, 30);

Find numbers that occur exactly twice.

List<Integer> result =
numbers.stream()
.filter(n -> Collections.frequency(numbers, n) == 2)
.distinct()
.toList();

System.out.println(result);

Output

[50, 30]

Frequency:

10 → 3
50 → 2
30 → 2
40 → 1

Therefore:

50 and 30

occur exactly twice.

Why distinct()?

Without:

.distinct()

the stream would contain:

50, 50, 30, 30

We only want:

50, 30

so we use distinct().

10. Find Strings Occurring At Least Twice

We can apply the same idea to Strings.

List<String> names =
List.of("Anuj", "Rahul", "Anuj", "Amit", "Rahul", "Anuj");

List<String> result =
names.stream()
.filter(n -> Collections.frequency(names, n) >= 2)
.distinct()
.toList();
System.out.println(result);

Output:

[Anuj, Rahul]

The frequencies are:

Anuj  → 3
Rahul → 2
Amit → 1

So only Anuj and Rahul satisfy:

frequency >= 2

11. Better Approach: groupingBy() + counting()

Although Collections.frequency() works, a better approach exists for frequency problems.

List<String> names =
List.of("Anuj", "Rahul", "Anuj", "Amit", "Rahul", "Anuj");

List<String> result =
names.stream()
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
))
.entrySet()
.stream()
.filter(e -> e.getValue() >= 2)
.map(Map.Entry::getKey)
.toList();
System.out.println(result);

Output:

[Anuj, Rahul]

What does groupingBy() produce?

Conceptually:

Anuj  → 3
Rahul → 2
Amit → 1

So we can think of it as:

Map<String, Long>

Then:

.filter(e -> e.getValue() >= 2)

keeps:

Anuj  → 3
Rahul → 2

And:

.map(Map.Entry::getKey)

extracts only the names:

Anuj
Rahul

Finally:

.toList()

stores them in a List<String>.

Important Stream Operations I Practiced

The problems above covered several commonly used Stream operations:

filter()

Used when we want to select elements based on a condition.

.filter(n -> n > 20)

map()

Used to transform elements.

.map(n -> n * n)

or:

.map(String::length)

distinct()

Removes duplicate elements.

.distinct()

sorted()

Sorts elements.

.sorted()

Descending:

.sorted(Comparator.reverseOrder())

reduce()

Combines elements into a single result.

.reduce(0, (a, b) -> a + b)

findFirst()

Returns the first matching element as an Optional.

.findFirst()

anyMatch()

Checks whether at least one element matches.

.anyMatch(n -> n > 18)

allMatch()

Checks whether every element matches.

.allMatch(n -> n > 0)

max()

Finds the maximum element according to a comparator.

.max(Comparator.comparingInt(String::length))

skip()

Skips a specified number of elements.

.skip(1)

collect()

Used to collect Stream results into a collection or another result type.

For example, in Java 8:

.collect(Collectors.toList())

In modern Java:

.toList()

Final Takeaway

The most important thing I learned from these exercises is that Stream API is not about memorizing methods individually.

It’s about understanding how operations can be combined into a pipeline:

Once the purpose of each operation becomes clear, solving Stream-based interview questions becomes much easier.

💡 Preparing for Java interviews? Follow me for more interview questions and answers on Java, Spring Boot, Microservices, SQL, and backend development — explained in a simple, practical, and interview-focused way. 🚀 Let’s crack interviews and grow together!

--

--