Java Stream: как сопоставить несколько значений с одним DTO?

У меня есть результат List в моем сервисном методе Spring Boot, как показано ниже:

Country:
String name;
List<State> states;
State:
String name;
Long population;
List<Town> towns;
Town:
String name;

Я возвращаю список стран из своего репозитория, и в нем есть все соответствующие даты штата и города для каждой страны. Я хочу сопоставить эти данные с DTO, как показано ниже:

public class CountryDTO {

    private Long id;

    private String name;

    private Long population; //population sum of states by country

    private List<Town> towns;

    //constructor
}

Итак, как мне правильно сопоставить объект Country с этим CountryDTO, как описано выше? Мне нужны следующие данные:

Имя страны Сумма населения по каждой стране Города каждой страны

Обновление: вот мой метод обслуживания, в котором я пытался использовать Java Stream, а затем и ModelMapper, но не могу вернуть желаемые значения :(

List<CountryDTO> countries = countryRepository.findAll().stream()
                .flatMap(x -> x.getStates().stream())
                .map(x -> new CountryDTO(x.getCountry(), <-- need to return sum of population here -->, ObjectMapperUtils.mapAll(x.getTowns(), TownDTO.class)))
                .toList();
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
  • Вы можете использовать Stream#mapToInt, чтобы получить все населения штата, и .sum, чтобы сложить их.
  • Stream#flatMap можно использовать, чтобы собрать все города каждого штата в один поток.
List<CountryDTO> res = countries.stream().map(c -> new CountryDTO(c.getName(), 
      c.getStates().stream().mapToInt(State::getPopulation).sum(), 
      c.getStates().stream().flatMap(s -> s.getTowns().stream()).toList())).toList();

Большое спасибо за этот полезный ответ. Я пробую этот подход, но мне просто нужно суммировать population как BigDecimal вместо Integer, и я не могу использовать BigDecimal::add. Есть идеи для этой строки c.getStates().stream().mapToInt(State::getPopulation).sum() с BigDecimal?

rosy 19.02.2023 20:58

Сейчас попробую c.getStates().stream().map(State::getPopulation).reduce(BigD‌​ecimal.ZERO, BigDecimal::add),

rosy 19.02.2023 21:02

@rosy c.getStates().stream().map(s -> new BigDecimal(s.getPopulation())).reduce(BigDecimal.ZERO, BigDecimal::add) должна это сделать. (Вам нужно сначала преобразовать каждый Long в BigDecimal.)

Unmitigated 19.02.2023 21:03

Не совсем понял ваш вопрос, возможно, будет полезнее, если вы поделитесь точным ответом, возвращаемым API.

Но, исходя из варианта использования, если вы получаете список в ответе, у вас всегда есть возможность передать список, выполнить итерацию каждого элемента, а затем использовать логику условной/группировки для получения данных желаемым способом.

Например; Допустим, у вас есть список типа Object, для которого у вас есть слой репозитория, настроенный как ObjetRepo. Теперь, если вы получаете список объектов, вы можете передать его следующим образом:

@Autowired
private ObjectRepo objectRepo;

public List<Object> method() {
    
    
    List<Object> objects = new ArrayList<>();
    objectRepo.findAll().forEach(objects::add);
    // Here, instead of add, any other logic can be used.
    // You can also write a method, and use that method here
    // objectRepo.findAll().forEach(objects::someMethod);
    return objects; 
}

Другие вопросы по теме