Java - соответствие критериям для 3 коллекций для обновления 1 из них - PullRequest
0 голосов
/ 07 января 2020

Рассмотрим классы Site, Tag и SiteTagRelation. У меня есть коллекция каждого из них. Для каждого сайта мне нужно найти все соответствующие теги, просмотрев его в классе отношений, а затем добавить соответствующие теги в объект сайта.

Это можно сделать с помощью петель, но это не элегантно и не эффективно. Я хотел бы найти однострочное решение с потоками, но мне не удается обдумать, как совместить 3 коллекции в одном выражении. Любой намек на то, как этого добиться, будет приветствоваться.

public class Tag {
   private int id;
...
}

public class Site {
   private int id;
   Collection<Tag> tags;
...
}

public class SiteTagRelation {
   private int siteId;
   private int tagId;
...
}

public static void main(String[] arg) {
   Collection<SiteTagRelation> tagMapping = ...
   Collection<Site> sites = ...
   Collection<Tag> tags = ...

   // The expression I am struggling with should be here
   // From that point, all sites with a tag in sites should have a non-empty tags collection within itself
}

Мое решение с петлями

private void enrichSite(Collection<Site> sites) {

        for(Site site : sites) {

            // Get all the matching relation
            Set<SiteTagRelation> matchingTagRelation = tagMapping.stream().filter(x -> x.getSiteId().equals(site.getId())).collect(Collectors.toSet());

            Set<Tag> matchingTags = new HashSet<Tag>();

            // Add each tag found to the collection
            for(SiteTagRelation mapping : matchingTagRelation) {
                Tag foundTag = this.tags().stream().filter(x -> x.getId().equals(mapping.getTagId())).findFirst().get();
                matchingTags.add(foundTag);
            }

            // Set the tags on the entity
            site.setTags(matchingTags);

        }
    }

1 Ответ

0 голосов
/ 08 января 2020

Решение Stream было бы следующим, оно является многословным, но оно делает то же самое, что и циклы, которые здесь следует предпочитать для ясности

private void enrichSite(Collection<Site> sites) {
    sites.forEach(site ->
        site.setTags(tagMapping.stream().filter(x -> x.getSiteId().equals(site.getId()))
            .map(mapping -> this.tags.stream().filter(x -> x.getId().equals(mapping.getTagId())).findFirst().get())
            .collect(Collectors.toSet())));
}
  • , которые вы не можете использовать equals на int, поэтому я предполагаю, что ваши геттеры вернули Integer
  • , использовать .get() небезопасно, поскольку вы уверены, что значение возвращается внутренним потоком

Обрабатывать опасно get(): вы могли бы подделать Tag в случае, если внутренний поток ничего не возвращает, а затем отфильтровать его

class Tag {
    private int id;
    // ...
    static Tag useless() {
        return new Tag(-1);
    }
}


private void enrichSite(Collection<Site> sites) {
    sites.forEach(site ->
        site.setTags(tagMapping.stream().filter(x -> x.getSiteId().equals(site.getId()))
            .map(mapping -> this.tags.stream().filter(x -> x.getId().equals(mapping.getTagId())).findFirst().orElseGet(Tag::useless))
            .filter(tag -> tag.getId() != -1)
            .collect(Collectors.toSet())));
}
...