Вы можете делать что угодно с потоками и с помощью специального пользовательского конструктора и нескольких вспомогательных методов в GiftCertificate
.Вот конструктор:
public GiftCertificate(GiftCertificate another) {
this.id = another.id;
this.tags = new ArrayList<>(another.tags);
}
Это просто работает как конструктор копирования.Мы создаем новый список тегов, поэтому, если список тегов одного из экземпляров GiftCertificate
будет изменен, другой не будет изменен.(Это просто основные концепции ОО: инкапсуляция).
Затем, чтобы добавить другие теги GiftCertificate
в этот список тегов GiftCertificate
, вы можете добавить следующий метод к GiftCertificate
:
public GiftCertificate addTagsFrom(GiftCertificate another) {
tags.addAll(another.tags);
return this;
}
А также вспомогательный метод, который возвращает, является ли список тегов пустым или нет, очень пригодится:
public boolean hasTags() {
return tags != null && !tags.isEmpty();
}
Наконец, с этими тремя простыми методамина месте, мы готовы использовать все возможности потоков для элегантного решения проблемы:
Collection<GiftCertificate> result = certificates.stream()
.filter(GiftCertificate::hasTags) // keep only gift certificates with tags
.collect(Collectors.toMap(
GiftCertificate::getId, // group by id
GiftCertificate::new, // use our dedicated constructor
GiftCertificate::addTagsFrom)) // merge the tags here
.values();
При этом используется Collectors.toMap
для создания карты, которая группирует подарочные сертификаты по id
,слияние тегов.Затем мы сохраняем значения карты.
Вот эквивалентное решение без потоков:
Map<Long, GiftCertificate> map = new LinkedHashMap<>(); // preserves insertion order
certificates.forEach(cert -> {
if (cert.hasTags()) {
map.merge(
cert.getId(),
new GiftCertificate(cert),
GiftCertificate::addTagsFrom);
}
});
Collection<GiftCertificate> result = map.values();
А вот вариант с небольшим улучшением производительности:
Map<Long, GiftCertificate> map = new LinkedHashMap<>(); // preserves insertion order
certificates.forEach(cert -> {
if (cert.hasTags()) {
map.computeIfAbsent(
cert.getId(),
k -> new GiftCertificate(k)) // or GitCertificate::new
.addTagsFrom(cert);
}
});
Collection<GiftCertificate> result = map.values();
Для этого решения требуется следующий конструктор:
public GiftCertificate(Long id) {
this.id = id;
this.tags = new ArrayList<>();
}
Преимущество этого подхода состоит в том, что новые GiftCertificate
экземпляры будут создаваться только в том случае, если на карте нет другой записи стот же идентификатор.