Tengo una colección de objetos de la clase A
class A {
String code;
long timestamp;
long largestTimestamp;
}
Tengo que llenar el campo largestTimestamp para cada objeto (el valor más grande "marca de tiempo" en el grupo de objetos con el mismo código). Puedo hacer esto en dos etapas de la siguiente manera -
Map<String, Long> largestTimestampMap = list.stream().collect(Collectors.toMap(A::getCode, A::getTimestamp, Long::max));
list.forEach(a -> a.setLargestTimestamp(largestTimestampMap.get(a.getCode())));
¿Hay una manera de combinar estos en una sola cadena de corriente?
Sí, puede combinarlos en una sola tubería de la siguiente manera:
list.stream()
.map(a -> new A(a.getCode(), a.getTimestamp(),
list.stream()
.filter(b -> a.getCode().equals(b.getCode()))
.mapToLong(A::getTimestamp)
.max().getAsLong()))
.collect(Collectors.toList());
o si se quiere evitar la creación de una nueva lista, sino que modificar la existente como en su ejemplo a continuación, utilizar replaceAll
:
list.replaceAll(a -> new A(a.getCode(), a.getTimestamp(),
list.stream()
.filter(b -> a.getCode().equals(b.getCode()))
.mapToLong(A::getTimestamp)
.max().getAsLong()));
Sin embargo, recomiendo evitar este enfoque:
1) porque tiene un peor rendimiento que su implementación actual, esta solución requiere una iteración list
nuevo forEach
elemento en ella. Mientras que el enfoque Mapa has mostrado sólo requiere una sola get
llamada y todos sabemos lo rápido que mira en un mapa es.
2) Hay más de código.
Sí, se puede refactorizar el código dentro de la map
operación intermedia en un método para que se vea más corto, pero en última instancia es todavía más largo.
A veces, el mejor enfoque requiere dos o más líneas separadas y en este caso, lo mejor es continuar con su enfoque.