Guide to Java 8 Collectors: counting()

Introduction

A stream represents a sequence of elements and supports different kinds of operations that lead to the desired result. The source of a stream is usually a Collection or an Array, from which data is streamed from.

Streams differ from collections in several ways; most notably in that the streams are not a data structure that stores elements. They're functional in nature, and it's worth noting that operations on a stream produce a result and typically return another stream, but do not modify its source.

To "solidify" the changes, you collect the elements of a stream back into a Collection.

In this guide, we'll take a look at how to count elements in a Java Stream with the help of Collectors.counting().

Collectors and Stream.collect()

Collectors represent implementations of the Collector interface, which implements various useful reduction operations, such as accumulating elements into collections, summarizing elements based on a specific parameter, etc.

All predefined implementations can be found within the Collectors class.

You can also very easily implement your own collector and use it instead of the predefined ones, though - you can get pretty far with the built-in collectors, as they cover the vast majority of cases in which you might want to use them.

To be able to use the class in our code we need to import it:

import static java.util.stream.Collectors.*;

Stream.collect() performs a mutable reduction operation on the elements of the stream.

A mutable reduction operation collects input elements into a mutable container, such as a Collection, as it processes the elements of the stream.

Guide to Collectors.counting()

The Collectors.counting() method returns a Collector accepting the elements of type T, and counts the number of input elements. The method has the following syntax:

public static <T> Collector<T,?,Long> counting()

The usage of the collector is really straightforward - you just chuck it into the collect() method. Let's create a "grocery shopping list" with a few items, and then count the number of elements in the list with Collectors.counting():

List<String> groceryList = Arrays.asList("apples", "milk", "meat", "eggs", "juice");
long result = groceryList.stream().collect(Collectors.counting());

System.out.println(result);

This results in:

5

Note: The return type of the counting() method is always Long.

Collectors.counting() as a Downstream Collector

We can also use Collectors.counting() as a downstream function in another collector that accepts a downstream collector/function.

Collectors.groupingBy() or Collectors.groupingByConcurrent() are two great examples of this, and they're both commonly used with Collectors.counting().

If you'd like to read more about these two collectors, read our Guide to Java 8 Collectors: groupingBy() and Guide to Java 8 Collectors: groupingByConcurrent()!

This is a more common use-case than just counting the number of elements in a stream, created from a collection. Since this is most commonly done on custom objects, rather than primitive types or Strings - let's define a simple Book model:

public class Book {
    private String title;
    private String author;
    private int releaseYear;
    private int soldCopies;

    // Constructor, getters and setters

And let's instantiate a List of Books:

List<Book> books = Arrays.asList(
    new Book("The Fellowship of the Ring", "J.R.R. Tolkien", 1954, 30),
    new Book("The Hobbit", "J.R.R. Tolkien", 1937, 40),
    new Book("Animal Farm", "George Orwell", 1945, 37),
    new Book("Nineteen Eighty-Four", "George Orwell", 1949, 55),
    new Book("The Road to Wigan Pier", "George Orwell", 1937, 25),
    new Book("Lord of the Flies", "William Golding", 1954, 44)
);

Let's say we own a small book shop offering these titles, and the soldCopies is the quantity sold of a particular title. We want to count how many titles of a specific author have sold over 35 copies.

This entails filtering the stream, based on the soldCopies field, then grouping the books by author, and counting the books associated with each author (group).

Since the groupingBy() method returns a map - our map will then consist of a String (author) and Long (result of the count):

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

Map<String, Long> soldCopiesStats = books.stream().filter(book -> book.getSoldCopies() > 35)
    .collect(Collectors.groupingBy(Book::getAuthor, Collectors.counting()));

System.out.println(soldCopiesStats);

If you'd like to read more about the filter() method, read our Java 8 Streams: Guide to the filter() Method!

We've used Collectors.counting() as a downstream function for Collectors.groupingBy(), which can come quite useful in getting some nice statistics.

When we run this piece of code, we get the following result:

{J.R.R. Tolkien=1, William Golding=1, George Orwell=2}

Conclusion

In this guide, we've covered the Collectors.counting() method. It can come quite useful in many cases as the count of elements is an insightful metric. We've taken a look at how to count the number of elements in a stream, as well as how to use it as a downstream collector with other collectors, such as groupingBy() to get a simple statistical count of elements, based on certain criteria.

Last Updated: November 16th, 2021
Was this article helpful?

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms