Vis*_*tna 6 java java-8 java-stream
问:是否可以创建在单个操作中对元素进行计数而不是对流中的每个元素进行计数的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());
Run Code Online (Sandbox Code Playgroud)
size()
相对而言count()
,它花费的时间更少,因此,有没有一种可能的方法来创建Stream实现,该实现在单个操作中对它们的元素进行计数并使其复杂度为O(1)?
编辑 文章以回答是:
可以创建
Stream
在单个操作O(1)中对元素进行计数的实现,而不是对流中的每个元素进行计数。这可以显着提高性能,尤其是对于具有许多元素的流。
这已经在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;
}
Run Code Online (Sandbox Code Playgroud)
您可以检查它不会处理所有元素
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)));
Run Code Online (Sandbox Code Playgroud)
而插入filter
像
System.out.println(count(Stream.of("a", "b", "c")
.peek(System.out::println).filter(x -> true)));
Run Code Online (Sandbox Code Playgroud)
会使计数不可预测,并且需要遍历。
如上所述,在JDK 9或更高版本中,您可以轻松使用
System.out.println(Stream.of("a", "b", "c").peek(System.out::println).count());
Run Code Online (Sandbox Code Playgroud)
和
System.out.println(Stream.of("a", "b", "c")
.peek(System.out::println).filter(x -> true).count());
Run Code Online (Sandbox Code Playgroud)
当计数是可预测的时,就不会发生遍历。