Keys match, but get/containsKey don't find it - java

I am trying retrieve a value from a hashmap. The keys are TransitionKey objects which have implemented equals and hashcode. When I use equals(...) to compare the key I want to look up and the current key in the hashmap, it returns true, but get returns null and containsKey returns false. I have not modified the key in any way since adding it to the hashmap. Can anyone help?
TransitionKey current = new TransitionKey(this.currentState, inputSymbol);
for(TransitionKey tk: transitions.keySet()) {
System.out.println(tk.equals(current)); // True (only one key in table)
System.out.println(transitions.containsKey(current)); // false
String value = transitions.get(tk).toString(); // null
}
In the TransitionKey class:
/**
* #override
*/
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TransitionKey)) return false;
TransitionKey transitionKey = (TransitionKey) o;
return (state.equals(transitionKey.state)) && (symbol==transitionKey.symbol);
}
/**
* #override
*/
public int hashcode() {
int result = (int)symbol;
result = result*31 + state.hashCode();
return result;
}

You haven't overriden hashCode, you have created a new hashcode method (note the c vs. C).
Change your code to
#Override
public int hashCode() {
int result = (int)symbol;
result = result*31 + state.hashCode();
return result;
}
And it should work as expected.
Note that if you hadn't commented out the #Override annotation, you would have received a useful compiler error.

Related

How to correctly implement equals(), hashCode() if the values are within a range of each other?

The criteria is that equals() method where the objects are considered equal if the value of the double variable is within +/- 10 of the other object's value of the double variable.
I'm not sure how to correctly implement hashCode() so that the hashCode would be equal if it satisfies the conditions of the equals() method.
I would really appreciate your input! Thanks!
public class Test
{
private double value;
private boolean isEqualValues (final double valueOne, final double valueTwo)
{
if(valueOne == valueTwo)
{
return true;
}
else if((valueOne - valueTwo <= 10) &&
(valueOne - valueTwo >= -10))
{
return true;
}
else
{
return false;
}
#Override
public boolean equals(final Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
Test test = (Test) o;
if(isEqualValues(test.value, value))
{
return true;
}
else
{
return false;
}
}
//How to implement hashCode()
#Override
public int hashCode()
{
//unsure how to correctly implement hashCode() so that the hashCode would be equal if it
//satisfies the conditions of the equals() method above
}
}
There's no way to consistently implement this, since equals() demands transitivity:
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
new Test(1), new Test(9) and new Test(14) would fail that test (assuming a trivial one-argument constructor that assigns its argument to value).
One way to work around that is to not check for the absolute distance, but "categorize" your objects using some formula, for example take the floor of value / 10 and compare that.
This way some "close" values like new Test(9) and new Test(11) would compare as not-equal, but other than that you'd get a similar result to what you described.
private long getEquivalenceGroup() {
return Math.floorDiv((long) value, 10);
}
#Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Test test = (Test) o;
return test.getEquivalenceGroup() == this.getEquivalenceGroup();
}
#Override
public int hashCode()
{
return Long.hashCode(getEquivalenceGroup());
}
As long as getEquivalenceGroup() is implemented in a stable manner this will produce "groups" of slightly different objects that still compare as equal and has a valid hashCode() implementation.
Note: if you want a comparison as described in the question but you don't necessarily need it to be returned by equals() then adding a boolean isClose(Test other) is perfectly fine. The only problem is you are trying to implement the equals method specifically with that semantic.
You can't and you shouldn't.
You should implement a comparator and do such operations using that.

What happen if hascode function is false while equal function is true

I am thinking about a question if hashcode function is false but equal function is true, what will happen? For example:
public class Demo {
private int age;
private String name;
//getter
//setter
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Demo demo = (Demo) o;
return age == demo.age &&
Objects.equals(name, demo.name);
}
#Override
public int hashCode() {
return Objects.hash(age, name)
+ (new Random().nextInt(1000));
}
}
What will happen is that instances of the Demo class will behave incorrectly when used as hash keys.
Here is one example of what will happen.
Demo demo = new Demo(...);
HashSet<Demo> set = new HashSet<>();
set.add(demo);
System.out.println(set.contains(demo)); // will print false 99.9% of the time.
In other words, the HashSet will lose track elements from the perspective of the contains method. (But they will still be there if you iterate the set. And you will probably be able to add the same Demo object twice ... leading to the set containing duplicates.)

Java "contains" not working properly

My class:
public class UserProgressModel {
private String email;
public UserProgressModel(String pEmail) {
super();
this.email = pEmail;
}
#Override
public boolean equals(Object x) {
if (x != null && x instanceof UserProgressModel
&& ((UserProgressModel) x).email.equals(this.email) == true) {
return true;
}
if (x != null && x instanceof String
&& x.equals(this.email) == true) {
return true;
}
return false;
}
#Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + (this.email != null ? this.email.hashCode() : 0);
return hash;
}
}
And after putting some objects via gson:
UserProgressModel[] userProgressArray;
List<UserProgressModel> retUserProgress = new ArrayList<>();
userProgressArray = gs.fromJson(fileContents,
new TypeToken<UserProgressModel[]>() {
}.getType());
for (UserProgressModel ele : userProgressArray) {
if (ele != null) {
retUserProgress.add(ele);
}
}
I am unable to get true for the following code:
retUserProgress.contains("test#test.com");
I looped thru the array to verify that one object has the email.
Am I doing right? I think I have overridden the equals & hashcode.
Your equals implementation is incorrect. If you look at the contract for equals the implementation must be symmetric:
... for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
In your case you have a list of UserProgressModel objects, but you are trying to compare against a String. While you've implemented UserProgressModel.equals(String) you would still need to have String.equals(UserProgressModel) return the correct result. Since you cannot do that this implementation will never work in all cases. What you should do is two things:
Remove the check in equals for String because it will never work.
Use a mock object to check in the collection:
retUserProgress.contains(new UserProgressModel("test#test.com"));
As long as your equals method is correct within your own type (UserProgressModel.equals(UserProgressModel)) this should fix your issue.
You cannot check if the retUserProgress contains e-mails because it does not. The ArrayList contains objects of Class: UserProgressModel, thus you can check if the ArrayList contains a 'UserProgressModel'.
What you would like to do is the following
private boolean containsEmail(List<UserProgressModel> retUserProgress, String email) {
boolean result = false;
for (UserProgressModel object : retUserProgress) {
if (object.equals(email))
result = true;
}
return result;
}
And the call the method like so:
containsEmail(retUserProgress, "test#test.com"); //This will return a true or false, depending if the ArrayList retUserProgress contains the email
i have tested your code in ideone
and it's working
true
UserProgressModel model=new UserProgressModel("test#test.com");
System.out.print(model.equals("test#test.com"));
false
UserProgressModel model=new UserProgressModel("test#test.com");
System.out.print(model.equals("test#test.co"));
try to compare with new object
retUserProgress.contains(new UserProgressModel("test#test.com"))
result
if you don't wanna compare with a new UserProgressModel you need to create your own list type that when it compare two object (UserProgressModel,string) it creates a new UserProgressModel and pass that email for it

How to compare the data of two same Objects in Java

I have a class
MyData
and its object
myData
In that Class MyData .. there are multiple fields
like
int id
String name
String desc
etc ..
Now i have two objects of this class ..
Is it possible to check that if the data of these two object are all the same , Like both objects have the same Id ,same Name ,same Desc ... Without checking each and every field of this object ..(i.e without checking the id,name,desc of Each object myself) As there are dozens of fields of this object .
I am using JAVA with GWT
Some implementation i came across.. Not sure if this is some thing possible .valid
private static String oldSequence = "";
boolean changed(TestSequence sequence) {
String newSequence = serializeToString(sequence);
boolean changed = !newSequence.equals(oldSequence);
oldSequence = newSequence;
return changed;
}
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(obj);
return b.toByteArray();
}
private static String serializeToString(Object obj) {
try {
return new String(serialize(obj));
} catch (Exception ex) {
return "" + ex;
}
}
Thanks
You should override hashCode() and equals() method. you can generate these from IDE.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MyData)) return false;
MyData myData = (MyData) o;
if (id != myData.id) return false;
if (!desc.equals(myData.desc)) return false;
if (!name.equals(myData.name)) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + name.hashCode();
result = 31 * result + desc.hashCode();
return result;
}
Now you can compare the objects. That's it.
Conventional way is to override equals and hashCode methods. Java standard libraries, for instance Map s, List s, Set s use the equals and hashCode functions for equality testing. The code below also null-safe;
Here is the code for your case;
public class MyData {
int id;
String name;
String desc;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyData myData = (MyData) o;
if (id != myData.id) return false;
if (desc != null ? !desc.equals(myData.desc) : myData.desc != null) return false;
if (name != null ? !name.equals(myData.name) : myData.name != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (desc != null ? desc.hashCode() : 0);
return result;
}
}
and you can test the equality by;
....
Mydata d1 = new...
Mydata d2 = new...
boolean areTheyEqual = d1.equals(d2);
However if you are not allowed to make a compare field by field then you can use byte arrays, there is no need to convert them to strings.
.....
public boolean equals(Object other){
if (this == other) return true;
if (other == null || getClass() != other.getClass()) return false;
byte[] bytesThis = serialize(this);
byte[] bytesOther = serialize(other);
if(bytesOther.length != bytesThis.length) return false;
return Arrays.equals(bytesThis, bytesOther);
}
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(obj);
return b.toByteArray();
}
...
GWT doesn't make a difference to your requirement.
There is no direct way.
You have to define your equality to check weather they are equal or not. That is overriding equals() method.
#Override
public boolean equals(Object obj) { ...
Before doing:Right way to implement equals contract
Like everyone else is saying, you should override the equals() and hashCode() methods.
Note that you don't have to do this manually. In Eclipse you can simply click on Source/generate hashCode() and equals() and it will do the work for you. I am sure other IDEs have similar feature as well.
If you don't want to add any more code when you add a new field, you can try iterating over fields.
You said "Without checking each and every field of this object ..(i.e without checking the id,name,desc of Each object myself) ", I couldn't figure out whether you don't want to check for each field for equality, or don't want to WRITE a check for each field for equality. I assumed the latter since you tried to add an equality comparison method by using bytewise checks.
Anyways, the code to check each field follows. You can copy/paste to any object. If, in the future, you want some fields to be checked and some not, you can use annotations.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyData myData = (MyData) o;
Field[] fields = this.getClass().getDeclaredFields();
for(Field field:fields){
Object o1 = null;
Object o2 = null;
try {
o1 = field.get(this);
o2 = field.get(o);
} catch (IllegalAccessException e) {
return false;
}
if(o1 == null && o2 != null) return false;
if(o2 == null && o1 != null) return false;
if(o2 == null && o1 == null) continue;
if(!o2.equals(o1)) return false;
}
return true;
}
No.
You have to override the equals() method and compare the objects in that.
Override the equals method of the object in MyData and check the fields independently.
Serialize your objects and compare the results!
You just should be wise in selection of your serialization method.
Override hashCode() and equals() methods
hashCode()
This method provides the has code of an object.
Basically the default implementation of hashCode() provided by Object is derived by mapping the memory address to an integer value. If look into the source of Object class , you will find the following code for the hashCode.
public native int hashCode();
It indicates that hashCode is the native implementation which provides the memory address to a certain extent. However it is possible to override the hashCode method in your implementation class.
equals()
This method is used to make equal comparison between two objects. There are two types of comparisons in Java. One is using “= =” operator and another is “equals()”. I hope that you know the difference between this two. More specifically the .equals() refers to equivalence relations. So in broad sense you say that two objects are equivalent they satisfy the equals() condition.

Need proper hashCode when comparing Object with unordered pair of integers as variables

I have a class
final class BuildingPair {
int mBA;
int mBB;
public BuildingPair(int pBuildingA,int pBuildingB) {
mBA = pBuildingA;
mBB = pBuildingB;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + mBA;
result = prime * result + mBB;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BuildingPair other = (BuildingPair) obj;
if ((mBA==other.mBA&&mBB==other.mBB)||(mBA==other.mBB&&mBB==other.mBA)) return true;
return false;
}
}
I want to compare two objects , and when both have the same buildings ids they are equal
so they need to be equal in both directions when :
BuildingPair(1,2) vs BuildingPair(2,1)
BuildingPair(1,2) vs BuildingPair(1,2)
BuildingPair(2,1) vs BuildingPair(1,2)
i think equals method is ok, but hashcode is wrong.
You need something that computes the same result whether passed A,B or B,A. There may be far more subtle solutions, but I'd probably just go for:
#Override
public int hashCode() {
return mBA * mBB;
}
Or anything else which uses an operator that is commutative.
Alternatively, you could change your constructor so that it always stores min(a,b) in mBA and max(a,b) in mBB - you can then simplify your comparison code and keep your hash code as it currently is.
You need a symmetric hashcode (hashcode(a,b) == hashcode(b,a)), for example:
return mBB ^ mBA;
(your current code is not symmetric - for example: hascode (2,1) = 1024 but hashcode(1,2) = 994)
Note: this is inspired from the hashcode of Long:
return (int)(value ^ (value >>> 32));
If they are unordered you can use an arbitrary order which simplifies the rest of the code.
public BuildingPair(int pBuildingA,int pBuildingB) {
mBA = Math.min(pBuildingA, pBuildingB);
mBB = Math.max(pBuildingA, pBuildingB);
}
code the rest of the methods as normal and BuildingPair(2,1) will be exactly the same as BuildingPair(1,2)

Categories