Verwandeln Sie eine flache Liste Domänenobjekte mit untergeordneten Objekte mit Java-Streams

Adam :

Ich habe eingehende Objekte mit einer flachen de-normalisierte Struktur, die ich von einem JDBC-Ergebnis instanziiert. Die eingehenden Objekte spiegeln die resultset gibt Lasten von wiederholten Daten ist, damit ich die Daten in eine Liste der übergeordneten Objekte mit verschachtelten Kind Sammlungen, dh ein Objektgraph oder normalisierte Liste konvertieren möchten.

Die eingehenden Objektklasse sieht wie folgt aus:

class IncomingFlatItem {
    String clientCode;
    String clientName;
    String emailAddress;
    boolean emailHtml;
    String reportCode;
    String reportLanguage;
}

So ist die eingehenden Daten enthält, die für jeden Kunden mehrere Objekte, die Ich mag würde zu einem Client-Objekt aggregieren, die eine Liste von E-Mail-Adresse Objekte für den Client enthält, und eine Liste der Berichtsobjekte.

So ist das Client-Objekt würde wie folgt aussehen:

class Client {
    String clientCode;
    String clientName;
    Set<EmailAddress> emailAddresses;
    Set<Report> reports;
}

Merkwürdiger Ich kann nicht eine vorhandene Antwort auf diese finden. Ich bin auf der Suche Ströme nisten oder Bäche Verkettungs aber ich möchte das eleganteste Ansatz finden, und ich möchte auf jeden Fall eine for-Schleife zu vermeiden.

Adam :

Vielen Dank an alle Antworter , die erwähnt Collectors.groupingBy(). Dies war der Schlüssel , um einen Strom der Einrichtung , wo ich verwenden könnte reduce(). Ich hatte geglaubt , fälschlicherweise soll ich in der Lage sein zu verwenden , reduceauf seinem eigenen , das Problem zu lösen, ohne groupingBy.

Unser Dank gilt auch den Vorschlag , eine fließend API zu erstellen. Ich fügte hinzu , IncomingFlatItem.getEmailAddress()und IncomingFlatItem.getReport()zu fließend die Domänenobjekte aus greifen IncomingFlatItem- und auch eine Methode , um das ganze Wohnung Element an ein richtiges Domain - Objekt mit seiner E - Mail und Bericht bereits verschachtelt zu konvertieren:

public Client getClient() {
    Client client = new Client();
    client.setClientCode(clientCode);
    client.setClientName(clientName);
    client.setEmailAddresses(new ArrayList());
    client.getEmailAddresses().add(this.getEmailAddress());
    client.setReports(new ArrayList<>());
    client.getReports().add(this.getReport());
    return client;
}

Ich habe auch Business - ID-basierte .equals()und .hashCode()Methoden auf Client, EmailAddressund Reportwie empfohlen von @SamuelPhilip

Schließlich für die Domain - Objekte, habe ich .addReport(Report r)und .addEmail(EmailAddress e)meine ClientKlasse, die das untergeordnete Objekt hinzufügen würde , Clientwenn nicht bereits vorhanden ist . Ich ditched den SetKollektionstyp für , Listweil der Domain - Modell Standard ist Listund Setswürde viele Conversions hat gemeint Lists.

Also mit diesem, schauen der Stream-Code und Lambda-Ausdrücke prägnant.

Es gibt drei Stufen:

  1. Karte IncomingFlatItemszuClients
  2. die Gruppe Clientsin eine Karte durch den Kunden (die jedoch stark von Client.equals())
  3. reduzieren, jede Gruppe zu einem Client

Das ist also der Funktionsalgorithmus:

List<Client> unflatten(List<IncomingFlatItem> flatItems) {
    return flatItems.parallelStream()
            .map(IncomingFlatItem::getClient)
            .collect(Collectors.groupingByConcurrent(client -> client))
            .entrySet().parallelStream()
            .map(kvp -> kvp.getValue()
                    .stream()
                    .reduce(new Client(), 
                            (client1, client2) -> {
                                    client1.getReports()
                                            .forEach(client2::addReport);
                                    client1.getEmailAddresses()
                                            .forEach(client2::addEmail);
                                    return client2;
                    }))
            .collect(Collectors.toList());
}

Ich habe eine lange Zeit wegen auf einer Tangente gehen, bevor ich wirklich verstanden reduce- ich eine Lösung gefunden , die meine Tests bestanden während der Verwendung , .stream()aber völlig gescheiterten .parallelStream()daher seine Verwendung hier. Ich hatte zu verwenden , CopyOnWriteArrayListwie auch sonst ist es zufällig umfallen würde mitConcurrentModificationExceptions

Ich denke du magst

Origin http://43.154.161.224:23101/article/api/json?id=226551&siteId=1
Empfohlen
Rangfolge