Beispielsweise ist es möglich, Unterschiede in CSV-Dateien einfach zu vergleichen. Gleiches gilt für den Differenzvergleich von Tabellendaten.
Java 11
Ein Beispiel für die Set-Operation ist unten dargestellt.
Darüber hinaus können auch Differenzsätze erhalten werden.
In Java gibt es zwei Arten der Objektäquivalenz:
In Java kann die Identität überprüft werden, indem Objekte mit Referenzadressen mit == verglichen werden.
Reference.java
Object object = new Object();
Object object2 = new Object();
object == object; // true
object == object2; // false
Entspricht der Object-Klasse, die alle Objekte erben Die Äquivalenz kann durch Überschreiben bestimmt werden.
Equals.java
Object object = new Object();
Object object2 = new Object();
object.equals(object); // true
object.equals(object2); // false
Und eine Methode namens hashCode ist tief in diese Gleichheit involviert.
Schauen wir uns zunächst das JavaDoc an.
equals JavaDoc entspricht (von Java8 Oracle HP)
Gibt an, ob dieses Objekt anderen Objekten entspricht. Die Methode equals implementiert die Äquivalenz mit Objektreferenzen ungleich Null
Konkretes Beispiel.java
object.equals(null); // false
- Reflexiv: Für Nicht-Null-Referenzwerte x gibt x.equals (x) true zurück.
Schauen wir uns jeden an.
- Reflexiv: Für Nicht-Null-Referenzwerte x gibt x.equals (x) true zurück.
Entspricht dem im Abschnitt zur Objektäquivalenz dargestellten.
Equals.java
object.equals(object); // true
- Symmetrisch: Für Nicht-Null-Referenzwerte x und y gibt x.equals (y) nur dann true zurück, wenn y.equals (x) true zurückgibt.
Konkretes Beispiel.java
Object object = new Object();
Object object2 = object;
object.equals(object2); // true
object2.equals(object); // true
- Für Nicht-Null-Referenzwerte x, y und z gibt x.equals (z) true zurück, wenn x.equals (y) true und y.equals (z) true zurückgibt. Wenn A = B und B = C, dann ist A = C.
Konkretes Beispiel.java
Object A = new Object();
Object B = A;
Object C = A;
object.equals(object2); // true
object2.equals(object3); // true
//Object2 ohne Vergleich.equals(object3)Scheint wahr zurückzugeben.
- Konsistent: Mehrere Aufrufe von x.equals (y) für Nicht-Null-Referenzwerte x und y Wenn sich die im Gleichheitsvergleich für dieses Objekt verwendeten Informationen nicht geändert haben, wird entweder konsistent true oder konsistent false zurückgegeben.
Unabhängig davon, wie oft gleich ausgeführt wird, wird das gleiche Ergebnis zurückgegeben, wenn die Objekte gleich sind.
Konkretes Beispiel.java
object.equals(object); // true
object.equals(object); // true
Die Methode equals der Object-Klasse implementiert die Äquivalenzbeziehungen der vergleichbarsten Objekte. Das heißt, für Nicht-Null-Referenzwerte x und y gibt diese Methode nur dann true zurück, wenn x und y auf dasselbe Objekt verweisen (x == y ist true).
Mit anderen Worten, die Gleichheit der Objektklasse selbst im vorherigen Beispiel
Konkretes Beispiel.java
object.equals(object2);
Ist
Konkretes Beispiel.java
object == object2;
Sofern die Klasse nicht gleich überschreibt, wird nur die oben genannte Identität überprüft.
Beispielsweise gibt equals in der Klasse java.lang.String zuerst true zurück, wenn die Identität bestätigt wird, andernfalls wird die Äquivalenz überprüft. Befolgen Sie beim Überschreiben grundsätzlich den Ablauf der Identitätsprüfung → Äquivalenzprüfung.
String#equals.java
public boolean equals(Object anObject) {
if (this == anObject) { //Überprüfung der Identität
return true;
}
//Überprüfung der Äquivalenz
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
Wenn Sie diese Methode überschreiben, sollten Sie normalerweise immer die hashCode-Methode überschreiben und die allgemeine Konvention der hashCode-Methode befolgen. ** "Äquivalente Objekte müssen den äquivalenten Hash-Code enthalten" **. Bitte beachten Sie, dass es ** gibt.
Was ist übrigens die allgemeine Regel [^ 1] von hasCode? Sollten wir nicht gleich die Methode equals überschreiben?
hashCode JavaDoc hashCode (von Java8 Oracle HP)
Gibt den Hash-Code-Wert des Objekts zurück. Diese Methode wird für die Vorteile von Hash-Tabellen unterstützt, z. B. der von HashMap bereitgestellten Hash-Tabellen.
Hash ist [Wikipedia: Hash-Funktion](https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96 % A2% E6% 95% B0) ist detailliert.
Es drückt den Datenidentifikationsschlüssel aus. Lesen Sie weiter den Javadoc.
Die allgemeinen Regeln für hashCode sind:
- Immer wenn eine Java-Anwendung ausgeführt wird und mehrmals für dasselbe Objekt aufgerufen wird, gibt die hashCode-Methode immer dieselbe Ganzzahl zurück, es sei denn, die im Vergleich ** für dieses Objekt verwendeten Informationen haben sich geändert. wird gebraucht**. Diese Ganzzahl muss jedoch nicht für jeden Lauf derselben Anwendung gleich sein.
Entspricht es der Konsistenz von Gleichen in der vorherigen Stufe?
- Wenn zwei Objekte gemäß der * equals (Object) -Methode ** gleich sind, muss ein Aufruf der ** hashCode-Methode für jedes der beiden Objekte das gleiche ganzzahlige Ergebnis ** erzeugen.
- Wenn zwei Objekte gemäß der Methode equals (java.lang.Object) nicht gleich sind, dann zwei Das Aufrufen der hashCode-Methode für jedes Objekt muss nicht zu unterschiedlichen ganzzahligen Ergebnissen führen. Programmierer werden jedoch feststellen, dass das Generieren unterschiedlicher ganzzahliger Ergebnisse für ungleiche Objekte die Leistung von Hash-Tabellen verbessern kann. ** "Äquivalente Objekte müssen äquivalenten Hashcode enthalten" **
Die Eigenschaften der Rückgabewerte von equals und hashCode für die Äquivalenz und Nichtäquivalenz der beiden Objekte sind nachstehend zusammengefasst.
Methode | Äquivalentes Objekt | Nicht äquivalente Objekte |
---|---|---|
hashCode | Muss gleichwertig sein | Nicht gleichwertig empfohlen. * Es muss nicht gleichwertig sein, wird jedoch für die Leistung empfohlen. |
equals | Sollte true zurückgeben | Sollte false zurückgeben |
Inzwischen haben wir festgestellt, dass die Objektäquivalenz sowohl aus equals als auch aus hashCode besteht. Von den Klassen, die wir erstellen, wird angenommen, dass die Ziele, die die Äquivalenz beurteilen und in Sammlungen wie List, Map und Set verarbeiten, POJO (Plain Old Java Object) sind. Unter POJO werden Daten modelliert, dh DTO (Datenübertragungsobjekt), VO (Wertobjekt), Entität (Klasse, die die Tabellenstruktur imitiert), einige Daten mit unterschiedlichen Namen Im Ausdruck von wird die Äquivalenz durch Gleichheit beurteilt.
Equals und hashCode werden von POJO überschrieben, es wird jedoch erwartet, dass die Mittelwerte wie folgt lauten.
Für 1 und 2 ist es eine Implementierung von equals, die überprüft, ob alle Felder dieser Klasse und der Superklasse den gleichen Wert haben.
In Bezug auf 3 scheint es, dass eine Methode, die denselben Wert überprüft, auf dieselbe Weise erstellt oder unter bestimmten Umständen implementiert wird. In diesem Artikel wird dies jedoch nicht angenommen und nicht empfohlen. 1 scheint der Vertreter zu sein.
Die Objekte equals und hashCode sind in der Auflistungs-API wichtig. Wir werden erneut die Beteiligung von equals und hashCode an der Collection-API bestätigen. Da dies eine Einführung auf der Schnittstellenseite ist, lesen Sie bitte das Javadoc und wählen Sie die entsprechende Implementierungsklasse aus, wenn Sie es verwenden.
List
Eine Sammelschnittstelle mit einer Bestellung. Die Implementierungsklassen sind in der Standardimplementierung wie folgt. Es gibt Implementierungen in vielen anderen Bibliotheken.
Diese werden basierend auf den Eigenschaften implementiert, die vom Javadoc der List-Schnittstelle erfüllt werden. Die Implementierungsdetails sind für jede Implementierungsklasse unterschiedlich. Beispielsweise hat LinkedList einen langsamen Direktzugriff (Zugriff über Indizes), der Betrieb von Tip / End-Elementen ist schnell und ArrayList hat einen schnellen Direktzugriff. Wir werden hier nicht darauf eingehen, wie jede Implementierungsklasse ausgewählt wird.
boolean contains(Object o) Gibt true zurück, wenn das angegebene Element in dieser Liste enthalten ist. Das heißt, es wird nur dann true zurückgegeben, wenn diese Liste ein oder mehrere Elemente e enthält, die (o == null? E == null: ** o.equals (e) **) sind.
e ist jedes Element der Liste. Als Ergebnis der Überprüfung der Äquivalenz mit e in o.equals gibt es true zurück, wenn es sogar eine gibt, die true zurückgibt.
Mit anderen Worten, Liste enthält ** verwendet die gleiche Implementierung des übergebenen Objekts **. Einige Sammlungs-APIs verwenden in Operationen für die von der Sammlung gehaltenen Elemente Gleichheit.
boolean remove(Object o) Wenn sich das angegebene Element in dieser Liste befindet, entfernen Sie das erste aus der Liste (optionale Operation). Wenn das Element nicht in dieser Liste enthalten ist, wird es nicht geändert. Löschen Sie also das Element mit dem kleinsten Indexwert i (o == null? Get (i) == null: ** o.equals (get (i)) **) (ein solches Element) Wenn vorhanden). Gibt true zurück, wenn das angegebene Element in dieser Liste enthalten war (dh wenn diese Liste infolge eines Aufrufs geändert wurde).
Gleich wie enthält und hängt von der Implementierung von Gleichen ab. Es wird auch die Überlegung beschrieben, wenn mehrere Objekte gleich sind.
boolean equals(Object o) Vergleicht, ob das angegebene Objekt dieser Liste entspricht. ** Gibt nur dann true zurück, wenn das angegebene Objekt auch eine Liste **, ** derselben Größe ** ist und alle entsprechenden Elemente der beiden Listen gleich sind **. Die beiden Elemente e1 und e2 sind gleich, wenn sie sind (e1 == null? E2 == null: ** e1.equals (e2) **). Das heißt, die beiden Listen werden als ** gleich definiert, wenn dieselben Elemente in derselben Reihenfolge enthalten sind **. Diese Definition stellt sicher, dass die Methode equals mit verschiedenen Implementierungen der List-Schnittstelle ordnungsgemäß funktioniert.
Es ist ersichtlich, dass die Gleichheit von List die Verarbeitung an die Gleichheit der Elementklasse delegiert, über die List selbst verfügt.
Der folgende Abschnitt listA.equals (listB) lautet beispielsweise
StringListEquals.java
List<String> listA = List.of("A", "B", "C");
List<String> listB = List.of("A", "B", "C");
listA.equals(listB); // true
Daher wird true zurückgegeben.
boolean containsAll(Collection<?> c) Gibt true zurück, wenn alle Elemente der angegebenen Auflistung in dieser Liste enthalten sind.
Eine Erweiterung von enthält, die true zurückgibt, wenn die aufrufende Liste alle Elemente des Arguments c enthält (das Ergebnis von enthält ist true).
Mit anderen Worten, es wird überprüft, ob ein Satz alle angegebenen Sätze enthält.
boolean retainAll(Collection<?> c) Behält nur die Elemente bei, die in der angegebenen Sammlung in dieser Liste enthalten sind (optionaler Vorgang). Das heißt, es werden alle Elemente aus dieser Liste entfernt, die nicht in der angegebenen Sammlung enthalten sind.
Mit anderen Worten, Sie erhalten das Produkt eines Satzes und eines bestimmten Satzes. Wenn keine enthalten sind, ist die Anruferliste natürlich leer.
boolean removeAll(Collection<?> c) Entfernt alle Elemente aus der angegebenen Sammlung aus dieser Liste (optionaler Vorgang).
Erweiterung entfernen.
Set
Eine Sammlung ohne doppelte Elemente. Das heißt, die Menge hat kein Elementpaar von e1 und e2, das ** e1.equals (e2) ** ist, und hat höchstens ein Nullelement. Wie der Name schon sagt, modelliert diese Schnittstelle die Abstraktion von Mengen in der Mathematik.
Eine Auflistungsklasse, in der doppelte Elemente nicht beibehalten werden können. Das Urteil über die Vervielfältigung ist fett gedruckt.
Die Idee der Methode ist die gleiche wie bei List. Siehe Javadoc für Details.
SortedSet
Ein Set, das die globale Reihenfolge für dieses Element bereitstellt. Die Reihenfolge der Elemente erfolgt gemäß ihrer natürlichen Reihenfolge oder unter Verwendung des Komparators, der normalerweise beim Erstellen eines Sets bereitgestellt wird. Der Mengeniterator durchläuft die Menge in aufsteigender Reihenfolge der Elemente. Es werden einige zusätzliche Vorgänge bereitgestellt, um diese Bestellung zu nutzen. (Diese Schnittstelle ist ein Set und ähnelt SortedMap.)
Das Folgende sind spezielle Hinweise [^ 2]
Damit ein Sortiersatz die Set-Schnittstelle ordnungsgemäß implementiert, muss die von diesem Sortiersatz verwaltete Reihenfolge mit gleich übereinstimmen, unabhängig davon, ob ein expliziter Komparator bereitgestellt wird. Bitte beachten Sie, dass Sie dies nicht tun sollten. (Die genaue Definition der Konsistenz mit equals finden Sie in der Schnittstelle Compareable oder Comparer.) Dies liegt daran, dass die Set-Schnittstelle basierend auf der Operation equals definiert wird, die Sortiermenge jedoch die Methode compareTo oder ist Da wir die Vergleichsmethode verwenden, um alle Elementvergleiche durchzuführen, sind die beiden Elemente, die von dieser Methode als gleichwertig angesehen werden, unter dem Gesichtspunkt der Sortiermenge gleich. Das Verhalten von Sortiersätzen ist gut definiert, auch wenn ihre Reihenfolge nicht mit gleich übereinstimmt, entspricht jedoch nicht den allgemeinen Konventionen der Set-Schnittstelle.
SortedSet ist eine Auflistungsklasse, die Klassen enthält, die die Schnittstelle Comparable implementieren. Das in Comparable implementierte compareTo muss mit equals übereinstimmen. Das heißt, wenn compareTo 0 ist (die Reihenfolge stimmt überein), sollte equals true zurückgeben.
Referenzartikel Hinweis, weil ich von TreeSet Composer abhängig war (für Anfänger)
Map
Sogenannte Schlüssel-, Wertwörterbuchklasse.
public Set<Map.Entry<K,V>> entrySet() Gibt eine Set-Ansicht der in dieser Map enthaltenen Zuordnungen zurück. ** Da das Set mit der Karte verknüpft ist, werden Änderungen an der Karte im Set ** und Änderungen am Set in der Karte ** wiedergegeben. Wenn die Map während des iterativen Prozesses des Satzes geändert wird, ist das Ergebnis des iterativen Prozesses undefiniert (mit Ausnahme der Entfernungsoperation des Iterators selbst oder der setValue-Operation für den vom Iterator zurückgegebenen Karteneintrag). Das Set unterstützt das Löschen von Elementen. Die Operationen Iterator.remove, Set.remove, removeAll, keepAll und clear entfernen die entsprechende Zuordnung aus der Zuordnung. Add- oder addAll-Operationen werden nicht unterstützt.
Set \ <Map.Entry \ <K, V > > ist in der For Each-Schleife verfügbar. Es wird gezeigt, dass durch das Erfassen aller Elemente von Map mit Set der Betrieb in einer festgelegten Einheit möglich wird.
boolean equals(Object o) Vergleicht, ob das angegebene Objekt dieser Zuordnung entspricht. Das angegebene Objekt ist ebenfalls eine Karte und gibt true zurück, wenn die beiden Karten dieselbe Zuordnung darstellen. Das heißt, wenn m1.entrySet () gleich (m2.entrySet ()) ist, repräsentieren die beiden Abbildungen m1 und m2 dieselbe Zuordnung. Dadurch wird sichergestellt, dass die Methode equals auch dann ordnungsgemäß funktioniert, wenn die Map-Schnittstelle anders implementiert ist.
Stellen Sie A ein
Set B.
StringSetDiff.java
import java.util.HashSet;
import java.util.Set;
public class StringSetDiff {
public static void main(String[] args) {
Set<String> setA = Set.of("a","b","c");
Set<String> setB = Set.of("b","c","d");
//Summensatz
System.out.println("Summensatz");
Set<String> setAcopy = new HashSet<>(setA);
Set<String> setBcopy = new HashSet<>(setB);
setAcopy.addAll(setBcopy); //setB wird zum Inhalt von setA hinzugefügt
setAcopy.forEach(System.out::print);
System.out.println();
//Differenz gesetzt
System.out.println("Differenz gesetzt");
setAcopy = new HashSet<>(setA);
setBcopy = new HashSet<>(setB);
setAcopy.removeAll(setBcopy); //Subtrahiere setB vom Inhalt von setA.
setAcopy.forEach(System.out::print);
System.out.println();
//Produktset
System.out.println("Produktset");
setAcopy = new HashSet<>(setA);
setBcopy = new HashSet<>(setB);
setAcopy.retainAll(setBcopy); //Belassen Sie die Inhalte in setA und setB in setA
setAcopy.forEach(System.out::print);
System.out.println();
//Exklusive logische Summe
System.out.println("Exklusiver logischer Summensatz");
setAcopy = new HashSet<>(setA);
setBcopy = new HashSet<>(setB);
Set<String> setAcopy2 = new HashSet<>(setA);
//Holen Sie sich zuerst das Produktset
setAcopy.retainAll(setBcopy);
//Schließen Sie das Produktset von jedem Set aus
setAcopy2.removeAll(setAcopy);
setBcopy.removeAll(setAcopy);
setAcopy2.addAll(setBcopy);
setAcopy2.forEach(System.out::print);
}
}
Fügen Sie B zu A hinzu.
Vorhersage der Ausführungsergebnisse + =
Summensatz.java
Set<String> setA = Set.of("a","b","c");
Set<String> setB = Set.of("b","c","d");
Set<String> setAcopy = new HashSet<>(setA);
Set<String> setBcopy = new HashSet<>(setB);
setAcopy.addAll(setBcopy); //Set A + Set B.
Ausführungsergebnis
abcd
Subtrahieren Sie B-Set von A-Set
Vorhersage der Ausführungsergebnisse - =
Differenz gesetzt.java
Set<String> setA = Set.of("a","b","c");
Set<String> setB = Set.of("b","c","d");
Set<String> setAcopy = new HashSet<>(setA);
Set<String> setBcopy = new HashSet<>(setB);
setAcopy.removeAll(setBcopy); //Set A-Set B.
Ausführungsergebnis
a
Holen Sie sich die Elemente in den Sets A und B.
Vorhersage der Ausführungsergebnisse × =
Produktset.java
Set<String> setA = Set.of("a","b","c");
Set<String> setB = Set.of("b","c","d");
Set<String> setAcopy = new HashSet<>(setA);
Set<String> setBcopy = new HashSet<>(setB);
setAcopy.retainAll(setBcopy); //Stellen Sie A ein*Set B.
Ausführungsergebnis
bc
Erhalten Sie ein Element, das nur in der A-Menge oder der B-Menge vorhanden ist.
Vorhersage der Ausführungsergebnisse XOR =
Exklusiver logischer Summensatz.java
Set<String> setA = Set.of("a","b","c");
Set<String> setB = Set.of("b","c","d");
setAcopy = new HashSet<>(setA);
setBcopy = new HashSet<>(setB);
Set<String> setAcopy2 = new HashSet<>(setA);
//Holen Sie sich zuerst das Produktset
setAcopy.retainAll(setBcopy); //Stellen Sie A ein*Set B.
//Schließen Sie das Produktset von jedem Set aus
setAcopy2.removeAll(setAcopy); //Stellen Sie A ein- (Stellen Sie A ein*Set B.)=Es existiert nur Satz A.
setBcopy.removeAll(setAcopy); //Set B.- (Stellen Sie A ein*Set B.)=Es existiert nur Satz B.
setAcopy2.addAll(setBcopy); //Stellen Sie A ein,Eine Menge, die nur in einer von B existiert
Ausführungsergebnis
ad
build.gradle
dependencies {
compile 'org.projectlombok:lombok:1.18.8'
compile 'org.apache.commons:commons-lang3:3.7'
compile 'org.slf4j:slf4j-api:1.7.25'
compile 'ch.qos.logback:logback-classic:1.2.3'
}
Record.java
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.apache.commons.beanutils.BeanUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.Comparator;
import java.util.UUID;
@Data
@EqualsAndHashCode
@ToString
@NoArgsConstructor
public class Record implements Comparable {
private UUID primaryKey;
private String name;
private Integer age;
//Damit die Ausgabe besser sichtbar ist
@Override
public int compareTo(Object o) {
if (o instanceof Record) {
//Alter aufsteigende Reihenfolge,Name aufsteigende Reihenfolge
Comparator<Record> comparator =
Comparator.comparing(Record::getAge).
thenComparing(Record::getName).
thenComparing(Record::getPrimaryKey);
return comparator.compare(this, (Record) o);
}
return 0;
}
//Kehren Sie von der Datensatzklasse zur später beschriebenen Änderungserkennung zur Datensatzklasse zurück
public Record(ModifiedRecord modifiedRecord) {
try {
BeanUtils.copyProperties(this, modifiedRecord);
} catch (IllegalAccessException | InvocationTargetException ex) {
ex.printStackTrace();
}
}
public Record(DeleteOrInsertRecord deleteOrInsertRecord) {
try {
BeanUtils.copyProperties(this, deleteOrInsertRecord);
} catch (IllegalAccessException | InvocationTargetException ex) {
ex.printStackTrace();
}
}
}
Eine Klasse, die sogenannte gewöhnliche Tabellendatensätze imitiert. Durch die Implementierung von Comparable wurde es notwendig, compareTo zu implementieren.
Vorsichtsmaßnahmen bei der Implementierung von Comparable Objekte, für die das Ergebnis von compareTo 0 ist, werden auch bei Sammlungen mit einer TreeSet-Reihenfolge als gleichwertig beurteilt. Wenn Sie dem TreeSet mehrere Objekte hinzufügen, die 0 mit compareTo zurückgeben, wie in diesem Beispiel gezeigt, verschwindet eines davon. In der Record-Klasse wird nicht für jedes Feld eine Nullprüfung durchgeführt, daher ist auch für den tatsächlichen Betrieb eine Nullprüfung erforderlich.
DeleteOrInsertRecord.java
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.apache.commons.beanutils.BeanUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.UUID;
/**
*Aufzeichnung für neue / gelöschte Erkennung.
* <pre>
*Diese VO implementiert die Äquivalenz zum Klassifizieren neuer und gelöschter Master.
*Die Gleichheitsmethode wird verwendet, um die Äquivalenz zu bestimmen{@code age, name}Beinhaltet nicht.
* </pre>
*/
@Data
@NoArgsConstructor
@ToString
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class DeleteOrInsertRecord {
@EqualsAndHashCode.Include
private UUID primaryKey;
private Integer age;
private String name;
public DeleteOrInsertRecord(Record record) {
try {
BeanUtils.copyProperties(this, record);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
Eine Datensatzklasse, die die Äquivalenzbeurteilung nur anhand der ID durchführt.
ModifiedRecord.java
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.apache.commons.beanutils.BeanUtils;
import java.lang.reflect.InvocationTargetException;
import java.util.UUID;
/**
*Datensatz für Master-Update.
* <pre>
*Diese VO implementiert die Äquivalenz zum Klassifizieren von Master-Updates.
*Die Gleichheitsmethode wird verwendet, um die Äquivalenz zu bestimmen{@code primaryKey}Beinhaltet nicht.
* </pre>
*/
@Data
@EqualsAndHashCode
@NoArgsConstructor
@ToString
public class ModifiedRecord {
@EqualsAndHashCode.Exclude
private UUID primaryKey;
private Integer age;
private String name;
public ModifiedRecord(Record record) {
try {
BeanUtils.copyProperties(this, record);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
Eine Datensatzklasse, die eine Äquivalenzbeurteilung in anderen Feldern als ID (Name, Alter) durchführt.
RecordPatternSample.java
import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
/**
*Beispiel für eine Datensatzoperation
*/
public class RecordPatternSample {
private Logger logger = LoggerFactory.getLogger(RecordPatternSample.class);
enum ModifiedPattern {
NEW,
UPDATE,
DELETE,
NO_MODIFIED
}
//Ich möchte sortieren und ausgeben, also aktivieren Sie Comparable, das in Record with TreeSet implementiert ist
//Stammsatzgruppe
private SortedSet<Record> masterRecords = new TreeSet<>();
//Datensatzgruppe anfordern (Stammdatensatzaktualisierungsdaten, die von einer Methode gesendet wurden)
private SortedSet<Record> requestRecords = new TreeSet<>();
public RecordPatternSample() {
int totalSize = 100;
while (masterRecords.size() < totalSize) {
masterRecords.add(createRandomRecord());
}
int createSize = masterRecords.size();
//Die Hälfte der vorhandenen Daten in den Anforderungsdaten
int existsDataCount = createSize / 2;
List<Record> createdList = masterRecords.stream().collect(Collectors.toList());
while(requestRecords.size() < existsDataCount) {
Record requestData = createRandomRecord();
requestData.setPrimaryKey(createdList.get(requestRecords.size()).getPrimaryKey());
requestRecords.add(requestData);
}
//Die andere Hälfte sind neue Daten (immer neu von UUID)
while (requestRecords.size() < createSize) {
requestRecords.add(createRandomRecord());
}
}
public static void main(String[] args) {
new RecordPatternSample().exec();
}
private void exec() {
//Holen Sie sich die Summe zum Drucken
//Zu diesem Zeitpunkt werden die entsprechenden Objekte (die für diesen Prozess nicht von Interesse sind, da es sich um nicht aktualisierte Daten handelt) von Set zu einem Objekt zusammengefasst.
Set<Record> aPlusBSet = getPlusSet(masterRecords, requestRecords);
//Vorläufige Listenausgabe
//Basierend auf dem Summensatz werden die entsprechenden Objekte aus der Stammsatzgruppe extrahiert und die Datensatzgruppe angefordert und ausgegeben.
logger.info("print Master , Request.");
aPlusBSet.stream().forEach(e -> {
Optional<Record> masterRecord = searchSameRecord(masterRecords, e);
Optional<Record> requestRecord = searchSameRecord(requestRecords, e);
ModifiedPattern modifiedPattern = getModifiedPattern(masterRecord, requestRecord);
logger.info("{}\t master:{},\t request:{}",
modifiedPattern,
toString(masterRecord),
toString(requestRecord));
});
//Identifizieren Sie neue, gelöschte, aktualisierte und nicht aktualisierte Daten durch Satzberechnung
//Rufen Sie einen Satz ab, der nur in der Anforderungsdatensatzgruppe vorhanden ist.
//Anforderungsdatensatzgruppe - Stammdatensatzgruppe = Daten, die nur in der Anforderungsdatensatzgruppe vorhanden sind
//Das heißt, neue Daten
Set<Record> newRecordSet = getSubtractSet(requestRecords, masterRecords);
logger.info("Anzeige neuer Daten.");
newRecordSet.forEach(e -> logger.info("new :{}", toString(Optional.of(e))));
//Rufen Sie einen Satz ab, der nur in der Stammsatzgruppe vorhanden ist.
//Stammsatzgruppe - Anforderungssatzgruppe = Daten, die nur in der Stammsatzgruppe vorhanden sind
//Das heißt, gelöschte Daten
Set<Record> deleteRecordSet = getSubtractSet(masterRecords, requestRecords);
logger.info("Anzeige gelöschter Daten.");
deleteRecordSet.forEach(e -> logger.info("delete :{}", toString(Optional.of(e))));
//Beziehen Sie den Produktsatz der Stammsätze und Anforderungssätze.
//Stammsatzgruppe (ID) x Anforderungssatzgruppe (ID) = ID-Gruppe, die in beiden vorhanden ist
//Stammsatzgruppe (nach ID extrahiert) x Anforderungssatzgruppe (nach ID extrahiert) = Datengruppe mit beidseitiger ID
//Das heißt, die Aktualisierungsdaten
Set<Record> updateRecordSet = getUpdateSet(masterRecords, requestRecords);
logger.info("Anzeige aktualisierter Daten.");
updateRecordSet.forEach(e -> logger.info("update :{}", toString(Optional.of(e))));
//Existiert sowohl in der Stammsatzgruppe als auch in der Anforderungssatzgruppe und alle stimmen genau überein
Set<Record> noModifiedSet = getSameSet(masterRecords, requestRecords);
logger.info("Anzeige von Daten ohne Aktualisierung.");
noModifiedSet.forEach(e -> logger.info("no modified :{}", toString(Optional.of(e))));
}
/**
*Holen Sie sich das Master-Update-Muster
*
* @param masterRecord Stammsatz
* @param requestRecord Anforderungsdatensatz
* @Master-Update-Muster zurückgeben
*/
private ModifiedPattern getModifiedPattern(Optional<Record> masterRecord, Optional<Record> requestRecord) {
if (masterRecord.isPresent() && requestRecord.isPresent()) {
//Durch Ersetzen durch ModifiedRecord
//Überprüfen Sie die Äquivalenz ohne PK und bestätigen Sie das Vorhandensein oder Fehlen einer Aktualisierung
ModifiedRecord masterModifiedRecord = new ModifiedRecord(masterRecord.get());
ModifiedRecord requestModifiedRecord = new ModifiedRecord(requestRecord.get());
if (masterModifiedRecord.equals(requestModifiedRecord)) {
return ModifiedPattern.NO_MODIFIED;
}
return ModifiedPattern.UPDATE;
}
if (!masterRecord.isPresent()) {
return ModifiedPattern.NEW;
}
if (!requestRecord.isPresent()) {
return ModifiedPattern.DELETE;
}
throw new IllegalStateException();
}
/**
*Suchen Sie den gleichen Primärschlüsseldatensatz in Set
*
* @param set set
* @Parameteraufzeichnung
* @Rückgabe Optionaler Datensatz
*/
private Optional<Record> searchSameRecord(Set<Record> set, Record e) {
return set.stream().filter(t -> t.getPrimaryKey().equals(e.getPrimaryKey())).findFirst();
}
/**
*Holen Sie sich die Zeichenfolgen für UUID, Alter und Namen.
*
* @Parameteraufzeichnung
* @Geben Sie UUID, Alter und Namen in einem Doppelpunkt zurück
*/
private String toString(Optional<Record> e) {
if (!e.isPresent())
return "nothing data";
return e.map(e2 -> String.join(",", e2.getPrimaryKey().toString(), String.valueOf(e2.getAge()), e2.getName())).get();
}
/**
*Holen Sie sich das Produktset
*
* @param setA set A.
* @param setB set B.
* @Produktsatz zurücksenden
*/
private Set<Record> getUpdateSet(final Set<Record> setA, final Set<Record> setB) {
SortedSet<Record> recordSetCopyA = new TreeSet<>(setA);
SortedSet<Record> recordSetCopyB = new TreeSet<>(setB);
//Holen Sie sich den Primärschlüssel für das Produktset
//Extrahieren Sie IDs, die sowohl in Satz A als auch in Satz B vorhanden sind
Set<UUID> samePrimarySet = recordSetCopyA.stream()
.filter(e -> recordSetCopyB.stream().anyMatch(b -> e.getPrimaryKey().equals(b.getPrimaryKey())))
.map(Record::getPrimaryKey)
.collect(Collectors.toSet());
//Aus der Menge A werden die Datensätze extrahiert, die mit den IDs der Elemente der Menge B übereinstimmen.
Set<Record> filteredSetA = recordSetCopyA.stream()
.filter(e -> samePrimarySet.contains(e.getPrimaryKey()))
.collect(Collectors.toSet());
Set<Record> filteredSetB = recordSetCopyB.stream()
.filter(e-> samePrimarySet.contains(e.getPrimaryKey()))
.collect(Collectors.toSet());
//Set A-Set B.
filteredSetA.removeAll(filteredSetB);
return filteredSetA;
}
/**
*Holen Sie sich die Summe gesetzt.
*
* @param setA set A.
* @param setB set B.
* @return Die Summenmenge von Menge A und Menge B.
*/
private Set<Record> getPlusSet(final SortedSet<Record> setA, final SortedSet<Record> setB) {
SortedSet<Record> recordSetAcopy = new TreeSet<>(setA);
SortedSet<Record> recordSetBcopy = new TreeSet<>(setB);
recordSetAcopy.addAll(recordSetBcopy);
return recordSetAcopy;
}
/**
*Holen Sie sich den Unterschied eingestellt.
*
* @param setA set A.
* @param setB set B.
* @Rückgabesatz A minus Satz B.
*/
private Set<Record> getSubtractSet(SortedSet<Record> setA, SortedSet<Record> setB) {
//Stellen Sie sicher, dass die Gleichheitsspezifikation nur von der Primärschlüsselübereinstimmung abhängt
Set<DeleteOrInsertRecord> copyASet = setA.stream().map(DeleteOrInsertRecord::new).collect(Collectors.toSet());
Set<DeleteOrInsertRecord> copyBSet = setB.stream().map(DeleteOrInsertRecord::new).collect(Collectors.toSet());
//Schließen Sie solche mit übereinstimmenden IDs aus
copyASet.removeAll(copyBSet);
//Zum ursprünglichen Datensatz zurückkehren
Set<Record> aSetSubtractBSet = copyASet.stream().map(Record::new).collect(Collectors.toSet());
return aSetSubtractBSet;
}
/**
*Holen Sie sich einen gleichen Satz, in dem alle Elemente übereinstimmen.
*
* @param setA Ein Set
* @param set BB set
* @Rückgabe eines äquivalenten Satzes, in dem alle Elemente im A-Satz und im B-Satz übereinstimmen
*/
private Set<Record> getSameSet(SortedSet<Record> setA, SortedSet<Record> setB) {
SortedSet<Record> recordSetAcopy = new TreeSet<>(setA);
SortedSet<Record> recordSetBcopy = new TreeSet<>(setB);
recordSetAcopy.retainAll(recordSetBcopy);
return recordSetAcopy;
}
/**
*Generieren Sie einen Datensatz mit einem zufälligen Wert.
* <ul>
* <li>id:UUID</li>
* <li>Alter: 1 bis 5 Jahre</li>
* <li>Name: ichiro, jiro, saburo, shiro, goro,Jeder von Rokuro zufällig</li>
* </ul>
*
* @Datensätze mit zufälligen Werten zurückgeben
*/
Record createRandomRecord() {
Record record = new Record();
record.setPrimaryKey(UUID.randomUUID());
record.setAge(RandomUtils.nextInt(1, 5));
String[] names = new String[]{"ichiro", "jiro", "saburo", "shiro", "goro", "rokuro"};
List<String> nameList = Arrays.asList(names);
record.setName(nameList.get(RandomUtils.nextInt(1, nameList.size())));
return record;
}
}
Vergleichen Sie die beiden Datensatzgruppen (Stammsatzgruppe, Anforderungssatzgruppe), Eine Klasse, die Fälle in vier Muster unterteilt: neu, gelöscht, aktualisiert und nicht aktualisiert.
Auf diese Weise ist es durch Steuern der Äquivalenz von Objekten und Verwenden der Erfassungs-API möglich, mithilfe der Leistung von Set-Operationen zu implementieren.
[^ 1]: "Allgemein" ist überzeugender als "Allzweck". Der Originaltext wird als "Generalvertrag" geschrieben. In der japanischen Übersetzung des berühmten Buches "Effective Java" wird es als "Generalvertrag" übersetzt. [^ 2]: Auch in diesem Artikel gab es bei der Implementierung von Comparable # compareTo in der Record-Klasse des Implementierungsbeispiels ein Problem, dass das Element aus Set verschwand, weil es mit equals inkonsistent gemacht wurde.
Recommended Posts