Es difícil de palabra a la pregunta. Aquí está mi fragmento de código:
Map<PassType, PassTypeRate> ratesPerType = new HashMap<>();
entries.stream().forEach((entry) -> {
if (!ratesPerType.containsKey(entry.getPassType())) {
ratesPerType.put(entry.getPassType(), new PassTypeRate(BigDecimal.ZERO, BigDecimal.ZERO));
}
if (AgeType.ADULT.equals(entry.getAgeType())) {
PassTypeRate passTypeRate = ratesPerType.get(entry.getPassType());
passTypeRate.setAdultRate(passTypeRate.getAdultRate().add(entry.getRate()));
}
if (AgeType.CHILD.equals(entry.getAgeType())) {
PassTypeRate passTypeRate = ratesPerType.get(entry.getPassType());
passTypeRate.setChildRate(passTypeRate.getChildRate().add(entry.getRate()));
}
});
Así que entries
es una lista de los granos que tiene una ageType, passType y tasa. Tengo que agregar las tasas totales por 'ageType' y 'passType'.
El grano de PassTypeRate posee un total agregado de tasa para adultos y niños por 'PassType'.
Mi pregunta básica es .... ¿es posible en absoluto volver a escribir el código anterior utilizando Java 8 El receptor o similar? No puedo resolverlo.
Cualquier consejo sería apreciado.
Gracias
Sí, se ve como un buen candidato para implementar con Collectors.toMap
. Echar un vistazo a continuación la aplicación (I Lombok usada ( https://projectlombok.org/ ) para que sea más legible):
Map<PassType, PassTypeRate> group(List<DataEntry> entries) {
return entries.stream()
.collect(Collectors.toMap(
DataEntry::getPassType,
entry -> PassTypeRate.builder()
.adultRate(entry.getAgeType() == ADULT ? entry.getRate() : BigDecimal.ZERO)
.childRate(entry.getAgeType() == CHILD ? entry.getRate() : BigDecimal.ZERO)
.build(),
(rate1, rate2) -> PassTypeRate.builder()
.childRate(rate1.getChildRate().add(rate2.getChildRate()))
.adultRate(rate1.getAdultRate().add(rate2.getAdultRate()))
.build()
));
}
Y breve explicación:
En primer lugar, tenemos que definir
PassType
como una clave del mapaEn segundo lugar, tenemos que trazar nuestro
DataEntry
a solasPassTypeRate
objetos. Si esta esAdult
la entrada, a continuación, la nuevaPassTypeRate
tiene que tener un valor enadultRate
el campo y cero enchildRate
. Y viceversa.Sin embargo, algunas entradas pueden tener el mismo
PassType
! Por lo tanto, tenemos que definir tercera función - la función de fusión. ¿Cómo nos fusionamosPassTypeRate
objetos? Mediante la adición de las tasas correspondientes. Función Merge devuelve nuevoPassTypeRate
como resultado de la adición de dosPassTypeRate
objetos.
También he preparado una serie de casos de prueba para verificar si funciona la solución - y parece que funciona :) caso de prueba a continuación:
public class RateGroupingTest {
private RateGrouping subject = new RateGrouping();
@Test
public void groups() {
//given
List<DataEntry> entries = List.of(
new DataEntry(ADULT, X, new BigDecimal("3")),
new DataEntry(ADULT, Y, new BigDecimal("5")),
new DataEntry(ADULT, Z, new BigDecimal("7")),
new DataEntry(CHILD, X, new BigDecimal("11")),
new DataEntry(CHILD, Y, new BigDecimal("13")),
new DataEntry(CHILD, Z, new BigDecimal("17")),
new DataEntry(ADULT, X, new BigDecimal("13")),
new DataEntry(ADULT, Y, new BigDecimal("25")),
new DataEntry(ADULT, Z, new BigDecimal("37")),
new DataEntry(CHILD, X, new BigDecimal("411")),
new DataEntry(CHILD, Y, new BigDecimal("513")),
new DataEntry(CHILD, Z, new BigDecimal("617"))
);
//when
Map<PassType, PassTypeRate> actual = subject.group(entries);
//then
assertThat(actual.get(PassType.X))
.isEqualTo(
PassTypeRate.builder()
.childRate(new BigDecimal("422"))
.adultRate(new BigDecimal("16"))
.build()
);
assertThat(actual.get(PassType.Y))
.isEqualTo(
PassTypeRate.builder()
.childRate(new BigDecimal("526"))
.adultRate(new BigDecimal("30"))
.build()
);
assertThat(actual.get(PassType.Z))
.isEqualTo(
PassTypeRate.builder()
.childRate(new BigDecimal("634"))
.adultRate(new BigDecimal("44"))
.build()
);
}
}