Какую гарантию даёт underestimatedCount у Sequence и почему его нельзя использовать как точный размер?
underestimatedCount возвращает нижнюю границу количества элементов: значение не превышает фактическое число элементов, но может быть меньше него, включая ноль. Это оценка для предварительного резервирования памяти, а не точный размер и не условие остановки обхода.
Произвольный Sequence может не знать число элементов заранее или вычислять его только полным обходом. Нижняя оценка появилась как компромисс: алгоритм может заранее зарезервировать часть ёмкости результата и сократить количество перераспределений памяти, не требуя отдельного полного прохода.
Подход особенно полезен при построении массива из последовательности, когда точный размер неизвестен, а сама последовательность может быть однопроходной.
Если принять underestimatedCount за точный размер, можно неправильно определить пустую последовательность, преждевременно завершить обработку или выделить неподходящую структуру данных. Недооценка сама по себе безопасна: результат всё равно должен достраиваться по мере обхода.
Важно также не путать нижнюю границу с верхней. Последовательность может содержать больше элементов, чем вернуло свойство, поэтому значение нельзя использовать для ограничения числа вызовов next().
Контракт свойства прост: оно возвращает неотрицательное значение, которое не больше фактического количества элементов последовательности. Реализация может вернуть точное значение, полезную оценку или 0, если недорогая оценка неизвестна.
Типичный потребитель использует оценку только как подсказку:
reserveCapacity не фиксирует размер массива и не добавляет элементы. Если фактическая последовательность длиннее оценки, массив автоматически расширится; если короче, логическое количество элементов останется фактическим.
Для произвольного Sequence точный размер в общем случае можно получить только обходом. Но такой обход может потребить однопроходную последовательность, а второй обход может быть невозможен или дать другой результат. Если тип является Collection, его count — точное количество элементов, хотя стоимость получения может зависеть от конкретной коллекции.
При создании собственного Sequence следует возвращать только дешёвую и гарантированно не завышенную оценку. Если такой оценки нет, корректный результат — 0; завышенное значение нарушает контракт и может привести к избыточному выделению памяти.
Функция собирает результаты чтения большого потока в массив. Рассматривались три варианта: не резервировать ёмкость, сначала полностью посчитать элементы или использовать underestimatedCount.
Первый вариант проще, но может вызвать несколько расширений массива. Второй потенциально уменьшает перераспределения, однако требует дополнительного прохода и непригоден для однопроходного источника. Третий вариант сохраняет один проход и использует безопасную нижнюю границу, поэтому был выбран.
Если источник обычно возвращает хорошую оценку, количество расширений уменьшается. Если он возвращает ноль, корректность не меняется: массив просто растёт обычным способом.
underestimatedCount вернуть ноль для непустой последовательности?Да. Ноль означает отсутствие известной безопасной нижней границы, а не пустоту последовательности. Проверять пустоту нужно отдельным способом, например получить первый элемент через соответствующую операцию поиска; при этом для однопроходного источника следует учитывать состояние итерации.
underestimatedCount элементов?Нет. Свойство задаёт нижнюю, а не верхнюю границу. После обработки такого числа элементов в последовательности могут оставаться другие элементы, поэтому обход должен продолжаться до обычного завершения итератора.
Протокол Sequence не гарантирует повторный обход. Источник может быть однопроходным, зависеть от внешнего состояния или выдавать разные значения при каждом проходе. Поэтому предварительный подсчёт либо потребит источник, либо сделает второй проход некорректным; underestimatedCount позволяет получить безопасную подсказку без требования точного подсчёта.