Comparing boolean values - java

I am facing an issue while comparing boolean values, I want the loop to enter inside the block but its not entering the block.
else if (!(keyCompare.contains(compareKey)) || (save == true)) {
//do something
}
here !(keyCompare.contains(compareKey) will return false. I am seeing if the vector keyCompare does not have compareKey or if save is true then enter if loop, but its not.
Where I am doing wrong?

There are three possibilities:
An if or else if block above this one is executing.
An exception is being thrown by contains.
You're incorrect and both of those conditions are false.
A debugger will tell you exactly which possibility is correct. There's not really any need for discussion here - those are literally the only three possibilities.

Suppose you have a class as follows:
static class Contents {
private String contents;
public Contents(String contents) {
this.contents = contents;
}
}
Writing the following code:
Vector<Contents> v = new Vector<>();
v.add(new Contents("a"));
System.out.println("Contains a: "+v.contains(new Contents("a")));
Would yield the following output:
Contains a: false
However adding the equals method to the Contents class as follows:
public boolean equals(Object obj) {
return Objects.equals(this.contents, ((Contents)obj).contents);
}
Yields suddenly the following result:
Contains a: true
A better implementation might have looked as follows:
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass())return false;
final Contents other = (Contents) obj;
if (!Objects.equals(this.contents, other.contents))return false;
return true;
}

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

Comparing An Entry In A Map With An Object

I have a Map in Java like so,
private HashMap<String, Object[][]> theMap;
Where the key is a String and the entry is going to be something along the line of,
theMap = new HashMap<>();
Object[][] theData = {
{Boolean.FALSE, "Text"}
};
theMap.put("Key1", theData);
Somewhere along the line I would like to check if an entry in the map is equivalent to another object. Currently I am doing it like this,
Object[][] tempData = {
{Boolean.FALSE, "Text"}
};
for(Object key: entries.keySet()) {
if(entries.get(key).equals(tempData)) {
entries.remove(key);
}
}
And it is not working.
I would prefer the comparison to be done with an object rather than with another map. I'm wondering what I'm doing wrong with this comparison here?
The reason you are not getting equality is that arrays inherit Object#equals() which is based on identity, not equality of contents. You could consider using java.util.Arrays.deepEquals(Object[], Object[]) to compare.
That is the answer to the immediate question. However, using a 2-dimensional array of Object to hold a boolean and a String is really bad code smell and indicates you need to encapsulate what you are putting in the array.
Identity vs Equivalence
Please make sure that you understand that by default the equals() method of Object checks on whether two object references are referring to the same object (identity), which is not what your code is checking.
Instead, your code is checking whether the two objects (the values you put on the map) are having the same value (equivalence).
Here are two articles about this topic:
What is the difference between identity and equality in OOP?
Overriding equals method in Java
In this particular problem of yours, I think the solution involves two steps:
Your tempData and theData does not seems to be an array
of elements of the same type (it does not appear to be a 2-dimensional
array either). Instead, it contains a Boolean value and then a
String value. In this case, I think you really should think
through what this thingy is and design a class for it (I am showing
an example below)
The class should override the equals() (and hashCode()) methods
so that you can use its equals() for equivalence checking.
Note also that your IDE (e.g. Eclipse) probably can generate a template for equals() and hashCode() for you.
Example: (here I assume your Boolean represents a condition, and your String represents a message)
class MyRecord {
private Boolean condition;
private String message;
public Boolean getCondition() {
return condition;
}
public void setCondition(Boolean condition) {
this.condition = condition;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((condition == null) ? 0 : condition.hashCode());
result = prime * result
+ ((message == null) ? 0 : message.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;
MyRecord other = (MyRecord) obj;
if (condition == null) {
if (other.condition != null)
return false;
} else if (!condition.equals(other.condition))
return false;
if (message == null) {
if (other.message != null)
return false;
} else if (!message.equals(other.message))
return false;
return true;
}
}

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()));

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.

How can I get the return value of a superclass method without executing it?

This is my superclass equals() method:
public boolean equals(Object other){
Car c = (Car)other;
if(this.make.equals(c.make) && this.model.equals(c.model)){
System.out.println("True, Cars are equal");
return true;
}
else
System.out.println("False, Cars are not equal");
return false;
}
Here is my subclass equals() method:
public boolean equals(Object other) {
GreenCar g = (GreenCar) other;
if(super.equals(g)==true){
if (this.type.equals(g.type)) {
System.out.println("True, Cars are equal");
return true;
} else {
System.out.println("False, Cars are not equal");
return false;
}
}
else
System.out.println("False, Cars are not equal");
return false;
}
When it runs the check at if(super.equals(g)==true){ it executes the method and prints out true or false. How can I just check the return value?
You cannot run the method without letting it print anything.
This is why most of your methods should not have "side effects" (like printing things to the screen).
Remove the println calls from both equals methods. Add them to the code that calls equals instead.
In your super class, you could write something like
protected boolean equals(Object other, boolean debug) {
if (other instanceof Car) {
Car c = (Car) other;
if (this.make.equals(c.make) && this.model.equals(c.model)) {
if (debug) {
System.out.println("True, Cars are equal");
}
return true;
}
}
if (debug) {
System.out.println("False, Cars are not equal");
}
return false;
}
then you can modify your equals() method (still in the super class) like
public boolean equals(Object other) {
return equals(other, true); // <-- default to debug.
}
next your subclass should call the version that takes the debug flag like
if (super.equals(g, false)) { // you don't need == true
Alternatively, you might use a Logger and enable and disable debug on demand.
Like people have said you need to take out those println's if you want it to not print something when you call it, because every time you call the method it will print.
Just as a note you can shorten some of your methods by taking out those elses since it will have returned before getting to the next body of code if the conditional was true. For example
public boolean equals(Object other){
Car c = (Car)other;
if(this.make.equals(c.make) && this.model.equals(c.model))//if this is true
return true;//the method ends here
return false;//if the method hasn't ended yet then the conditional must be false
}
Also I noticed that you used if(super.equals(g)==true) but if you just put if(super.equals(g)) it has the same effect since you are putting in a boolean and it checks if the boolean is true or not. If you want to have the effect of if((boolean)==false) you can do if(!(boolean)) because it checks if the opposite of that boolean is true.

Categories

Resources