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?
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());
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);
}
}
Ü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.
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.