Loading
October 26, 2026

AmirHesamTech

Raspberry Pi, homelab, Linux and automation — projects and practical guides

Java Stream API: 22 runnable examples, one operation per file

The Java Stream API is much easier to learn when you can run one operation at a time and watch what it prints. That’s the whole idea of my StreamAPIInJava repository: every Stream operation lives in its own file, with its own main method, its own small list of data and comments that explain what’s about to happen. Open a file, press run, read the output.

  • 22 runnable examples, one operation each.
  • Plain Java — no Maven, no Gradle, no libraries. Any IDE with a JDK opens it.
  • Java 8 or newer, since that’s when streams arrived.

Run your first example

git clone https://github.com/amirh3sam/StreamAPIInJava.git
cd StreamAPIInJava/src
javac Stream_Filter.java && java Stream_Filter

Each file is independent, so there’s no order to follow. Start with Stream_Filter, Stream_Map and Stream_Count — those three cover most of what you’ll use day to day.

Two kinds of operations

Intermediate operations return another stream, so you can chain them — and nothing runs until the chain ends. Terminal operations end the chain and produce a result; after one runs, the stream is used up.

Advertisement
Intermediate (chainable) What it does Terminal (ends the chain) What it does
filter() Keeps elements that pass a test count() How many are left
map() Turns each element into something else reduce() Folds everything into one value
flatMap() Flattens a list of lists min() / max() Smallest / largest
distinct() Drops duplicates findFirst() / findAny() One element, if there is one
sorted() Sorts, naturally or with a comparator allMatch() / anyMatch() / noneMatch() True or false tests
limit() / skip() Keep the first n / throw away the first n toArray() Back to a plain array
peek() Look at each element as it passes (debugging) collect() / forEach() Into a collection / do something with each

The repo also has concat() and parallelStream(), plus written notes in src/Stream.txt.

filter: keep only what passes

From Stream_Filter.java:

List<Integer> numbers = new ArrayList<Integer>(Arrays.asList(2,1,23,40,56,100,33));

List<Integer> evenNumbers = numbers.stream()
        .filter(each -> each % 2 == 0)
        .collect(Collectors.toList());
System.out.println(evenNumbers);      // [2, 40, 56, 100]

// several conditions in one filter: numbers between 2 and 40
numbers.stream()
        .filter(e -> e > 2 && e < 40)
        .forEach(System.out::println);  // 23, 33

forEach(each -> System.out.println(each)) and forEach(System.out::println) do exactly the same thing — the second is a method reference.

map vs flatMap

The question everyone asks. Condensed from Stream_FlatMap.java:

// map: one output for each input
List<Integer> num = new ArrayList<Integer>(Arrays.asList(1, 2, 4));
List<Integer> num2 = num.stream().map(e -> e + 2).collect(Collectors.toList());
System.out.println(num2);                 // [3, 4, 6]

// flatMap: each input is a whole list, and you want one flat list
List<List<Integer>> allNums = Arrays.asList(
        Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6), Arrays.asList(7, 8, 9));
List<Integer> flat = allNums.stream().flatMap(e -> e.stream()).collect(Collectors.toList());
System.out.println(flat);                 // [1, 2, 3, 4, 5, 6, 7, 8, 9]

reduce, and the identity trap

From Stream_Reduce.java:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce(0, (a, b) -> a + b);              // 15

List<Integer> newNumbers = Arrays.asList(10, 5, 8, 20, 15);
Integer max = newNumbers.stream().reduce(Integer.MIN_VALUE, Integer::max);  // 20
Integer min = newNumbers.stream().reduce(Integer.MAX_VALUE, Integer::min);  // 5

The first argument is the identity. One example in the file starts a sum at 3 instead of 0 — reduce(3, (x, y) -> x + y) over 1 to 6 — to show that the starting value is added in, giving 24 instead of 21. That’s worth understanding, and also worth not doing in real code: the identity is supposed to be the neutral value (0 for adding, 1 for multiplying), because on a parallel stream it can be applied once per chunk, and the answer changes with the number of chunks.

Five things to remember

  1. Nothing runs until the terminal operation. filter() and map() on their own only describe the work — which is why peek() prints nothing without a terminal operation after it.
  2. A stream can only be used once. A second terminal operation on the same stream throws IllegalStateException. Make a new stream from the collection.
  3. The original collection never changes. Streams produce a new result; assign it if you want to keep it.
  4. min, max, findFirst and findAny return an Optional, because there may be nothing left. Prefer .orElse(...) to .get() when you’re not sure.
  5. Parallel isn’t automatically faster. Splitting and merging costs time; on a short list a parallel stream is slower. It pays off on large data with independent work.

Why this matters for testers

Streams are everywhere in Java test code: filtering the rows a page returned, mapping web elements to their text, checking that every value in an API response passes a rule with allMatch(). If you’re learning test automation in Java, these 22 files are a quick way to get fluent — and my Java test automation framework is the place to use them.

Frequently asked questions

There’s no pom.xml — how do I open it?

That’s on purpose: it’s plain Java with no dependencies. Open the folder as a project in your IDE, select a JDK, and run any file.

findFirst or findAny?

On a normal stream they behave the same. On a parallel stream findAny can return whichever result finishes first, so it doesn’t have to wait to work out which element was really first.

Which Java version do I need?

Java 8 or anything newer.

All 22 examples: StreamAPIInJava on GitHub. Learning more than one language? See the same tasks solved in Java, Python, JavaScript and TypeScript.

Advertisement

65 Posts

SDET and QA engineer. I build Raspberry Pi servers, a Proxmox homelab and automations, and share how on TikTok and Instagram (@techwithamirh3sam).

View All Posts

You Missed

REWARDS 🔰 LV1 0🪙 ❯
🔰
Recruit
Guest Operative
Level1
XP0 / 100
💬 Need help?
coins0
Streak0 days · best 0
📋 Daily missions
↻ Resets daily at midnight
Rank ladder
How to earn
✓ Welcome bonus for joining — +200 🪙 & +100 XP (one-time)
✓ Daily check-in (streak bonus) — +20 XP & +12–24 🪙 (more 🪙 the longer your streak)
✓ Spin the daily wheel — +10 to +150 🪙 (free, once a day)
✓ Daily missions — check-in +15 🪙/+10 XP · daily spin +15 🪙/+10 XP
✓ Finish ALL daily missions — +30 🪙 & +20 XP bonus
✓ Level up — +25 🪙 every new level
✓ Achievements — first sign-in +50 🪙 · Lv5 +75 · Lv10 +150 · Lv25 +300 · 7-day streak +100 · 30-day +250 · collector +100 · subscriber +50
✓ Complete your profile (name, bio, photo) — up to +55 XP (one-time)
✓ Subscribe to the newsletter — +250 🪙 (one-time)
Coins and XP are just for fun: they have no cash value and can't be exchanged for money or prizes. You never earn them for viewing or clicking ads, or for how many pages or articles you open.
🛒 Token Shop0 🪙
🛍️ Shop0items
🎒 Inventory0items

🎡 Daily Spin

One free spin every day — pure bonus coins!
🪙
💬Need help?