Это уже происходит в Java 9 и новее (учитывая реализацию OpenJDK, которая также является основой для Oracle JDK).
Если вы хотите подобную операцию, вы можете использовать, например,
public static long count(BaseStream<?,?> s) {
Spliterator<?> sp = s.spliterator();
long c = sp.getExactSizeIfKnown();
if(c >= 0) return c;
final class Counter implements Consumer<Object>,
IntConsumer, LongConsumer, DoubleConsumer { // avoid boxing where possible
long count;
public void accept(Object t) { count++; }
public void accept(int value) { count++; }
public void accept(long value) { count++; }
public void accept(double value) { count++; }
}
Counter c = new Counter();
sp.forEachRemaining(c);
return c.count;
}
Вы можете проверить, что он не будет обрабатывать все элементы с помощью
System.out.println(count(IntStream.range(0, 100).peek(System.out::println)));
System.out.println(count(Stream.of("a", "b", "c").peek(System.out::println)));
при вставке операции filter
, например
System.out.println(count(Stream.of("a", "b", "c")
.peek(System.out::println).filter(x -> true)));
сделает подсчет непредсказуемым и потребует обхода.
Как сказано выше, в JDK 9 или новее вы можете просто использовать
System.out.println(Stream.of("a", "b", "c").peek(System.out::println).count());
и
System.out.println(Stream.of("a", "b", "c")
.peek(System.out::println).filter(x -> true).count());
чтобы увидеть, что обход не происходит, когда счет предсказуем.