Java: Better way to compare sets of 2 numbers than concatenation - java

Here's the situation: I want to test 2 objects for uniqueness based on 2 different ID's. Example:
// Note I'm using JSON notation to keep things simple; the actual code
// is with Java Objects
// OBJECT A
{
main_id: 0,
id_a: 123,
id_b: 456
}
// OBJECT B
{
main_id: 1,
id_a: 123,
id_b: 456
}
// OBJECT C
{
main_id: 2,
id_a: 123,
id_b: 789
}
In the Example, Objects A and B are the same because id_a and id_b are the same, and Object C is different.
To determine this in the code, I'm planning on converting both ID's to a string and concatenating them together with a separator char in the middle (e.g., "{id_a},{id_b}"), then adding them to a Set<String> to test for uniqueness.
My question is, is there a better way? (By better, I mean more efficient and/or less kludgy)

If you want to use HashSet, you can override hashCode and equals to exclusively look at those two members.
Hash code: (31 is just a prime popularly used for hashing in Java)
return 31*id_a + id_b;
Equals: (to which you'll obviously need to add instanceof checks and type conversion)
return id_a == other.id_a && id_b == other.id_b;
If you don't want to bind these functions to the class because it's used differently elsewhere, but you still want to use HashSet, you could consider:
Creating an intermediate class to be stored in the set, which will contain your class as a member and implement the above methods appropriately.
Use your string approach
Use HashSet<Point> - Point is not ideal for non-coordinate purposes as the members are simply named x and y, but I do find it useful to have such a class available, at least for non-production code.
Alternatively, if you want to use TreeSet, you could have your class implement Comparable (overriding compareTo) or provide a Comparator for the TreeSet, both of which would compare primarily on the one id, and secondarily on the other.
The basic idea would look something like this:
if (objectA.id_a != objectB.id_a)
return Integer.compare(objectA.id_a, objectB.id_a);
return Integer.compare(objectA.id_b, objectB.id_b);

Not sure this is any more efficient or less kludgy. You could keep the original hashcode/equals using the main id (as per your comment) and then create a wrapper that has a hashcode/equals for the composite ida, idb. Maybe over the top for what you need though.
CompositeIdEntity.java
public interface CompositeIdEntity {
long getIdA();
long getIdB();
}
Entity.java
public class Entity implements CompositeIdEntity {
private final long mainId;
private final long idA;
private final long idB;
public Entity(long mainId, long idA, long idB) {
this.mainId = mainId;
this.idA = idA;
this.idB = idB;
}
#Override
public long getIdA() {
return idA;
}
#Override
public long getIdB() {
return idB;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (mainId ^ (mainId >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Entity other = (Entity) obj;
if (mainId != other.mainId)
return false;
return true;
}
#Override
public String toString() {
return "Entity [mainId=" + mainId + ", idA=" + idA + ", idB=" + idB
+ "]";
}
}
CompositeIdWrapper.java
public class CompositeIdWrapper {
private final CompositeIdEntity compositeIdEntity;
public CompositeIdWrapper(CompositeIdEntity compositeIdEntity) {
this.compositeIdEntity = compositeIdEntity;
}
public CompositeIdEntity getCompositeIdEntity() {
return compositeIdEntity;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ (int) (compositeIdEntity.getIdA() ^ (compositeIdEntity
.getIdA() >>> 32));
result = prime * result
+ (int) (compositeIdEntity.getIdB() ^ (compositeIdEntity
.getIdB() >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CompositeIdWrapper other = (CompositeIdWrapper) obj;
if (compositeIdEntity.getIdA() != other.compositeIdEntity.getIdA())
return false;
if (compositeIdEntity.getIdB() != other.compositeIdEntity.getIdB())
return false;
return true;
}
}
Test.java
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Entity en1 = new Entity(0, 123, 456);
Entity en2 = new Entity(1, 123, 456);
Entity en3 = new Entity(2, 123, 789);
Entity en4 = new Entity(2, 123, 456);
Entity en5 = new Entity(1, 123, 789);
// Set based on main id
Set<Entity> mainIdSet = new HashSet<>();
mainIdSet.add(en1);
mainIdSet.add(en2);
mainIdSet.add(en3);
mainIdSet.add(en4);
mainIdSet.add(en5);
System.out.println("Main id set:");
for (Entity entity : mainIdSet) {
System.out.println(entity);
}
// Set based on ida, idb
Set<CompositeIdWrapper> compositeIdSet = new HashSet<>();
compositeIdSet.add(new CompositeIdWrapper(en1));
compositeIdSet.add(new CompositeIdWrapper(en2));
compositeIdSet.add(new CompositeIdWrapper(en3));
compositeIdSet.add(new CompositeIdWrapper(en4));
compositeIdSet.add(new CompositeIdWrapper(en5));
System.out.println("Composite id set:");
for (CompositeIdWrapper wrapped : compositeIdSet) {
System.out.println(wrapped.getCompositeIdEntity());
}
}
}
Output
Main id set:
Entity [mainId=1, idA=123, idB=456]
Entity [mainId=2, idA=123, idB=789]
Entity [mainId=0, idA=123, idB=456]
Composite id set:
Entity [mainId=0, idA=123, idB=456]
Entity [mainId=2, idA=123, idB=789]

See this, Here I override the equals() and hashcode() to ensure uniqueness on "name" field of a Person object
public class SetObjectEquals {
Person p1 = new Person("harley");
Person p2 = new Person("harley");
public void method1() {
Set<Person> set = new HashSet<Person>();
set.add(p1);
set.add(p2);
System.out.println(set);
}
public static void main(String[] args) {
SetObjectEquals obj = new SetObjectEquals();
obj.method1();
}
}
class Person {
String name;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
Person(String name) {
this.name = name;
}
}

Related

How to calculate hashCode of this class [duplicate]

This question already has answers here:
Implementing equals and hashCode for objects with circular references in Java
(4 answers)
Closed 3 years ago.
I'm trying to calculate hashcode of one class, but I got stackoverflow. How can I do this correctly? I genered it by IntelliJ idea, but still. Got stackoverflow, I know the reason (probably) but I really want to calculate proper hashcode..
public class Main {
public static void main(String[] args) {
TestA testA = new TestA();
TestB testB = new TestB();
testA.id = 1;
testA.name = "test";
testA.testB = testB;
testB.testA = testA;
testB.id = 1;
testB.name = "test";
System.out.println(testA.hashCode());
}
}
class TestB {
int id;
String name;
TestA testA;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TestB)) return false;
TestB testB = (TestB) o;
if (id != testB.id) return false;
if (name != null ? !name.equals(testB.name) : testB.name != null) return false;
return testA != null ? testA.equals(testB.testA) : testB.testA == null;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (testA != null ? testA.hashCode() : 0);
return result;
}
}
class TestA {
int id;
String name;
TestB testB;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TestA)) return false;
TestA testA = (TestA) o;
if (id != testA.id) return false;
if (name != null ? !name.equals(testA.name) : testA.name != null) return false;
return testB != null ? testB.equals(testA.testB) : testA.testB == null;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (testB != null ? testB.hashCode() : 0);
return result;
}
}
I included main function too. You can easily open this..
What you are looking for is a way to walk the object tree without entering into an infinite loop. This can be achieved by storing the visited objects in a thread-local Set and stopping when entering a hashcode while this is in that set.
And you can't just willy-nilly use a HashSet to store the 'visited' objects, because it internally calls your hashcode so the problem is just shifted elsewhere and you still get a stack overflow. Luckily there's a container that uses identity instead of equality, however it's the Map variant, not the Set. Ideally you want IdentityHashSet, but it doesn't exist, however the still useful IdentityHashMap exists. Just use the keys as the actual contents and use dummy values.
public class Main {
public static void main(String[] args) {
TestA testA = new TestA();
TestB testB = new TestB();
testA.id = 1;
testA.name = "test";
testA.testB = testB;
testB.testA = testA;
testB.id = 1;
testB.name = "test";
System.out.println(testA.hashCode());
}
}
class TestB {
int id;
String name;
TestA testA;
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof TestB))
return false;
TestB testB = (TestB)o;
if (id != testB.id)
return false;
if (name != null ? !name.equals(testB.name) : testB.name != null)
return false;
return testA != null ? testA.equals(testB.testA) : testB.testA == null;
}
private static final ThreadLocal<Set<Object>> VISITED = ThreadLocal.withInitial(() -> new HashSet(10));
#Override
public int hashCode() {
Set<Object> visited = VISITED.get();
if (visited.contains(this))
return 0;
visited.add(this);
try {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (testA != null ? testA.hashCode() : 0);
return result;
} finally {
visited.remove(this);
}
}
}
class TestA {
int id;
String name;
TestB testB;
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof TestA))
return false;
TestA testA = (TestA)o;
if (id != testA.id)
return false;
if (name != null ? !name.equals(testA.name) : testA.name != null)
return false;
return testB != null ? testB.equals(testA.testB) : testA.testB == null;
}
private static final ThreadLocal<Map<Object, Object>> VISITED =
ThreadLocal.withInitial(() -> new IdentityHashMap<>(10));
#Override
public int hashCode() {
Map<Object, Object> visited = VISITED.get();
if (visited.containsKey(this))
return 0;
visited.put(this, this);
try {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (testB != null ? testB.hashCode() : 0);
return result;
} finally {
visited.remove(this);
}
}
}
Note: The two VISITED variables can be a single variable, but since your classes don't have a common superclass (other than Object) I had to make two of them.
Caveat: When the tree contains multiple times the same instance of a class, the hashcode of that instance will be calculated multiple times. This is because everytime that instance is done visiting, it's removed from the list. This is because you don't want hard references to these instances to remain in the thread-local Map, preventing garbage collection.

What is the best way to compare variables of same class?

I have a class with variables for old data and new data.
Example:
class Person{
String newAddress;
int newMobileNumber;
String newOfficeId;
// many fields like this (atleast 15 fields)
String oldAddress;
int oldMobileNumber;
String oldOfficeId;
// many fields like this (atleast 15 fields)
//getters and setters of all the fields.
}
What I am doing is on click of button storing old data and new data in a table consisting column with the same name as that of fields(for keeping track of old data)
But if all the oldFields are equal to newFields I want to avoid to avoid database operation.
one way of doing this is using many if conditions. like this,
if(oldAddress.equals(newAddress)){
flag = true;
}
if(oldMobileNumber.equals(newMobileNumber)){
flag = true;
}
So I'll need many such if() ,I don't find this solution that good. How can I do this in a better way?
You could also throw away all these double values in your Person class and just create a Person variable that is just used to store the old values. You could just update the old values inside your setter methods. To check if any value changed you could override the equals method and compare the current object to the olvValues variable in your Person class.
Due to this way you will safe yourself some extra work if you are adding variables to your Person class at some point.
this could look something like this.
public class Person{
String address;
int mobileNumber;
String officeId;
// many fields like this (atleast 15 fields)
private Person oldValues;
public Person(String address, int mobileNumber, String officeId) {
this.address = address;
this.mobileNumber = mobileNumber;
this.officeId = officeId;
oldValues = new Person(this);
}
public Person(Person p) {
this.address = p.address;
this.mobileNumber = p.mobileNumber;
this.officeId = p.officeId;
}
// Your method that checks if any value did change.
public void checkIfValuesChanged() {
if(this.equals(oldValues)) {
// Nothing changed
}
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + mobileNumber;
result = prime * result + ((officeId == null) ? 0 : officeId.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if(!(obj instanceof Person)) return false;
Person other = (Person) obj;
if (address == null) {
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (mobileNumber != other.mobileNumber)
return false;
if (officeId == null) {
if (other.officeId != null)
return false;
} else if (!officeId.equals(other.officeId))
return false;
return true;
}
// Your setter methods do save the old values in the oldValues Person object
public void setAddress(String address) {
oldValues.address = this.address;
this.address = address;
}
}
You could use ComparisonChain class from Guava to simplify boilerplate code. In your case in would be something like this:
return ComparisonChain.start()
.compare(newAddress, oldAddress)
.compare(newMobileNumber, oldMobileNumber)
...
.result() == 0;
Though I would definitely recommend you to get rid of copy-paste as suggested by Kevin Esche. Comparison chain would be handy in that case either.
UPD Note that if the members of your class can be null than simple oldAddress.equals(newAddress) won't suffice because of NullPointerException. And if you don't want to depend on Guava you could use Objects#equals method to simplify cumbersome null-checking.
You only need to add all those if statements once, in the overridden Object#equals method for your class.
You can have it automatically drafted for you in most IDEs.
You probably also want to override Object#hashCode along the way.
In Ecplise
Right-click your class
Click Source -> Generate hashCode() and equals()
You then compare two Person instances by just invoking equals.
I suggest to define a class Contact and compare an old contact with a new contact using the standard equals method
import org.junit.Test;
public class MyTest {
#Test
public void myTest() {
Contact oldContact= new Contact("A",1,"A");
Contact newContact= new Contact("A",1,"A");
System.out.println(oldContact.equals(newContact));
}
}
class Contact{
String newAddress;
int newMobileNumber;
String newOfficeId;
public Contact(String newAddress, int newMobileNumber, String newOfficeId) {
super();
this.newAddress = newAddress;
this.newMobileNumber = newMobileNumber;
this.newOfficeId = newOfficeId;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Contact other = (Contact) obj;
if (newAddress == null) {
if (other.newAddress != null)
return false;
} else if (!newAddress.equals(other.newAddress))
return false;
if (newMobileNumber != other.newMobileNumber)
return false;
if (newOfficeId == null) {
if (other.newOfficeId != null)
return false;
} else if (!newOfficeId.equals(other.newOfficeId))
return false;
return true;
}
}
class Person{
Contact newContact;
Contact oldContact;
public Person(Contact newContact, Contact oldContact) {
super();
this.newContact = newContact;
this.oldContact = oldContact;
}
}

Java Merge 2 Custom Class results

I have 2 custom Java classes;
private MyCustomClass1 obj1;
private MyCustomClass2 obj2;
Each of them has multiple attributes as below;
MyCustomClass1 {
attr1,
attr2,
commonattrId,
attr3
}
MyCustomClass2 {
attr4,
attr5,
commonattrId,
attr6
}
So as you can see, there is a common attribute in each of them (commonattrId) which just to add is a Long
There is also a composite class defined as below;
MyCompositeClass {
MyCustomClass1 obj1;
MyCustomClass2 obj2;
}
Now one of my query execution returns below list;
List myList1
and there is another query execution which returns me below list;
List myList2
My question is can I combine the above 2 lists given I have a commonattrId ?
slightly long but the idea is to override equals in MyClass1 and MyClass2:
public static void main(String[] args) throws IOException {
List<MyClass1> myClass1s = new ArrayList<MyClass1>();
myClass1s.add(new MyClass1(1, 1));
myClass1s.add(new MyClass1(2, 2));
List<MyClass2> myClass2s = new ArrayList<MyClass2>();
myClass2s.add(new MyClass2(3, 1));
myClass2s.add(new MyClass2(4, 2));
List<MyComposite> allMyClasses = new ArrayList<MyComposite>();
for(MyClass1 m : myClass1s) { // note: you should take the shorte of the two lists
int index = myClass2s.indexOf(m);
if(index != -1) {
allMyClasses.add(new MyComposite(m, myClass2s.get(index)));
}
}
System.out.println(allMyClasses);
}
static class MyClass1 {
int attr1;
long commonAttrId;
public MyClass1(int attr, long commonAttr) {
this.attr1 = attr;
this.commonAttrId = commonAttr;
}
#Override
public int hashCode() {
int hash = 5;
hash = 83 * hash + (int) (this.commonAttrId ^ (this.commonAttrId >>> 32));
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if(obj instanceof MyClass2) {
return this.commonAttrId == ((MyClass2)obj).commonAttrId;
}
if(obj instanceof MyClass1) {
return this.commonAttrId == ((MyClass1)obj).commonAttrId;
}
return false;
}
#Override
public String toString() {
return "attr1=" + attr1 + ", commonAttrId=" + commonAttrId;
}
}
static class MyClass2 {
int attr2;
long commonAttrId;
public MyClass2(int attr, long commonAttr) {
this.attr2 = attr;
this.commonAttrId = commonAttr;
}
#Override
public int hashCode() {
int hash = 5;
hash = 83 * hash + (int) (this.commonAttrId ^ (this.commonAttrId >>> 32));
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if(obj instanceof MyClass1) {
return this.commonAttrId == ((MyClass1)obj).commonAttrId;
}
if(obj instanceof MyClass2) {
return this.commonAttrId == ((MyClass2)obj).commonAttrId;
}
return false;
}
#Override
public String toString() {
return "attr2=" + attr2 + ", commonAttrId=" + commonAttrId;
}
}
static class MyComposite {
MyClass1 myClass1;
MyClass2 myClass2;
public MyComposite(MyClass1 a, MyClass2 b) {
myClass1 = a;
myClass2 = b;
}
#Override
public String toString() {
return "myClass1=" + myClass1 + ", myClass2=" + myClass2;
}
}
I don't know all the parameters of your problem but there are probably better ways to do this. For example: have both MyClass1 and MyClass2 inherit from a common class (i.e. MyBaseClass) and create a collection of that instead of the composite class MyCompositeClass.
Or instead of Lists you could have sets and create a set intersection.
You could create a map from id to the object for one of the lists and then iterate through the other to create the new List using the data from the map.
List<MyCompositeClass> combine(List<MyCustomClass1> myList1, List<MyCustomClass2> myList2) {
// create map
Map<Long, MyCustomClass1> idToObj = new HashMap<>();
for (MyCustomClass1 o : myList1) {
idToObj.put(o.commonattrId, o);
}
// construct result list
List<MyCompositeClass> result = new ArrayList<>();
for (MyCustomClass2 o : myList2) {
MyCustomClass1 o1 = map.get(o.commonattrId);
if (o1 != null) {
MyCompositeClass combined = new MyCompositeClass();
combined.obj1 = o1;
combined.obj2 = o;
result.add(combined);
}
}
return result;
}
This will only add all possible combinations of objects from both lists, if commonattrId values are pairwise distinct in each list, but since the field name has "Id" as suffix, I made an educated guess...

Java HashMap containsKey returns false for existing object

I have a HashMap for storing objects:
private Map<T, U> fields = Collections.synchronizedMap(new HashMap<T, U>());
but, when trying to check existence of a key, containsKey method returns false.
equals and hashCode methods are implemented, but the key is not found.
When debugging a piece of code:
return fields.containsKey(bean) && fields.get(bean).isChecked();
I have:
bean.hashCode() = 1979946475
fields.keySet().iterator().next().hashCode() = 1979946475
bean.equals(fields.keySet().iterator().next())= true
fields.keySet().iterator().next().equals(bean) = true
but
fields.containsKey(bean) = false
What could cause such strange behavioure?
public class Address extends DtoImpl<Long, Long> implements Serializable{
<fields>
<getters and setters>
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + StringUtils.trimToEmpty(street).hashCode();
result = prime * result + StringUtils.trimToEmpty(town).hashCode();
result = prime * result + StringUtils.trimToEmpty(code).hashCode();
result = prime * result + ((country == null) ? 0 : country.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Address other = (Address) obj;
if (!StringUtils.trimToEmpty(street).equals(StringUtils.trimToEmpty(other.getStreet())))
return false;
if (!StringUtils.trimToEmpty(town).equals(StringUtils.trimToEmpty(other.getTown())))
return false;
if (!StringUtils.trimToEmpty(code).equals(StringUtils.trimToEmpty(other.getCode())))
return false;
if (country == null) {
if (other.country != null)
return false;
} else if (!country.equals(other.country))
return false;
return true;
}
}
You shall not modify the key after having inserted it in the map.
Edit : I found the extract of javadoc in Map :
Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.
Example with a simple wrapper class:
public static class MyWrapper {
private int i;
public MyWrapper(int i) {
this.i = i;
}
public void setI(int i) {
this.i = i;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return i == ((MyWrapper) o).i;
}
#Override
public int hashCode() {
return i;
}
}
and the test :
public static void main(String[] args) throws Exception {
Map<MyWrapper, String> map = new HashMap<MyWrapper, String>();
MyWrapper wrapper = new MyWrapper(1);
map.put(wrapper, "hello");
System.out.println(map.containsKey(wrapper));
wrapper.setI(2);
System.out.println(map.containsKey(wrapper));
}
Output :
true
false
Note : If you dont override hashcode() then you will get true only
As Arnaud Denoyelle points out, modifying a key can have this effect. The reason is that containsKey cares about the key's bucket in the hash map, while the iterator doesn't. If the first key in your map --disregarding buckets -- just happens to be the one you want, then you can get the behavior you're seeing. If there's only one entry in the map, this is of course guaranteed.
Imagine a simple, two-bucket map:
[0: empty] [1: yourKeyValue]
The iterator goes like this:
iterate over all of the elements in bucket 0: there are none
iterate over all the elements in bucket 1: just the one yourKeyValue
The containsKey method, however, goes like this:
keyToFind has a hashCode() == 0, so let me look in bucket 0 (and only there). Oh, it's empty -- return false.
In fact, even if the key stays in the same bucket, you'll still have this problem! If you look at the implementation of HashMap, you'll see that each key-value pair is stored along with the key's hash code. When the map wants to check the stored key against an incoming one, it uses both this hashCode and the key's equals:
((k = e.key) == key || (key != null && key.equals(k))))
This is a nice optimization, since it means that keys with different hashCodes that happen to collide into the same bucket will be seen as non-equal very cheaply (just an int comparison). But it also means that changing the key -- which will not change the stored e.key field -- will break the map.
Debugging the java source code I realized that the method containsKey checks two things on the searched key against every element in the key set:
hashCode and equals; and it does it in that order.
It means that if obj1.hashCode() != obj2.hashCode(), it returns false (without evaluating obj1.equals(obj2). But, if obj1.hashCode() == obj2.hashCode(), then it returns obj1.equals(obj2)
You have to be sure that both methods -may be you have to override them- evaluate to true for your defined criteria.
Here is SSCCE for your issue bellow. It works like a charm and it couldn't be else, because your hashCode and equals methods seem to be autogenerated by IDE and they look fine.
So, the keyword is when debugging. Debug itself can harm your data. For example somewhere in debug window you set expression which changes your fields object or bean object. After that your other expressions will give you unexpected result.
Try to add all this checks inside your method from where you got return statement and print out their results.
import org.apache.commons.lang.StringUtils;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class Q21600344 {
public static void main(String[] args) {
MapClass<Address, Checkable> mapClass = new MapClass<>();
mapClass.put(new Address("a", "b", "c", "d"), new Checkable() {
#Override
public boolean isChecked() {
return true;
}
});
System.out.println(mapClass.isChecked(new Address("a", "b", "c", "d")));
}
}
interface Checkable {
boolean isChecked();
}
class MapClass<T, U extends Checkable> {
private Map<T, U> fields = Collections.synchronizedMap(new HashMap<T, U>());
public boolean isChecked(T bean) {
return fields.containsKey(bean) && fields.get(bean).isChecked();
}
public void put(T t, U u) {
fields.put(t, u);
}
}
class Address implements Serializable {
private String street;
private String town;
private String code;
private String country;
Address(String street, String town, String code, String country) {
this.street = street;
this.town = town;
this.code = code;
this.country = country;
}
String getStreet() {
return street;
}
String getTown() {
return town;
}
String getCode() {
return code;
}
String getCountry() {
return country;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + StringUtils.trimToEmpty(street).hashCode();
result = prime * result + StringUtils.trimToEmpty(town).hashCode();
result = prime * result + StringUtils.trimToEmpty(code).hashCode();
result = prime * result + ((country == null) ? 0 : country.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Address other = (Address) obj;
if (!StringUtils.trimToEmpty(street).equals(StringUtils.trimToEmpty(other.getStreet())))
return false;
if (!StringUtils.trimToEmpty(town).equals(StringUtils.trimToEmpty(other.getTown())))
return false;
if (!StringUtils.trimToEmpty(code).equals(StringUtils.trimToEmpty(other.getCode())))
return false;
if (country == null) {
if (other.country != null)
return false;
} else if (!country.equals(other.country))
return false;
return true;
}
}

Sets intersection

I want to apply the inteserction ( using this method http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Sets.html) to sets that contain objects not primitive. I wrote this code but I have that the intersection is empty..
Concept a = new Concept("Dog");
Concept b = new Concept("Tree");
Concept c= new Concept("Dog");
HashSet<Concept> set_1 = new HashSet<Concept>();
HashSet<Concept> set_2 = new HashSet<Concept>();
set_1.add(a);
set_1.add(b);
set_1.add(c);
SetView<Concept> inter = Sets.intersection(set_1,set_2);
System.out.println(inter.size()); ----> I HAVE ZERO !!!
The Concept class contains only a private member of type String and the method of get and set ..I don't have equals() and hashCode().
This works as expected (notice equals and hashCode on Concept)
package com.stackoverflow.so19634761;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import java.util.Set;
public class ISect {
public static void main(final String[] args) {
final Concept a = new Concept("Dog");
final Concept b = new Concept("Tree");
final Concept c= new Concept("Dog");
final Set<Concept> set1 = Sets.newHashSet(a);
final Set<Concept> set2 = Sets.newHashSet(b, c);
final SetView<Concept> inter = Sets.intersection(set1, set2);
System.out.println(inter); // => [Concept [data=Dog]]
}
private static class Concept {
private final String data;
// below this point code was generated by eclipse.
public String getData() {
return data;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((data == null) ? 0 : data.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Concept other = (Concept) obj;
if (data == null) {
if (other.data != null)
return false;
} else if (!data.equals(other.data))
return false;
return true;
}
public Concept(String data) {
this.data = data;
}
#Override
public String toString() {
return "Concept [data=" + data + "]";
}
}
}
You are putting Concept inside Sets, not the Strings - Dog, Tree. U also need to override the hashcode and equals of the concept class for it to work
At first, You need to override equals and hashcode method on Concept class. You don't need third party library. Just use
set_1.retainAll(set2);
set_1.retainAll(set2) transforms set_1 into the intersection of set_1 and set_2. (The intersection of two sets is the set containing only the elements common to both sets.).

Categories