Cómo resumir los campos individuales de la lista de objetos y devolver los resultados como un objeto único

Martin:

Tengo un método que se está calculando nutrientes para una lista de objeto que estamos recibiendo de solicitud de API llamada.

El aspecto del método les gusta:

public Nutrients nutrientsCalculator(DailyMeals dailyMeals) {

    String foodNamesForRequest = prepareFoodNamesForRequest(dailyMeals);

    HttpEntity<NutrientsBodyForRequest> requestBody = prepareRequestForAPICall(foodNamesForRequest);

    ResponseEntity<List<FoodNutritional>> response =
        //create request here

    if (nonNull(response.getBody())) {

      double totalFat = response.getBody()
          .stream()
          .map(FoodNutritional::getTotalFat)
          .mapToDouble(Double::doubleValue)
          .sum();

      double totalProtein = response.getBody()
          .stream()
          .map(FoodNutritional::getProtein)
          .mapToDouble(Double::doubleValue)
          .sum();

      double totalCarbohydrates = response.getBody()
          .stream()
          .map(FoodNutritional::getTotalCarbohydrate)
          .mapToDouble(Double::doubleValue)
          .sum();

      double totalDietaryFiber = response.getBody()
          .stream()
          .map(FoodNutritional::getDietaryFiber)
          .mapToDouble(Double::doubleValue)
          .sum();

      return Nutrients.builder()
          .carbohydrates(totalCarbohydrates)
          .protein(totalProtein)
          .fat(totalFat)
          .dietaryFiber(totalDietaryFiber)
          .build();
    }
    return new Nutrients();
  }

Mi apariencia FoodNutritional.class como:

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
class FoodNutritional {

  @JsonProperty("food_name")
  private String foodName;

  @JsonProperty("brand_name")
  private String brandName;

  @JsonProperty("serving_qty")
  private Integer servingQuantity;

  @JsonProperty("serving_unit")
  private String servingUnit;

  @JsonProperty("serving_weight_grams")
  private String servingWeightGrams;

  @JsonProperty("nf_calories")
  private Double calories;

  @JsonProperty("nf_total_fat")
  private Double totalFat;

  @JsonProperty("nf_saturated_fat")
  private Double saturatedFat;

  @JsonProperty("nf_cholesterol")
  private Double cholesterol;

  @JsonProperty("nf_sodium")
  private Double sodium;

  @JsonProperty("nf_total_carbohydrate")
  private Double totalCarbohydrate;

  @JsonProperty("nf_dietary_fiber")
  private Double dietaryFiber;

  @JsonProperty("nf_sugars")
  private Double sugars;

  @JsonProperty("nf_protein")
  private Double protein;

  @JsonProperty("nf_potassium")
  private Double potassium;
}

Mi solución en el método funciona, pero empecé a pensar si es posible deshacerse de este sumflujo de método repetitivo de este enfoque.

Todo lo que queremos lograr es sumando los campos individuales: totalFat, protein, dietaryFiber, totalCarbohydratey devolverlos como un componentes de campos de un nuevo objeto.

Yo estaré agradecido por las sugerencias sobre cómo mejorar la calidad de la versión actual del código.

Editar:

El fin de semana que pasé un momento para fundar un enfoque diferente, adicional que cumpla con los requisitos y es un poco más funcional. Por último, he creado dos métodos estáticos como:


private static Nutrients reduceNutrients(Nutrients n1, Nutrients n2) {
    return Nutrients.builder()
        .protein(n1.getProtein() + n2.getProtein())
        .carbohydrates(n1.getCarbohydrates() + n2.getCarbohydrates())
        .dietaryFiber(n1.getDietaryFiber() + n2.getDietaryFiber())
        .fat(n1.getFat() + n2.getFat())
        .build();
  }

  private static Nutrients fromFoodNutritionalToNutrients(FoodNutritional foodNutritional) {
    return Nutrients.builder()
        .dietaryFiber(foodNutritional.getDietaryFiber())
        .carbohydrates(foodNutritional.getTotalCarbohydrate())
        .fat(foodNutritional.getTotalFat())
        .protein(foodNutritional.getProtein())
        .build();
  }

y después de todo lo utilicé como:

Stream<FoodNutritional> foodNutritionalStream = Optional.ofNullable(response.getBody()).stream()
        .flatMap(List::stream);

Nutrients nutrients = foodNutritionalStream
        .map(NutrientsCalculatorService::fromFoodNutritionalToNutrients)
        .reduce(NutrientsCalculatorService::reduceNutrients)
        .orElseThrow(() -> new CustomException("custom_exception");

No obstante, saludos para @Koziołek, @Nir Levyy @Namanpor ser mi musa. Gracias por cada compromiso.

cabra:

Vamos a introducir la clase NutritionAccumulator:

class NutritionAccumulator{
    private double fat = 0.;
    private double carbs = 0.;
    private double fiber = 0.;
    private double protein = 0.;

    public NutritionAccumulator() {
    }

    public NutritionAccumulator(double fat, double carbs, double fiber, double protein) {
        this.fat = fat;
        this.carbs = carbs;
        this.fiber = fiber;
        this.protein = protein;
    }

    public NutritionAccumulator add(NutritionAccumulator that){
        return new NutritionAccumulator(this.fat + that.fat,
        this.carbs + that.carbs,
        this.fiber + that.fiber,
        this.protein + that.protein
        );
    }
}

Y ahora podemos escribir simple arroyo reducir:

Optional.ofNullable(response.body())
.stream()
.reduce(
                        new NutritionAccumulator(),
                        (acc, fudNut) -> new NutritionAccumulator(
                                fudNut.getTotalFat(),
                                fudNut.getTotalCarbohydrate(),
                                fudNut.getDietaryFiber(),
                                fudNut.getProtein()
                        ).add(acc),
                        NutritionAccumulator::add

                );

Y, finalmente, se puede pasar a consecuencia de lo alto constructor.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=311844&siteId=1
Recomendado
Clasificación