For example, you can easily compare the differences between CSV files. The difference comparison of table data is the same.
Java 11
An example of set operation is shown below.
In addition to this, the difference set can also be obtained.
There are two types of object equivalence in Java:
In Java, identity can be verified by comparing the reference addresses of objects with ==.
Reference.java
Object object = new Object();
Object object2 = new Object();
object == object; // true
object == object2; // false
The equals of the Object class that all objects inherit Equivalence can be determined by overriding.
Equals.java
Object object = new Object();
Object object2 = new Object();
object.equals(object); // true
object.equals(object2); // false
And a method called hashCode is deeply involved in this equals.
First, let's take a look at the equals JavaDoc.
equals JavaDoc equals (from Java8 Oracle HP)
Indicates whether this object is equal to other objects. equals method implements equivalence relations on non-null object references
Concrete example.java
object.equals(null); // false
- Reflexive: For non-null reference values x, x.equals (x) returns true.
Let's look at each one.
- Reflexive: For non-null reference values x, x.equals (x) returns true.
Same as the one illustrated in the object equivalence section.
Equals.java
object.equals(object); // true
- Symmetry: For non-null reference values x and y, x.equals (y) returns true only if y.equals (x) returns true.
Concrete example.java
Object object = new Object();
Object object2 = object;
object.equals(object2); // true
object2.equals(object); // true
- For non-null reference values x, y, and z, x.equals (z) returns true if x.equals (y) returns true and y.equals (z) returns true. If A = B and B = C, then A = C.
Concrete example.java
Object A = new Object();
Object B = A;
Object C = A;
object.equals(object2); // true
object2.equals(object3); // true
//Object2 without comparison.equals(object3)Seems to return true.
- Consistent: Multiple calls to x.equals (y) for non-null reference values x and y If the information used in the equals comparison for this object has not changed, it either consistently returns true or consistently returns false.
No matter how many times equals is executed, if the objects are equivalent, the same result will be returned.
Concrete example.java
object.equals(object); // true
object.equals(object); // true
The equals method of the Object class implements the equivalence relations of the most comparable objects. That is, for non-null reference values x and y, this method returns true only if x and y refer to the same object (x == y is true).
In other words, the equals of the Object class itself in the example above
Concrete example.java
object.equals(object2);
Is
Concrete example.java
object == object2;
Only the above identities are verified unless the class overrides equals.
For example, equals of java.lang.String class returns true first if identity can be confirmed, otherwise it verifies equivalence. Basically, when overriding, follow the flow of identity verification → equivalence verification.
String#equals.java
public boolean equals(Object anObject) {
if (this == anObject) { //Verification of identity
return true;
}
//Equivalence verification
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;
}
Normally, when overriding this method, you should always override the hashCode method and follow the general convention of the hashCode method ** "equivalent objects must hold the equivalent hash code" **. Please note that there is **.
By the way, what is the general rule [^ 1] of hasCode? Shouldn't we just override the equals method in the first place?
hashCode JavaDoc hashCode (from Java8 Oracle HP)
Returns the hash code value of the object. This method is supported for the benefit of hash tables, such as the hash table provided by HashMap.
The hash is [Wikipedia: Hash Function](https://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96 % A2% E6% 95% B0) is detailed.
It expresses the data identification key. Continue reading the Javadoc.
The general rules for hashCode are:
- Whenever a Java application is run and is called multiple times for the same object, the hashCode method always returns the same integer unless the information used in the ** equals comparison for this object has changed. is needed**. However, this integer does not have to be the same for each run of the same application.
Is it the same as the consistency of equals in the previous stage?
- If two objects are equal according to the * equals (Object) method **, then a call to the ** hashCode method for each of the two objects must produce the same integer result **.
- If two objects are not equal according to the equals (java.lang.Object) method, then two Calling the hashCode method for each object does not have to produce different integer results. However, programmers will find that generating different integer results for unequal objects can improve the performance of hash tables. ** "Equivalent objects must hold equivalent hash code" **
The properties of the return values of equals and hashCode for the equivalence and non-equivalence of the two objects are summarized below.
Method | Equivalent object | Non-equivalent objects |
---|---|---|
hashCode | Must be equivalent | Non-equivalent recommended. * It does not have to be non-equivalent, but it is recommended for performance. |
equals | Should return true | Should return false |
By now, we know that object equivalence consists of both equals and hashCode. Of the classes we create, the targets that judge equivalence and handle in collections such as List, Map, and Set are thought to be POJOs (Plain Old Java Objects). Among POJOs, data is modeled, that is, DTO (Data Transfer Object), VO (Value Object), Entity (class that imitates table structure), some data with different names. In the expression of, the equivalence is judged by equals.
Equals and hashCode will be overridden by POJO, but it is expected that the means will be as follows.
For 1 and 2, it is an implementation of equals that verifies whether the fields of that class and superclass are all equivalent.
Regarding 3, it seems that a method that verifies the same value will be created or the implementation will be based on special circumstances, but this article does not assume it and does not recommend it. 1 seems to be the representative.
The objects equals and hashCode are important in the collection API. Once again, we will confirm the involvement of equals and hashCode in the Collection API. Since it will be an introduction on the interface side, please refer to the Javadoc and select the implementation class as appropriate when using it.
List
A collection interface with an order. The implementation class is as follows in the standard implementation. There are implementations in many other libraries.
These are implemented based on the properties that are satisfied by the Javadoc of the List interface. Implementation details are different for each implementation class. For example, LinkedList has slow random access (access using subscripts), operation of tip / end elements is fast, and ArrayList has fast random access. Here, we will not touch on how to select each implementation class.
boolean contains(Object o) Returns true if the specified element is included in this list. That is, it returns true only if this list contains one or more elements e that are (o == null? E == null: ** o.equals (e) **).
e is each element of List. As a result of verifying the equivalence with e in o.equals, if there is even one that returns true, it returns true.
In other words, the contains of the List ** uses the equals implementation of the passed object **. Some collection APIs use equals in operations on the elements held by the collection.
boolean remove(Object o) If the specified element is in this list, remove the first one from the list (optional operation). If the element is not in this list, it will not be modified. That is, delete the element with the smallest index value i that is (o == null? Get (i) == null: ** o.equals (get (i)) **) (such element If exists). Returns true if the specified element was included in this list (that is, if this list was modified as a result of a call).
Same as contains and depends on the implementation of equals. It also describes the consideration when there are multiple objects that are equals.
boolean equals(Object o) Compares whether the specified object is equal to this list. ** Returns true only if the specified object is also a list **, ** of the same size **, and all corresponding elements of the two lists are equal **. The two elements e1 and e2 are equal if they are (e1 == null? E2 == null: ** e1.equals (e2) **). That is, the two lists are defined as ** equal if the same elements are included in the same order **. This definition ensures that the equals method works correctly with different implementations of the List interface.
It can be seen that the equals of List delegates the processing to the equals of the element class that List itself has.
For example, the following listA.equals (listB) section is
StringListEquals.java
List<String> listA = List.of("A", "B", "C");
List<String> listB = List.of("A", "B", "C");
listA.equals(listB); // true
Therefore, true is returned.
boolean containsAll(Collection<?> c) Returns true if all elements of the specified collection are included in this list.
In the extension of contains, if the calling List contains all the elements of the argument c (the result of contains is true), true is returned.
In other words, it verifies that a set contains all the specified sets.
boolean retainAll(Collection<?> c) Keeps only the elements contained in the specified collection in this list (optional operation). That is, it removes all elements not included in the specified collection from this list.
In other words, you get the product of a set and the specified set. Of course, if none are included, the calling List will be empty.
boolean removeAll(Collection<?> c) Removes all elements from the specified collection from this list (optional operation).
Extension of remove.
Set
A collection with no duplicate elements. That is, the set does not have an element pair of e1 and e2 that is ** e1.equals (e2) **, and has a maximum of one null element. As the name implies, this interface models the mathematical abstraction of sets.
A collection class that does not allow duplicate elements to be retained. The judgment of duplication is as shown in bold.
The idea of the method is the same as List. See Javadoc for details.
SortedSet
A Set that provides global ordering for that element. The ordering of the elements is done according to their natural ordering or using the Comparator normally provided when building the set. The set iterator traverses the set in ascending order of elements. Some additional operations are provided to take advantage of that ordering. (This interface is a set and is similar to SortedMap.)
The following are special notes [^ 2]
For a sort set to implement the Set interface correctly, the ordering maintained by that sort set must be consistent with equals, regardless of whether an explicit comparator is provided. Please note that you should not. (See the Compareable or Comparator interfaces for the exact definition of consistency with equals.) This is because the Set interface is defined based on the equals operation, but the sort set is its compareTo method or Since we use the compare method to perform all element comparisons, the two elements that are considered equivalent by this method are the same from the perspective of the sort set. The behavior of sort sets is well defined, even if their ordering is inconsistent with equals, but it does not comply with the general conventions of the Set interface.
SortedSet is a collection class that holds a class that implements the Comparable interface, The compareTo implemented in Comparable must be consistent with equals. In other words, if compareTo is 0 (the order matches), equals should return true.
Reference article Note because I was addicted to the Comparator of TreeSet (for beginners)
Map
So-called key, value dictionary class.
public Set<Map.Entry<K,V>> entrySet() Returns a Set view of the mappings contained in this map. ** Since the set is linked to the map, changes to the map will be reflected in the set **, and changes to the set will be reflected in the map **. If the map is modified during a set iteration, the result of the iteration is undefined (except for the iterator's own remove operation or the setValue operation on the map entry returned by the iterator). The set supports the deletion of elements. Remove the corresponding mapping from the map with the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does not support add or addAll operations.
Set \ <Map.Entry \ <K, V > > is available in the For Each loop. It is shown that it is possible to operate in set units by acquiring all the elements of Map with Set.
boolean equals(Object o) Compares whether the specified object is equal to this map. The specified object is also a map and returns true if the two maps represent the same mapping. That is, if m1.entrySet (). Equals (m2.entrySet ()), the two maps m1 and m2 represent the same mapping. This ensures that the equals method works correctly even if the Map interface implementation is different.
Set A
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");
//Union
System.out.println("Union");
Set<String> setAcopy = new HashSet<>(setA);
Set<String> setBcopy = new HashSet<>(setB);
setAcopy.addAll(setBcopy); //setB is added to the contents of setA
setAcopy.forEach(System.out::print);
System.out.println();
//Difference set
System.out.println("Difference set");
setAcopy = new HashSet<>(setA);
setBcopy = new HashSet<>(setB);
setAcopy.removeAll(setBcopy); //Subtract setB from the contents of setA.
setAcopy.forEach(System.out::print);
System.out.println();
//Intersection
System.out.println("Intersection");
setAcopy = new HashSet<>(setA);
setBcopy = new HashSet<>(setB);
setAcopy.retainAll(setBcopy); //Leave the contents that exist in setA and setB in setA
setAcopy.forEach(System.out::print);
System.out.println();
//Exclusive OR
System.out.println("Exclusive OR set");
setAcopy = new HashSet<>(setA);
setBcopy = new HashSet<>(setB);
Set<String> setAcopy2 = new HashSet<>(setA);
//First get the intersection
setAcopy.retainAll(setBcopy);
//Exclude the intersection from each set
setAcopy2.removeAll(setAcopy);
setBcopy.removeAll(setAcopy);
setAcopy2.addAll(setBcopy);
setAcopy2.forEach(System.out::print);
}
}
Add the B set to the A set.
Prediction of execution results + =
Union.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
Execution result
abcd
Subtract B set from A set
Prediction of execution results - =
Difference set.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
Execution result
a
Get the elements in both the A and B sets.
Prediction of execution results × =
Intersection.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); //Set A*Set B
Execution result
bc
Obtain an element that exists only in either the A set or the B set.
Prediction of execution results XOR =
Exclusive OR set.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);
//First get the intersection
setAcopy.retainAll(setBcopy); //Set A*Set B
//Exclude the intersection from each set
setAcopy2.removeAll(setAcopy); //Set A- (Set A*Set B)=Only set A exists
setBcopy.removeAll(setAcopy); //Set B- (Set A*Set B)=Only set B exists
setAcopy2.addAll(setBcopy); //Set A,A set that exists in only one of B
Execution result
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;
//To make the output easier to see
@Override
public int compareTo(Object o) {
if (o instanceof Record) {
//age ascending order,name ascending order
Comparator<Record> comparator =
Comparator.comparing(Record::getAge).
thenComparing(Record::getName).
thenComparing(Record::getPrimaryKey);
return comparator.compare(this, (Record) o);
}
return 0;
}
//Return to record class from record class for change detection described later
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();
}
}
}
A class that imitates a so-called ordinary table record. By implementing Comparable, it became necessary to implement compareTo.
Precautions when implementing Comparable Objects whose result of compareTo is 0 are judged to be equivalent even on collections with TreeSet order. For this reason, if you add multiple objects that return 0 with compareTo to the TreeSet as shown in this sample, one of them disappears. In the Record class, null check is not performed for each field, so null check is also required for actual operation.
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;
/**
*Record for new / deleted detection.
* <pre>
*This VO implements equivalence for classifying new / deleted masters.
*The equals method is used to determine equivalence{@code age, name}Does not include.
* </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();
}
}
}
Record class that performs equivalence judgment only by ID.
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;
/**
*Record for master update.
* <pre>
*This VO implements equivalence for classifying master updates.
*The equals method is used to determine equivalence{@code primaryKey}Does not include.
* </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();
}
}
}
Record class that performs equivalence judgment in fields other than ID (name, age).
RecordPatternSample.java
import org.apache.commons.lang3.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
/**
*Record set operation sample
*/
public class RecordPatternSample {
private Logger logger = LoggerFactory.getLogger(RecordPatternSample.class);
enum ModifiedPattern {
NEW,
UPDATE,
DELETE,
NO_MODIFIED
}
//I want to sort and output, so enable Comparable implemented in Record with TreeSet
//Master record group
private SortedSet<Record> masterRecords = new TreeSet<>();
//Request record group (master record update data sent by some method)
private SortedSet<Record> requestRecords = new TreeSet<>();
public RecordPatternSample() {
int totalSize = 100;
while (masterRecords.size() < totalSize) {
masterRecords.add(createRandomRecord());
}
int createSize = masterRecords.size();
//Half the number of existing data in the request data
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);
}
//The other half will be new data (must be new by UUID)
while (requestRecords.size() < createSize) {
requestRecords.add(createRandomRecord());
}
}
public static void main(String[] args) {
new RecordPatternSample().exec();
}
private void exec() {
//Get the union for print
//At this point, the equivalent objects (which are not of interest to this process because they are unupdated data) are combined into one by Set.
Set<Record> aPlusBSet = getPlusSet(masterRecords, requestRecords);
//Preliminary list output
//Based on the union, the equivalent objects are extracted from the master record group and request record group and output.
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));
});
//Identify new, deleted, updated, and non-updated data by set calculation
//Get a set that exists only in the request record group.
//Request record group-Master record group = Data that exists only in the request record group
//That is, new data
Set<Record> newRecordSet = getSubtractSet(requestRecords, masterRecords);
logger.info("Display new data.");
newRecordSet.forEach(e -> logger.info("new :{}", toString(Optional.of(e))));
//Get a set that exists only in the master record group.
//Master record group-Request record group = Data that exists only in the master record group
//That is, deleted data
Set<Record> deleteRecordSet = getSubtractSet(masterRecords, requestRecords);
logger.info("View deleted data.");
deleteRecordSet.forEach(e -> logger.info("delete :{}", toString(Optional.of(e))));
//Get the intersection of master records and request records.
//Master record group (ID) x Request record group (ID) = ID group existing in both
//Master record group (extracted by ID) x Request record group (extracted by ID) = Data group with the same ID on both sides
//That is, the update data
Set<Record> updateRecordSet = getUpdateSet(masterRecords, requestRecords);
logger.info("Display of updated data.");
updateRecordSet.forEach(e -> logger.info("update :{}", toString(Optional.of(e))));
//It exists in both the master record group and the request record group, and all match exactly.
Set<Record> noModifiedSet = getSameSet(masterRecords, requestRecords);
logger.info("Display of data without update.");
noModifiedSet.forEach(e -> logger.info("no modified :{}", toString(Optional.of(e))));
}
/**
*Get the master update pattern
*
* @param masterRecord Master record
* @param requestRecord request record
* @return master update pattern
*/
private ModifiedPattern getModifiedPattern(Optional<Record> masterRecord, Optional<Record> requestRecord) {
if (masterRecord.isPresent() && requestRecord.isPresent()) {
//By replacing it with ModifiedRecord
//Verify equivalence excluding PK and confirm the presence or absence of update
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();
}
/**
*Find the record of the same Primary Key from Set
*
* @param set set
* @param e record
* @return Optional record
*/
private Optional<Record> searchSameRecord(Set<Record> set, Record e) {
return set.stream().filter(t -> t.getPrimaryKey().equals(e.getPrimaryKey())).findFirst();
}
/**
*Get the UUID, age and name strings.
*
* @param e record
* @return UUID, age and name in colons
*/
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();
}
/**
*Get the intersection
*
* @param setA set A
* @param setB set B
* @return intersection set
*/
private Set<Record> getUpdateSet(final Set<Record> setA, final Set<Record> setB) {
SortedSet<Record> recordSetCopyA = new TreeSet<>(setA);
SortedSet<Record> recordSetCopyB = new TreeSet<>(setB);
//Get the Primary Key of the intersection
//Extract IDs that exist in both set A and set B
Set<UUID> samePrimarySet = recordSetCopyA.stream()
.filter(e -> recordSetCopyB.stream().anyMatch(b -> e.getPrimaryKey().equals(b.getPrimaryKey())))
.map(Record::getPrimaryKey)
.collect(Collectors.toSet());
//From the set A, the records that match the IDs of the elements of the set B are extracted.
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;
}
/**
*Get the union.
*
* @param setA set A
* @param setB set B
* @return The union of set A and set 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;
}
/**
*Get the difference set.
*
* @param setA set A
* @param setB set B
* @return set A minus set B
*/
private Set<Record> getSubtractSet(SortedSet<Record> setA, SortedSet<Record> setB) {
//Make the equals spec depend only on Primary Key match
Set<DeleteOrInsertRecord> copyASet = setA.stream().map(DeleteOrInsertRecord::new).collect(Collectors.toSet());
Set<DeleteOrInsertRecord> copyBSet = setB.stream().map(DeleteOrInsertRecord::new).collect(Collectors.toSet());
//Exclude those with matching IDs
copyASet.removeAll(copyBSet);
//Revert to original record
Set<Record> aSetSubtractBSet = copyASet.stream().map(Record::new).collect(Collectors.toSet());
return aSetSubtractBSet;
}
/**
*Obtain an equivalence set in which all items match.
*
* @param setA A set
* @param setB B set
* @return Equivalent set in which all items in the A set and B set match
*/
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;
}
/**
*Generate a record with a random value.
* <ul>
* <li>id:UUID</li>
* <li>Age: 1 to 5</li>
* <li>Name: ichiro, jiro, saburo, shiro, goro,Random one of rokuro</li>
* </ul>
*
* @return Record with a random value
*/
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;
}
}
Compare the two records (master record group, request record group) and A class that divides cases into 4 patterns: new, deleted, updated, and no update.
In this way, by controlling the equivalence of objects and utilizing the collection API, it is possible to implement using the power of set operations.
[^ 1]: "General" is more convincing than "general purpose". The original text is written as "general contract". In the Japanese translation of the famous book "Effective Java", it is translated as "general contract". [^ 2]: Also in this article, when Implementing Compareable # compareTo in the Record class of the implementation example, there was a problem that the element disappeared from Set because it was made inconsistent with equals.
Recommended Posts