count()

Count the elements of a stream as a long, understand why it may skip your pipeline, and avoid counting when you only need to know if anything matches.

Signature
long count()
  • Added in Java Java 8

Return value

longThe number of elements in the stream.

Errors

Nothing directly. Exceptions from earlier steps surface if the pipeline has to run.

Changelog

  • PHP Java 9The documentation now states that count may compute the result directly from the source without running the pipeline, so steps such as peek or map may not execute when the size is already known.

count() is a terminal operation that returns how many elements reach the end of the pipeline. It returns a long, so assigning it to an int needs a cast or, safer, Math.toIntExact(count), which throws instead of silently overflowing.

Counting matches

The most common use is filter(...).count(): how many orders are pending, how many users are inactive, how many lines failed validation. For counts per group, use Collectors.groupingBy(key, Collectors.counting()) instead of calling count() once per group, which would walk the data repeatedly.

count may not run your pipeline

Since Java 9 the documentation says an implementation may work out the count straight from the source if it can, without executing the pipeline. In practice, when the source knows its size (a list or an array) and no step can change the number of elements, the JDK returns the size and skips the steps. list.stream().peek(log::info).count() logs nothing. map and sorted do not change the count either, so they may be skipped too. A filter, distinct or flatMap forces the pipeline to run.

This only bites code that relies on side effects in intermediate steps, which is a reason to keep those steps free of side effects. Never use count() as a way to force a map or peek to run.

Do not count to test for existence

stream.filter(p).count() > 0 walks every element even when the first one matches. anyMatch(p) stops at the first match, and noneMatch(p) expresses the negative. The same goes for count() == 0: on a collection use isEmpty().

Back-end notes

Counting in Java means loading the rows first. If the data lives in a database, SELECT COUNT(*) with a WHERE clause is far cheaper than fetching every row to call count(). In-memory counting is the right tool for data you already have: a page of results, a parsed upload, a list of validation errors.

When the source is a collection and there is no filter, collection.size() is simpler and returns an int.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Report how many rows of an uploaded CSV failed validation in the import response.
  • Count HTTP status codes per group from a batch of parsed access log lines for a metrics endpoint.
  • Check how many items in a basket are out of stock before allowing checkout.

Frequently asked questions

Why does Stream.count return a long instead of an int?

Streams are not limited to collection sizes; a stream can have more than Integer.MAX_VALUE elements. Use Math.toIntExact(count) when you need an int, so an overflow throws ArithmeticException instead of wrapping.

Why is my peek or map not called when I use count()?

Since Java 9, count may compute the size directly from the source when no step in the pipeline can change the number of elements, and then skips the pipeline. Do not rely on side effects in intermediate operations.

How do I count occurrences of each value in a list?

Use list.stream().collect(Collectors.groupingBy(v -> v, Collectors.counting())). Pass TreeMap::new as the map factory if you want the keys sorted.

More examples

count can skip the pipeline

In the first pipeline the size is known from the list and peek cannot change it, so count returns 3 without running peek. The filter in the second pipeline could change the number, so every element is processed.

Example · java
void main() {
    List<String> ids = List.of("a", "b", "c");

    long n = ids.stream()
        .peek(id -> IO.println("saw " + id))
        .count();
    IO.println(n);

    long m = ids.stream()
        .peek(id -> IO.println("saw " + id))
        .filter(id -> !id.equals("b"))
        .count();
    IO.println(m);
}
// Output:
// 3
// saw a
// saw b
// saw c
// 2

Counting per group

groupingBy with counting gives every group's count in one pass, which suits status-code summaries from access logs. A TreeMap keeps the keys in a stable, sorted order.

Example · java
void main() {
    List<String> statuses = List.of("200", "404", "200", "500", "200", "404");

    Map<String, Long> byStatus = statuses.stream()
        .collect(Collectors.groupingBy(s -> s, TreeMap::new, Collectors.counting()));
    IO.println(byStatus);

    long errors = statuses.stream().filter(s -> s.startsWith("5")).count();
    IO.println("server errors: " + errors);
}
// Output:
// {200=3, 404=2, 500=1}
// server errors: 1

anyMatch stops, count does not

Both answer whether there is an error, but count has to visit every element while anyMatch stops at the first match. For large inputs or expensive steps, that difference is real work saved.

Example · java
void main() {
    int[] visited = {0};

    boolean viaCount = Stream.of("ok", "error", "ok", "ok")
        .peek(s -> visited[0]++)
        .filter(s -> s.equals("error"))
        .count() > 0;
    IO.println(viaCount + " after " + visited[0]);

    visited[0] = 0;
    boolean viaAnyMatch = Stream.of("ok", "error", "ok", "ok")
        .peek(s -> visited[0]++)
        .anyMatch(s -> s.equals("error"));
    IO.println(viaAnyMatch + " after " + visited[0]);
}
// Output:
// true after 4
// true after 2

Discussion

  • Be the first to comment on this lesson.