问:是否有可能创建一个Stream实现,该实现在单个操作中对元素进行计数,而不是对流中的每个元素进行计数?
但是,当我尝试比较列表中的两种方法时,我想到了这一点:
size()
count()
Stream::count
终端操作计算Stream中元素的数量。操作的复杂度通常为 O(N),这意味着子操作的数量与 Stream 中的元素数量成正比。
List::size
方法的复杂度为 O(1),这意味着无论List中元素的数量如何,size()
方法都会在恒定时间内返回
List<Integer> list = IntStream.range(0, 100).boxed().collect(toList());
System.out.println(list.size());
System.out.println(list.stream().count());
size()
花费的时间比count()
短,所以有什么可能的方法来创建Stream实现,该实现在单个操作中对元素进行计数并使其复杂度为 O(1) ??
可以创建
Stream
个实现,将其数量 一次操作 O(1)中的元素,而不是对每个元素进行计数 流中的每个元素。这样可以提高性能 尤其是对于包含许多元素的流而言。
答案 0 :(得分:8)
这已经在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());
看到在可预测的计数时不会发生遍历。