Stream.count: примеры (JAVA)

Примеры и поведение count в Java Stream
Раздел: Потоки данных (Stream API) - терминальные операции
Stream.count: long

Описание метода

Метод count() интерфейса java.util.stream.Stream и примитивных потоков (IntStream, LongStream, DoubleStream) представляет собой терминальную операцию, возвращающую количество элементов в потоке. Возвращаемый тип у всех реализаций - long. Метод не принимает аргументов.

Краткие характеристики:

  • Тип вызова: терминальная операция.
  • Параметры: отсутствуют.
  • Возвращаемое значение: число элементов типа long.
  • Поведение для пустого потока: возвращается 0.
  • Параллельность: корректно работает с последовательными и параллельными потоками; реализация использует разбиение источника через Spliterator.
  • Переиспользование: после терминальной операции поток становится недействительным; повторный вызов операций на том же объекте приведет к исключению.
  • Работа с бесконечными потоками: если поток бесконечен и не применяется ограничение (limit), вызов будет блокирующим и не завершится.

Особенности реализации и взаимодействия с API:

  • Для коллекций получение размера через Collection.size() обычно быстрее и константно по времени, тогда как stream().count() производит обход и имеет линейную сложность.
  • Альтернативой внутри Stream API является использование Collectors.counting() в собранных результатах, особенно при группировке.
  • count() гарантирует точный подсчет элементов, как они проходит через весь цепочку промежуточных операций (фильтрация, маппинг, distinct и т. п.).

Примеры простого применения

Ниже приведены простые случаи вызова метода count() с выводом кода и результата.

1) Подсчет элементов в потоке объектов

import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        long c = Stream.of("a", "b", "c").count();
        System.out.println(c);
    }
}
3

2) Подсчет с фильтрацией

import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        long evens = Stream.of(1, 2, 3, 4, 5, 6)
                           .filter(n -> n % 2 == 0)
                           .count();
        System.out.println(evens);
    }
}
3

3) Примитивный поток и диапазон

import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long cnt = IntStream.rangeClosed(1, 100).count();
        System.out.println(cnt);
    }
}
100

4) Параллельный подсчет

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        long cnt = Arrays.asList(1,2,3,4,5,6,7,8)
                           .parallelStream()
                           .filter(x -> x > 4)
                           .count();
        System.out.println(cnt);
    }
}
4

Похожие методы в Java

  • Collection.size() - предоставляет размер коллекции за константное время для большинства реализаций коллекций. Предпочтительнее, если доступен объект Collection и требуется просто его размер.
  • Collectors.counting() - используется в комбинации с collect(), полезен при группировке: groupingBy(..., Collectors.counting()). Возвращает Long для каждой группы.
  • Stream.reduce() или mapToLong(...).sum() - альтернативные способы подсчета, но менее выразительны и чаще избыточны по сравнению с count().

Выбор между этими вариантами определяется контекстом: для простого подсчета элементов в коллекции - size(), для подсчета с группировкой - Collectors.counting(), для подсчета на потоке без сохранения в коллекцию - count().

Аналоги в других языках

Краткие отличия и примеры подсчета элементов в популярных языках.

JavaScript - массивы и итераторы

// массив
const arr = [1,2,3];
console.log(arr.length);

// Итератор с фильтром
const count = [...arr].filter(x => x>1).length;
console.log(count);
3
2

Python - len и подсчет для итераторов

# список
lst = [1,2,3]
print(len(lst))

# генератор
cnt = sum(1 for x in lst if x%2==0)
print(cnt)
3
1

PHP - функция count()

$arr = [1,2,3];
echo count($arr);
3

SQL - агрегатная функция COUNT

SELECT COUNT(*) FROM users WHERE active = 1;
-- возвращает количество строк, соответствующих условию

C# - LINQ Count()

using System.Linq;

var arr = new[] {1,2,3,4};
Console.WriteLine(arr.Count());
Console.WriteLine(arr.Count(x => x%2==0));
4
2

Kotlin - count() и size

val list = listOf(1,2,3)
println(list.size)
println(list.count { it%2==0 })
3
1

Go - len для срезов; для каналов требуется обход

slice := []int{1,2,3}
fmt.Println(len(slice))

// для канала
cnt := 0
for v := range ch { cnt++ }
3
// cnt подсчитывается во время чтения канала

Lua - оператор # для массивоподобных таблиц

local t = {1,2,3}
print(#t)
3

Отличия от Java: в большинстве языков для коллекций есть константный способ получить размер (length, len, size), тогда как подсчет по потоку/итератору обычно требует обхода. В некоторых языках (Kotlin, C#) присутствуют удобные функции с предикатом, аналогичные Stream.filter(...).count().

Типичные ошибки и нюансы

  • IllegalStateException: повторный вызов операций на одном и том же объекте Stream. Пример:
    Stream s = Stream.of("a", "b");
    long c1 = s.count();
    long c2 = s.count(); // выбросит IllegalStateException: stream has already been operated upon or closed
    Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
     at ...
  • NullPointerException при вызове count() на null-ссылке вместо самого потока. Пример:
    Stream s = null;
    long c = s.count(); // NPE
    Exception in thread "main" java.lang.NullPointerException
     at ...
  • Блокировка при работе с бесконечными потоками без ограничения. Пример:
    long c = Stream.iterate(0, n -> n + 1).count(); // никогда не завершится
    // программа будет висеть, подсчет не завершится
  • Производительность: использование stream().count() для уже доступных коллекций менее эффективно, чем Collection.size() для тех коллекций, где размер хранится.
  • Переполнение: возвращаемый тип long; если гипотетически требуется подсчитать больше, чем Long.MAX_VALUE элементов, переполнение не проверяется явно.

Изменения в API

Метод count() введен в Java 8 вместе со Stream API и с тех пор сохраняет прежнее поведение: отсутствие параметров, возвращение long и терминальность. В последующих версиях Java существенных изменений в сигнатуре или семантике count() не происходило. Дополнялись смежные механизмы Stream API, улучшалась производительность и поддержка параллельного выполнения, но контракт метода остался прежним.

Расширенные и нестандартные примеры

1) Подсчет элементов по группам через groupingBy и Collectors.counting()

Пример java
import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        List names = Arrays.asList("Anna", "Bob", "Alice", "Bob");
        Map counts = names.stream()
                                        .collect(Collectors.groupingBy(n -> n, Collectors.counting()));
        System.out.println(counts);
    }
}
{Alice=1, Bob=2, Anna=1}

2) Подсчет уникальных элементов

Пример java
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        long distinct = Stream.of(1,2,2,3,3,3)
                              .distinct()
                              .count();
        System.out.println(distinct);
    }
}
3

3) Безопасный подсчет по ленивому потоку с ограничением (для потенциально бесконечных источников)

Пример java
import java.util.stream.Stream;

public class Main {
    public static void main(String[] args) {
        long cnt = Stream.iterate(0, n -> n + 1)
                         .limit(1000)
                         .filter(n -> n % 7 == 0)
                         .count();
        System.out.println(cnt);
    }
}
143

4) Подсчет с использованием параллельности и пользовательского источника

Пример java
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.StreamSupport;

public class Main {
    public static void main(String[] args) {
        Spliterator sp = Spliterators.spliteratorUnknownSize(
            java.util.stream.Stream.of(1,2,3,4,5,6).iterator(), 0);
        long cnt = StreamSupport.stream(sp, true) // параллельный
                                 .filter(x -> x > 2)
                                 .count();
        System.out.println(cnt);
    }
}
4

5) Подсчет элементов после сложной трансформации (map + flatMap)

Пример java
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        long cnt = Arrays.asList("a,b", "c", "d,e,f").stream()
            .flatMap(s -> Arrays.stream(s.split(",")))
            .count();
        System.out.println(cnt);
    }
}
6

6) Подсчет с ранним завершением с помощью limit для экономии ресурсов

Пример java
import java.util.stream.IntStream;

public class Main {
    public static void main(String[] args) {
        long cnt = IntStream.range(1, Integer.MAX_VALUE)
                            .filter(n -> n % 1000000 == 0)
                            .limit(5) // гарантирует, что count завершится
                            .count();
        System.out.println(cnt);
    }
}
5

Пояснения: в продвинутых сценариях чаще используется комбинация фильтрации, distinct, limit и группировок. При работе с большими данными предпочтение отдается параллельным потокам при этом учитывается стоимость разделения источника и безопасность данных.

джава Stream.count function comments

En
Stream.count Returns the count of elements in the stream