java - por - ¿Está garantizado.collect para ser ordenado en corrientes paralelas?
organizar casas (2)
TL; DR
Sí, el pedido está garantizado.
Stream.collect () documentación de la API
El punto de partida es mirar qué determina si una reducción es concurrente o no. La descripción de Stream.collect()
dice lo siguiente:
Si el flujo es paralelo, y el
Collector
es concurrent , y si el flujo no está ordenado o el recopilador unordered está unordered , se realizará una reducción concurrente (consulte elCollector
para obtener detalles sobre la reducción simultánea).
Se cumple la primera condición: el flujo es paralelo. ¿Qué hay de la segunda y la tercera: es el Collector
concurrente y desordenado?
Collectors.toList () documentación de la API
toList()
lee:
Devuelve un
Collector
que acumula los elementos de entrada en una nuevaList
. No hay garantías sobre el tipo, la mutabilidad, la serialización o la seguridad de subprocesos de laList
devuelta; Si se requiere más control sobre laList
devuelta, usetoCollection(Supplier)
.Devoluciones:
un recopilador que recopila todos los elementos de entrada en una lista, en orden de encuentro
Una operación que funciona en orden de encuentro opera sobre los elementos en su orden original. Esto anula el paralelismo.
Código de implementación
La inspección de la implementación de Collectors.java
confirma que toList()
no incluye los rasgos CONCURRENT
o UNORDERED
.
public static <T>
Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);
}
// ...
static final Set<Collector.Characteristics> CH_ID
= Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
Observe cómo el recopilador tiene el CH_ID
rasgos CH_ID
, que tiene solo el único rasgo IDENTITY_FINISH
. CONCURRENT
y UNORDERED
no están allí, por lo que la reducción no puede ser simultánea.
Una reducción no concurrente significa que, si la secuencia es paralela, la recopilación puede proceder en paralelo, pero se dividirá en varios resultados intermedios confinados en subprocesos que luego se combinan. Esto asegura que el resultado combinado esté en orden de encuentro.
Vea también: ¿Por qué la transmisión paralela se recopila secuencialmente en Java 8?
Dado que tengo una lista de Strings List<String> toProcess
. Los resultados deben estar en el orden en que se dieron las líneas originales. Quiero utilizar las nuevas corrientes paralelas.
¿El siguiente código garantiza que los resultados estarán en el mismo orden en que estaban en la lista original?
// ["a", "b", "c"]
List<String> toProcess;
// should be ["a", "b", "c"]
List<String> results = toProcess.parallelStream()
.map(s -> s)
.collect(Collectors.toList());
Usted está garantizado para obtener los elementos en orden de encuentro.
De la documentación de toList
:
Devoluciones: un recopilador que recopila todos los elementos de entrada en una lista, en orden de encuentro
Consulte el resumen de java.util.streams para obtener más información sobre el término "orden de encuentro".
Además, la documentación del List#spliterator
requiere que todas las implementaciones de List
produzcan divisores que SE ORDENAN:
El Spliterator informa sobre Spliterator.SIZED y Spliterator.ORDERED. Las implementaciones deben documentar el reporte de valores característicos adicionales.
Por extraño que parezca, mientras que la interfaz de la List
requiere que el iterator()
produzca elementos en la "secuencia adecuada", solo se debe ordenar el spliterator()
pero no se requiere específicamente que siga el orden natural de la lista.
Entonces, para responder a su pregunta, se garantiza que la lista producida por toList
contendrá los elementos exactamente como los ordena el separador de la lista de origen . No importa si el flujo es paralelo o secuencial.