Q: ¿Es posible crear la aplicación corriente que cuenta sus elementos en una sola operación en lugar de contar todos y cada elemento en la corriente?
Vine a esto, sin embargo, cuando me trató de comparar los dos métodos en una lista:
size()
count()
Stream::count
el funcionamiento del terminal cuenta el número de elementos en una corriente. La complejidad de la operación es a menudo O (N) , lo que significa que el número de sub-operaciones es proporcional al número de elementos de la corriente .
List::size
método tiene una complejidad de O (1) , lo que significa que, independientemente del número de elementos en la lista, el size()
método devolverá en tiempo constante.
List<Integer> list = IntStream.range(0, 100).boxed().collect(toList());
System.out.println(list.size());
System.out.println(list.stream().count());
size()
tomó un tiempo inferior relativa que count()
, por lo que ¿hay alguna manera posible crear la aplicación corriente que cuenta sus elementos en una sola operación y hacer una complejidad de O (1) ??
Editar artículo para responder Sí :
Es posible crear
Stream
la aplicación que cuenta sus elementos en una única operación de O (1) en lugar de contar todos y cada elemento en la corriente. Esto puede mejorar significativamente el rendimiento, especialmente para los flujos con muchos elementos.
Esto ya está ocurriendo en Java 9 y posteriores (teniendo en cuenta la implementación OpenJDK, que es también la base para el JDK de Oracle).
Si quieres una operación similar, se puede utilizar, por ejemplo,
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;
}
Puede comprobar que no va a procesar todos los elementos con
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)));
mientras que la inserción de una filter
operación como
System.out.println(count(Stream.of("a", "b", "c")
.peek(System.out::println).filter(x -> true)));
hará que el recuento imprevisibles y que requieren un recorrido.
Como se dijo anteriormente, en JDK 9 o, puede utilizar simples
System.out.println(Stream.of("a", "b", "c").peek(System.out::println).count());
y
System.out.println(Stream.of("a", "b", "c")
.peek(System.out::println).filter(x -> true).count());
ver que el recorrido no sucede cuando el recuento es predecible.