Java Arena
Step 1 of 9

Why streams: filter and count

Since module 14, you've gone through lists with loops: a for-each loop, an if inside it, and a variable that counts or adds up. Java has a second way to do the same work, the stream. With a stream, you say what should happen to the values, one step after another, and Java does the looping for you.

One question, two ways

A cycling club keeps the distance of each ride, in kilometers. How many rides were longer than 50 km? Here's the answer with a loop, as you'd write it now:

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> rides = new ArrayList<>();
        rides.add(42);
        rides.add(65);
        rides.add(18);
        rides.add(80);
        rides.add(51);
        rides.add(30);

        int count = 0;
        for (int km : rides) {
            if (km > 50) {
                count++;
            }
        }
        System.out.println("Long rides: " + count);
    }
}
Output
Long rides: 3

And here's the same question with a stream:

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> rides = new ArrayList<>();
        rides.add(42);
        rides.add(65);
        rides.add(18);
        rides.add(80);
        rides.add(51);
        rides.add(30);

        long count = rides.stream()
                .filter(km -> km > 50)
                .count();
        System.out.println("Long rides: " + count);
    }
}
Output
Long rides: 3
  • rides.stream() makes a stream of the list's values, in the list's order. A stream isn't a list: it's a flow of values that passes through the steps you chain after it.
  • .filter(km -> km > 50) lets through only the values for which the condition is true. km -> km > 50 reads "take a value, call it km, and answer: is km greater than 50?" It's a lambda expression, and step 2 is all about them.
  • .count() counts the values that got through, and ends the stream. It returns a long, the bigger whole-number type that module 22 mentioned, so the variable is a long. It prints just like an int.

The chain is one statement, with one semicolon at the very end. It's split into lines before each dot, so that each line holds one step. Java doesn't mind the line breaks: rides.stream().filter(km -> km > 50).count() on one line works the same. The lines after the first are indented a little further, which shows that they continue the statement.

Read it out loud

The loop says how to find the answer: make a counter, go through the list, check each value, add one. The stream says what the answer is: from the rides, keep those over 50 km, and count them. The counter, the loop and the if are still there, but inside Java's code, not yours.

Both versions are right, and both are good Java. This module teaches the stream's tools one at a time, and step 9 comes back to when each way reads better.

The list stays as it was

filter doesn't remove anything from the list. The stream only reads the list's values, and the list is the same afterwards:

ArrayList<Integer> rides = new ArrayList<>();
rides.add(42);
rides.add(65);
rides.add(18);
long shortRides = rides.stream()
        .filter(km -> km < 20)
        .count();
System.out.println(shortRides);
System.out.println(rides);
Output
1
[42, 65, 18]

Two filters in a row

Each step passes the values it lets through on to the next step. Two filters in a row keep only the values that pass both, just like a condition with &&. The rides from 30 to 60 km:

ArrayList<Integer> rides = new ArrayList<>();
rides.add(42);
rides.add(65);
rides.add(18);
rides.add(80);
rides.add(51);
rides.add(30);
long middle = rides.stream()
        .filter(km -> km >= 30)
        .filter(km -> km <= 60)
        .count();
System.out.println(middle);
Output
3

42, 51 and 30 pass both filters. .filter(km -> km >= 30 && km <= 60) would give the same count.

Your task

Challenge 1 of 3

The club counts the rides of 100 km or more. Fill in the blanks: make a stream of the list, keep the rides of 100 km or more, and count them. The program prints:

Rides of 100 km or more: 3

Challenge 2

What does this program print?

Challenge 3

The club's app counts the short rides, under 20 km, with a loop. Rewrite the body of shortRides with a stream: stream(), filter and count, and no loop. Keep the method's header as it is. The check runs:

ArrayList<Integer> rides = new ArrayList<>();
rides.add(15);
rides.add(42);
rides.add(8);
rides.add(20);
System.out.println(shortRides(rides));

and expects:

2