Why doesn't my custom object Java HashMap handle unique keys? [duplicate] - java

This question already has an answer here:
When do you need to override hashcode() and equals() when using a hashmap [duplicate]
(1 answer)
Closed 9 months ago.
Below code returns false. Trying to make Equation object act as a key in a custom HashMap. Pretty sure method overrides are implemented correctly, hashCode is the exact same between the two equation instances. What is exactly wrong?
class Solution {
public boolean maxPoints(int[][] points) {
Map<Equation, Integer> map = new HashMap<>();
Equation eq1 = new Equation(1, 2);
Equation eq2 = new Equation(1, 2);
map.put(eq1, 1);
if (map.containsKey(eq1)) return true;
return false;
}
class Equation {
private int slope;
private int yIntercept;
public Equation(int slope, int yIntercept) {
this.slope = slope;
this.yIntercept = yIntercept;
}
public boolean equals(Equation other) {
if (other == this) return true;
return (this.slope == other.slope && this.yIntercept == other.yIntercept);
}
public int hashCode() {
return Objects.hash(this.slope, this.yIntercept);
}
}
}

If you want to overwrite a method annotade it with #Override.
The compiler would give you an error for your equals because you do not overwrite but overload the method
#Override
public boolean equals(Object other) {
...
}

equals needs to be public boolean equals(Object other) to match the signature in Object.
Your equals method doesn't override the one that the code in HashMap is calling.
Usually an equals method looks like this:
#Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (!(other instanceof Equation)) {
return false;
}
// instanceof above also covers null
Equation otherEquation = (Equation) other;
return otherEquation.slope == this.slope
&& otherEquation.yIntercept == this.yIntercept;
}
...or use Project Lombok's #EqualsAndHashCode annotation.

Related

get() and contains() methods do not find object in HashSet although it can be found by iterating and using equals() and the hashcode is the same

I have a program which first generates a Hashmap with all allowed instances of a particular object, called BoardState, as the keys. I then iterate over the keyset, creating copies of the BoardState objects and performing transformations on them and then looking up the transformed objects in my statemap and updating their associated values. The problem is that when I use the contains() method on this keyset (either directly or by first creating a HashSet of the keys) it will sometimes return false for my new object even though the object does exist in the map.
I know that the obvious answer here is that there's something wrong with my implementation of either equals() or hashcode() in BoardState or one of its fields, and I would be inclined to agree. In fact I have been able to narrow the problem down somewhat. BoardState includes as an instance variable a HashSet of Box objects, which I also implemented, and setting the hashcode() method of Box to return a constant resolves the issue (though this obviously is not an acceptable solution).
The thing is, that when I am getting the error I can still iterate through my keyset and find the object by comparing using equals(). If I then output the hashcode for this object and the object I am checking against I get the same result for each, so I'm at a loss as to why it is that contains() is throwing an error.
I apologise if the below code is a bit meaty, I've tried to strip out what I can and only show what's relevant to the error.
public class BoardState {
private static int size;
private static int totalTokens;
private static HashMap<Colour, Integer> colours;
private static HashSet<Token> fullTokenSet;
private int inactiveBoxes;
private HashSet<Box> boxes;
private HashSet<Token> offBoardTokens;
public BoardState(...){...}
public boolean checkRemoveBox(final Box box,
final HashMap<BoardState, Boolean> stateMap) {
BoardState checkState = copy();
checkState.remove(box, box.getBoxColours());
if (!stateMap.keySet().contains(checkState)) {
for (BoardState state : stateMap.keySet()) {
if (state.equals(checkState)){
System.out.println("state hashcode: " + Objects.hash(state));
System.out.println("checkstate hashcode: " +
Objects.hash(checkState));
}
}
throw new IllegalStateException ("State not found.");
} else {
if (!stateMap.get(checkState)) {
return false;
}
}
return true;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BoardState state = (BoardState) o;
return size == state.size &&
inactiveBoxes == state.inactiveBoxes &&
totalTokens == state.totalTokens &&
boxes.equals(state.boxes) &&
fullTokenSet.equals(state.fullTokenSet) &&
offBoardTokens.equals(state.offBoardTokens) &&
colours.equals(state.colours);
}
#Override
public int hashCode() {
return Objects.hash(inactiveBoxes, boxes, offBoardTokens);
}
}
public class Box {
private static int totalTokens;
private HashSet<Token> tokens;
Box(...) {...}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Box box = (Box) o;
return totalTokens == box.totalTokens &&
Objects.equals(tokens, box.tokens);
}
#Override
public int hashCode() {
return tokens.hashCode();
}
}
The given code gives the following output:
state hashcode: 157760
checkstate hashcode: 157760
Exception in thread "main" java.lang.IllegalStateException: State not found.
at game.BoardState.checkSplitBox(BoardState.java:306)
at game.BoardState.checkSplit(BoardState.java:284)
at game.Game.checkForP1Win(Game.java:173)
at game.Main.main(Main.java:11)
Process finished with exit code 1

How to override equals without increasing cyclomatic complexity?

I was recently overriding some equals methods in domain objects of my recent Java project. As we are using Sonar to calculate our code metrics, I immediately saw the cyclomatic complexity of these classes increasing above a threshold.
I'm wondering if there is a clever way, pattern or option at all to keep this metric low although having a little more complex equals method.
EDIT: Here is one of my examples that I have, nothing really specific I would say, just so that we know what we are talking about.
#Override
public boolean equals(Object o) {
if (o instanceof MyKey) {
MyKey other = (MyKey) o;
if (this.foo.longValue() == other.getFoo().longValue() &&
this.bar.equalsIgnoreCase(other.getBar()) &&
this.foobar.shortValue() == other.getFoobar().longValue()){
return true;
}
}
return false;
}
#Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + foo.hashCode();
hash = 53 * hash + bar.hashCode();
hash = 53 * hash + foobar.hashCode();
return hash;
}
You could use Apache's EqualsBuilder:
public boolean equals(Object obj) {
if (obj == null) { return false; }
if (obj == this) { return true; }
if (obj.getClass() != getClass()) {
return false;
}
MyClass rhs = (MyClass) obj;
return new EqualsBuilder()
.appendSuper(super.equals(obj))
.append(field1, rhs.field1)
.append(field2, rhs.field2)
.append(field3, rhs.field3)
.isEquals();
}
You didn't but you should always check for nulls. foo could be null, resulting in a NullPointerException.
this.foo.longValue() == other.foo.longValue()
Luckily Objects utility class saves you from a lot of problems as it automatically checks for nulls.
#Override
public boolean equals(Object object) {
if (object == null)
return false;
if (!(object instanceof MyObject))
return false;
MyObject other = (MyObject) object;
//#formatter:off
return Objects.equals(getX(), other.getX()) &&
Objects.equals(getY(), other.getY()) &&
Objects.equals(getZ(), other.getZ()));
//#formatter:on
}
#Override
public int hashCode() {
return Objects.hashCode(getX(), getY(), getZ());
}
If the fields to check are a lot you can optionally add this at the beginning of the equals method.
if (object == this)
return true;
In theory it can save some computation in some edge case.
The only thing that really helps, in my opinion, is good indentation. I always wrap those line between a pair of //#formatter:off and //#formatter:on. It's boilerplate code, anyway: very easy to write, very easy to make mistakes.
In your case, though, you're checking equality using equalsIgnoreCase. It's a pity Objects doesn't have such a method. You can build your own pretty easily.
public final class Strings {
public static boolean equalsIgnoreCase(String a, String b) {
return a == null ? b == null : a.equalsIgnoreCase(b);
}
private Strings() {
}
}
And use it like this
return Objects.equals (getX(), other.getX()) &&
Strings.equalsIgnoreCase (getY(), other.getY()) &&
Objects.equals (getZ(), other.getZ()));

HashMap doesn't work with user defined key class [duplicate]

This question already has answers here:
Overriding the java equals() method - not working?
(8 answers)
Closed 7 years ago.
I am using Processing language (derived from Java PApplet) version 3.01
Here is my code...
Pig a = new Pig(1);
Pig b = new Pig(1);
HashMap<Pig, String> m = new HashMap<Pig, String>();
m.put(a,"foo");
String c = m.get(b);
println(c);
class Pig {
int a;
Pig(int x) { a=x;}
boolean equals(Pig b) { return b.a==a;}
int hashCode() { return a;}
}
As you can see I am using Pig for key, I defined the equals and hashCode. I expect output "foo", however, I get output null.
Any idea what is going on here? Why doesn't this work?
Try that, you didn't override Object methods at all / correctly :
class Pig {
int a;
Pig(int x) {
a = x;
}
#Override
public boolean equals(Object b) {
if(b == null) return false;
if(!(b instanceof Pig)) return false;
if(b == this) return true;
return ((Pig) b).a == a;
}
#Override
public int hashCode() {
return a;
}
}
You didn't override equals(Object), but you did implement an unrelated equals(Pig) method. HashMap uses the former, your method isn't even called.

Not sure how to complete this equals method

Could someone help me with this question please? I've tried looking up other examples of this to find what I need to do and keep running into something called and EqualsBuilder, is that what I need to use? Do I need to have it call on equals again if it satisfies neither of the IFs?
The following code contains a class definition and an incomplete method definition. The equals method is used to compare Buildings.
It is intended to return true if Buildings have the same names and number of floors (but are not necessarily the same Building) and false otherwise.
public class Building {
private String name;
private int noOfFloors;
public boolean equals (Object rhs) {
if (this == rhs) {
return true;
}
if (!(rhs instanceof Building)) {
return false;
}
Building b = (Building) rhs;
// missing return statement
}
}
public boolean equals (Object rhs) {
if (this == rhs) {
return true;
}
if (!(rhs instanceof Building)) {
return false;
}
Building b = (Building) rhs;
// This is what you're supposed to add. It will return true only if both
// object's attributes (name and number of floors) are the same
return this.name.equals(b.name) && this.noOfFloors == b.noOfFloors;
}
The only thing that you have to test for now is the fields of both objects. If they are equal, then you should return true, if at least one of them is not then you should return false.
Since your fields in that case are int and Stringyou can use == for the integer field and .equals() for the String field.
Something like this should do the job just fine:
if(this.name.equals(b.name) && this.noOfFloors == b.noOfFloors){
return true ;
}
else{
return false;
}
After the instanceOf tests you want to compare the fields of the object to the other object. Something like Objects.deepEquals() should do the trick for you nicely.

Implementation of hashCode in PrimaryKeyClass of spring-data-cassandra

I am using spring-data-cassandra and have a table such that
its primary key is ((int_col1,int_col2),bigint_col1,bigint_col2).
int_col1&int_col2 are the partition keys
bigint_col1 & bigint_col2 are the cluster keys.
How important is it to implement hashcode & equals method for my class.
What should be the hashcode implementation of my above #PrimaryKeyClass
// your class's constructor should have exactly four arguments
// and ensure that each of these four fields are non-null
#Override
public int hashCode() {
return 37
^ int_col1.hashCode()
^ int_col2.hashCode()
^ bigint_col1.hashCode()
^ bigint_col2.hashCode();
}
#Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (!(that instanceof YourPrimaryKeyClass)) {
return false;
}
YourPrimaryKeyClass other = (YourPrimaryKeyClass) that;
return this.int_col1.equals(other.int_col1)
&& this.int_col2.equals(other.int_col2)
&& bigint_col1.equals(other.bigint_col1)
&& bigint_col2.equals(other.bigint_col2);
}

Categories

Resources