webentwicklung-frage-antwort-db.com.de

Zusammenführen von zwei Objektlisten in Java 8

Ich habe eine Java-Klasse Parent mit 20 Attributen (attrib1, attrib2 .. attrib20) und die entsprechenden Getter und Setter. Ich habe auch zwei Listen von Parent Objekten: list1 und list2.

Jetzt möchte ich beide Listen zusammenführen und doppelte Objekte basierend auf attrib1 und attrib2 vermeiden.

Verwendung von Java 8:

List<Parent> result = Stream.concat(list1.stream(), list2.stream())
                .distinct()
                .collect(Collectors.toList());   

Aber wo muss ich die Attribute angeben? Soll ich die hashCode- und equals-Methode überschreiben?

25
Manu Joy

Wenn Sie equals und hashCode implementieren möchten, ist inside die Klasse Parent. Fügen Sie innerhalb dieser Klasse die Methoden wie hinzu

    @Override
    public int hashCode() {
        return Objects.hash(getAttrib1(), getAttrib2(), getAttrib3(),
            // …
                            getAttrib19(), getAttrib20());
    }

    @Override
    public boolean equals(Object obj) {
        if(this==obj) return true;
        if(!(obj instanceof Parent)) return false;
        Parent p=(Parent) obj;
        return Objects.equals(getAttrib1(), p.getAttrib1())
            && Objects.equals(getAttrib2(), p.getAttrib2())
            && Objects.equals(getAttrib3(), p.getAttrib3())
            // …
            && Objects.equals(getAttrib19(), p.getAttrib19())
            && Objects.equals(getAttrib20(), p.getAttrib20());
    }

Wenn Sie dies tun, wird distinct(), das für einen Stream<Parent> aufgerufen wird, automatisch das Richtige tun.


Wenn Sie die Klasse Parent nicht ändern wollen oder können, gibt es keinen Delegierungsmechanismus für Gleichheit. Sie können jedoch auf order zurückgreifen, da dies einen Delegierungsmechanismus hat:

Comparator<Parent> c=Comparator.comparing(Parent::getAttrib1)
        .thenComparing(Parent::getAttrib2)
        .thenComparing(Parent::getAttrib3)
        // …
        .thenComparing(Parent::getAttrib19)
        .thenComparing(Parent::getAttrib20);

Dies definiert eine Reihenfolge basierend auf den Eigenschaften. Es erfordert, dass die Typen der Attribute selbst vergleichbar sind. Wenn Sie über eine solche Definition verfügen, können Sie das Äquivalent einer distinct() basierend auf dieser Comparator implementieren:

List<Parent> result = Stream.concat(list1.stream(), list2.stream())
        .filter(new TreeSet<>(c)::add)
        .collect(Collectors.toList());

Es gibt auch eine Thread-sichere Variante, falls Sie diese mit parallelen Streams verwenden möchten:

List<Parent> result = Stream.concat(list1.stream(), list2.stream())
        .filter(new ConcurrentSkipListSet<>(c)::add)
        .collect(Collectors.toList());
21
Holger

Zum Beispiel:

public class Parent {

    public int no;
    public String name;

    @Override
    public int hashCode() {
        return (no << 4) ^ name.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Parent))
            return false;
        Parent o = (Parent)obj;
        return this.no == o.no && this.name.equals(o.name);
    }
}
1
saka1029

Überschreiben Sie die Methoden equals und hashCode in der Klasse Parent, um Doppeleinträge aus den Listen zu vermeiden. Dies gibt Ihnen das genaue Ergebnis, was Sie wollen.

0
Dominic D'Souza

Wenn Sie .equals(…) und .hashCode() überschreiben möchten, müssen Sie dies für die Parent-Klasse tun. Beachten Sie, dass dies dazu führen kann, dass andere Verwendungen von Parent fehlschlagen. Die verbundene Lösung von Alexis C. ist konservativer.

0
llogiq