Guía para coleccionistas de Java 8: contar()

En esta guía, aprenda cómo contar la cantidad de elementos en una colección o secuencia en Java, así como también cómo usar Collectors.counting() como una función descendente de otros recopiladores, con ejemplos.

Introducción

Una secuencia representa una secuencia de elementos y admite diferentes tipos de operaciones que conducen al resultado deseado. La fuente de un flujo suele ser una Colección o un Array, desde el cual se transmiten los datos.

Los flujos se diferencian de las colecciones en varios aspectos; sobre todo porque los flujos no son una estructura de datos que almacena elementos. Son de naturaleza funcional, y vale la pena señalar que las operaciones en un flujo producen un resultado y, por lo general, devuelven otro flujo, pero no modifican su origen.

Para "solidificar" los cambios, reúne los elementos de un flujo en una Colección.

En esta guía, veremos cómo contar elementos en un flujo de Java con la ayuda de Collectors.counting().

Coleccionistas y Stream.collect()

Los recopiladores representan implementaciones de la interfaz Collector, que implementa varias operaciones de reducción útiles, como acumular elementos en colecciones, resumir elementos en función de un parámetro específico, etc.

Todas las implementaciones predefinidas se pueden encontrar dentro de la clase Collectors.

Sin embargo, también puede implementar muy fácilmente su propio recopilador y usarlo en lugar de los predefinidos; puede llegar bastante lejos con los recopiladores integrados, ya que cubren la gran mayoría de los casos en los que es posible que desee usarlos.

Para poder usar la clase en nuestro código necesitamos importarla:

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

Stream.collect() realiza una operación de reducción mutable en los elementos de la secuencia.

{.icon aria-hidden=“true”}

Una operación de reducción mutable recopila elementos de entrada en un contenedor mutable, como una Colección, mientras procesa los elementos de la secuencia.

Guía de coleccionistas.conteo()

El método Collectors.counting() devuelve un Collector que acepta los elementos de tipo T y cuenta el número de elementos de entrada. El método tiene la siguiente sintaxis:

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

El uso del recopilador es realmente sencillo: simplemente lo introduce en el método collect(). Vamos a crear una "lista de compras del supermercado" con algunos artículos, y luego contar el número de elementos en la lista con Collectors.counting():

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

System.out.println(result);

Esto resulta en:

1
5

{.icon aria-hidden=“true”}

Nota: El tipo de retorno del método counting() siempre es Largo.

Collectors.counting() como un recopilador descendente

También podemos usar Collectors.counting() como una función descendente en otro recopilador que acepta una función/recolector descendente.

Collectors.groupingBy() o Collectors.groupingByConcurrent() son dos excelentes ejemplos de esto, y ambos se usan comúnmente con Collectors.counting().

If you'd like to read more about these two collectors, read our Guía de recopiladores de Java 8: groupingBy() and Guía de recopiladores de Java 8: groupingByConcurrent()!

Este es un caso de uso más común que solo contar la cantidad de elementos en una secuencia, creada a partir de una colección. Dado que esto se hace más comúnmente en objetos personalizados, en lugar de tipos primitivos o Cadenas, definamos un modelo Libro simple:

1
2
3
4
5
6
7
public class Book {
    private String title;
    private String author;
    private int releaseYear;
    private int soldCopies;

    // Constructor, getters and setters

Y vamos a instanciar una Lista de Libros:

1
2
3
4
5
6
7
8
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)
);

Digamos que tenemos una pequeña librería que ofrece estos títulos, y Copias vendidas es la cantidad vendida de un título en particular. Queremos contar cuántos títulos de un autor específico se han vendido sobre 35 copias.

Esto implica filtrar el flujo, según el campo Copias vendidas, luego agrupar los libros por autor y contar los libros asociados con cada autor (grupo).

Dado que el método groupingBy() devuelve un mapa, nuestro mapa consistirá en un String (autor) y Long (resultado del conteo):

1
2
3
4
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: Guía del método filter()!

Hemos usado Collectors.counting() como una función descendente para Collectors.groupingBy(), que puede ser bastante útil para obtener buenas estadísticas.

Cuando ejecutamos este fragmento de código, obtenemos el siguiente resultado:

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

Conclusión

En esta guía, hemos cubierto el método Collectors.counting(). Puede resultar bastante útil en muchos casos, ya que el recuento de elementos es una métrica perspicaz. Hemos echado un vistazo a cómo contar la cantidad de elementos en un flujo, así como también cómo usarlo como un recopilador posterior con otros recopiladores, como groupingBy() para obtener un recuento estadístico simple de elementos, en base a ciertos criterios.