How to sum up the individual fields of the object list and return the results as a single object

You can use Stream.reduce method for that, just need to create a NutrientsAggregator that will know to add the values from FoodNutritional to itself and sum everything

public class NutrientsAggregator {
   private double calories;
   private double totalFat;
   private double saturatedFat;
   private double cholesterol;

   public NutrientsAggregator addFoodNutritionalValues(FoodNutritional foodNutrional) {
      this.calories += foodNutrional.getCalories();
      this.totalFat+= foodNutrional.getTotalFat();
      this.saturatedFat+= foodNutrional.getSaturatedFat();
      this.cholesterol+= foodNutrional.getCholesterol();

      return this;
   }
}

and than:

NutrientsAggregator result = response.getBody()
          .stream()
          .reduce(new NutrientsAggregator(), 
                  (aggregator, food) -> aggregator.addFoodNutritionalValues(food);

Let introduce class 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
        );
    }
}

And now we can write simple stream reduce:

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

                );

And finally you can pass result from above to builder.


How about using a Supplier<Stream<T>>> to create a reusable Stream something like :

Supplier<Stream<FoodNutritional>> foodNutritionalSupplier = () -> Optional.ofNullable(responseBody)
        .stream()
        .flatMap(List::stream);
return Nutrients.builder()
        .carbohydrates(foodNutritionalSupplier.get().mapToDouble(FoodNutritional::getTotalCarbohydrate).sum())
        .protein(foodNutritionalSupplier.get().mapToDouble(FoodNutritional::getProtein).sum())
        .fat(foodNutritionalSupplier.get().mapToDouble(FoodNutritional::getTotalFat).sum())
        .dietaryFiber(foodNutritionalSupplier.get().mapToDouble(FoodNutritional::getDietaryFiber).sum())
        .build();

where responseBody corresponds to the response.getBody() in the question.


Or further to using a utility to abstract out the core logic, such as :

private Nutrients nutrientsCalculator(List<FoodNutritional> responseBody) {
    Supplier<Stream<FoodNutritional>> foodNutritionalSupplier =
            () -> Optional.ofNullable(responseBody).stream().flatMap(List::stream);
    // should ideally be as simple as 'responseBody::stream'
    return Nutrients.builder()
            .carbohydrates(sumNutrition(foodNutritionalSupplier, FoodNutritional::getTotalCarbohydrate))
            .protein(sumNutrition(foodNutritionalSupplier, FoodNutritional::getProtein))
            .fat(sumNutrition(foodNutritionalSupplier, FoodNutritional::getTotalFat))
            .dietaryFiber(sumNutrition(foodNutritionalSupplier, FoodNutritional::getDietaryFiber))
            .build();
}

private Double sumNutrition(Supplier<Stream<FoodNutritional>> foodNutritionalSupplier,
                            ToDoubleFunction<FoodNutritional> nutritionTypeFunction) {
    return foodNutritionalSupplier.get().mapToDouble(nutritionTypeFunction).sum();
}