Equality comparison -- any saner way? - java

How do I implement this equality comparison is a sane java way?
boolean x = (a == b) || (a.equals(b))
I want to make sure the content of both objects is equal but null is also ok, i.e. both can be null and are thus equal.
Update: just to be clear, I have to implement this comparison several times and don't want to copy&paste this stuff every time, especially with lenghty object names. With 'a' and 'b' it looks small and simple, but tends to grow... I'd like to know if I'm missing some existing Java feature for this.

You might want to have a look at the always useful Apache Commons Lang, more precisely ObjectUtils.equals().

Another way to do
boolean x = null==a ? null==b : a.equals(b);

The typical pattern is:
if (a == b)
{
return true;
}
if (a == null || b == null)
{
return false;
}
// Now deal with a and b, knowing that they are non-identical, non-null references
Yes, it's wordy - but if you separate it out into its own method, you can keep it under reasonable control.

What happens if a is null but b is not? I think you really want:
boolean x = (a == null && b == null) || (a != null && a.equals(b))
EDIT: You could implement a static NullEquals method for the class that takes two objects of that class and does the comparison as above to avoid rewriting and make the code a little cleaner.
public class MyClass {
public static boolean NullEquals( MyClass a, MyClass b )
{
return (a == null && b == null) || (a != null && a.equals(b));
}
}
if (MyClass.NullEquals(a,b))
{
...
}

Not a direct answer, but if you have lot of objects that can be or not null, may be that indicates some problem with your code. Take a look at the Null Pattern , that is an alternative way to represent the absence of an object

What about:
boolean x = equals( a, b );
public static boolean equals( Object a, Object b ) {
if ( a == null && a == b ) {
return true;
} else {
return a == b || a.equals( b );
}
}
Let me see.
if a is null and a is b then it's ok
if a is not null then if a == b ( same ref ) return true by shortcircuit
if a is not b ( 2dns part of the OR probably b is null ) then return a ( not null ) .equals( b ) whatever b is
Yeap covered.

Can not add comment,
Treat this as comment to Jon Skeet's answer.
Does Null = Null true or false in Java.
More specifically what should be Null = Null should be treated and How and why the different language treat this case ?

The most common way of doing it is:
a==null ? b==null : a.equals(b)
A potentially slightly more efficient, but less clear, expressions is:
a==b || (a!=null && a.equals(b))
You can of course put this inside a method:
public static boolean eq(Object a, Object b) {
return a==b || (a!=null && a.equals(b));
}
Note the original question code NPEs if a is null and b is non-null.

For performance reasons, usually it is good to check for identity before executing any other logic, as was done in the question. However, many of the answers don't take this into account.
The best place to put the identity check is in the implementation of the equals method on your class:
public boolean equals(Object obj) {
if(this == obj) return true;
...
}
If this has/can be done, you can do the comparison easily:
a == null ? b == null : a.equals(b);
Otherwise you might have to check for identity yourself:
a == null ? b == null : (a == b || a.equals(b));

Related

How do I specify both objects when overriding equals method?

I'm doing an assignment that asks me to override the equals method of a house class.
The instructions are as follows:
Two houses are equal when their building areas are equal and their pool status is the same
Until now, this is what I've wrote:
#Override
public boolean equals(Object other) {
if (other instanceof House) {
House otherHouse = (House) other;
return otherHouse.calcBuildingArea() == ???
&& otherHouse.mPool == ???
} else {
return false;
}
}
Now I don't know what to write after the == signs. I don't know how to specify the object that calls the method.
If you call a method without specifying an object, the method will get called on the current object. So you can write
return otherHouse.calcBuildingArea() == calcBuildingArea()
&& otherHouse.mPool == mPool;
or if you want to make it nice and clear and explicit, you can write
return otherHouse.calcBuildingArea() == this.calcBuildingArea()
&& otherHouse.mPool == this.mPool;
Note also that this assumes that mPool is of a primitive type or an enum type. If it's a reference type, such as String, you may need to invoke its equals method like
return otherHouse.calcBuildingArea() == calcBuildingArea()
&& otherHouse.mPool.equals(mPool);
or even the more null-friendly
return otherHouse.calcBuildingArea() == calcBuildingArea()
&& Objects.equals(otherHouse.mPool, mPool);
How about this?
return otherHouse.calcBuildingArea() == this.calcBuildingArea()
&& otherHouse.mPool == this.mPool

Java Multiple comparision in java

Pardon me if this is a stupid question.. I was wondering if there is any support for following comparison in Java:
(a, b, c .... != null) in place for :
(a != null && b != null && c != null && d ! null and so on ..)
I was trying to make code more readable as my code which is almost unreadable due to multiple condition in single statement.
code :
variable = (rest.host != null && rest.payload != null
&& rest.lockQueue != null && rest.endpoint != null ) || rest.default.setState
|| rest.scheduler.locked && rest.scheduler.queue.isFull()
&& lastPayload.getActivity.status.executing ? onExecute(rest.payload) : wait(TIME);
If your elements are in a collection, use collection.stream().allMatch(x -> x != null). Actually, there's even a predicate for that: collection.stream().allMatch(Objects::nonNull).
If your elements aren't in a collection, you can still use Arrays.asList() to create an ad-hoc list from them. So, in your case:
Arrays.asList(rest.host, rest.payload, rest.lockQueue, rest.endpoint).stream().allMatch(Objects::nonNull)
EDIT: actually, as someone mentioned in another answer, there is a method that creates a stream directly, namely Stream.of(...). So:
Stream.of(rest.host, rest.payload, rest.lockQueue, rest.endpoint).allMatch(Objects::nonNull)
You could do something like this to make sure everything is not null, if using a Java version lower than 8. Otherwise I would go with the other people's answers using streams.
private boolean checkIfNotNull( Object ... objects ) {
for(int i = 0; i < objects.length; i++) {
if(objects[i] == null)
return false;
}
return true;
}
and you could pass in all the objects that you want to check if they are null.
then you can call this in the if statement such as
if( checkIfNotNull( a, b, c, d, e, f, g ) ) {
//do stuff
}
In java 8, it could be done as next Stream.of(a, b, c, d).allMatch(Objects::nonNull), it will return true if they are all non null.
I think if you want your code more readable, you should replace your comparisons with method calls that "says" what each comparison is.
Example:
if (isAllRight(a, b, c)) {
...
}
In other cases you can break them into single comparisons and check one by one:
if (a == NUL) {
return false;
}
if (b == NULL) {
return false;
}
return true;

How can I cast an Object in an equals override method in Java?

I have the following code in a class used to simulate the IRS with employer filings in accordance with the filer. I am required to override the equals class but I keep getting the error saying that the methods I am trying to use cannot be found when called on the casted Object.
#Override
public boolean equals(Object obj) {
if ((this == null )|| (obj == null) || (this.getClass() != obj.getClass()))
return false;
if ((this.sameEmployer((Employer)obj))
&& (this.getEmployeeSSN() == (Employer)obj.getEmployeeSSN())
&& (this.getName() == (Employer)obj.getName())
&& (this.getEmployeeName() == (Employer)obj.getEmployeeName())
&& (this.getEmployeeWages() == (Employer)obj.getEmployeeWages()))
return true;
else
return false;
}
Casting happens after method calls. According to the precedence of operators, () for method calling is at the highest level, 1, while () for casting is at level 3. In other words you are attempting to cast obj.getEmployeeSSN() as an Employer, not obj.
Once you know obj is an Employer, you can place parentheses to force casting first, e.g.
&& (this.getEmployeeSSN() == ((Employer) obj).getEmployeeSSN())
However, it looks like a mess of parentheses. For clarity, just declare an Employer variable, cast it once, then call the methods, passing the Employer variable.
Employer emp = (Employer) obj;
if (this.sameEmployer(emp)
&& ...
For expressions like this:
(Employer)obj.getEmployeeSSN()
The . has higher precedence - "binds tighter" - than the cast. So it's closer to:
(Employer) (obj.getEmployeeSSN())
... whereas you want:
((Employer) obj).getEmployeeSSN()
in order to cast and then call the method. That's most easily done by casting in an earlier line:
public boolean equals(Object obj) {
if (obj == null || this.getClass() != obj.getClass()) {
return false;
}
Employee other = (Employee) obj;
// Now use "other" in the rest of the code:
return sameEmployer(other)
&& getEmployeeSSN() == other.getEmployeeSSN()
...;
}
Note that:
this can never be null, so you don't need to test it
You don't need nearly as many brackets as you had before
I'd strongly encourage you to use braces for all if blocks... you'd be surprised at how easy it is to end up with mistakes otherwise. (There are lots of SO questions which are basically due to that...)
Any time you have:
if (foo) {
return true;
} else {
return false;
}
you should simplify it to:
return foo;
Class Object doesn't have getEmployeeSSN(). What you should have instead is :
(this.getEmployeeSSN() == ((Employer)obj).getEmployeeSSN() //and so forth.
The cast should happen first, then you try to use the method on the casted object
You just have a problem with priority of your operations. The cast to (Employer) will happen after you call the specific methods. To enforce the priority you need to add brackets:
((Employer) obj).getName()
instead of
(Employer) obj.getName()

How do I compare the "state" of two objects of the same type?

I'm supposed to create my own equals() method which overrides the equals(method) of the parent class. This method accepts a Counter object as its argument. In the code below, I want an easy way to determine if the Counter object argument equals the current instance of the Counter class, if that makes sense. I have achieved this in the code below by comparing the fields of each object one by one, but I want a simpler way to do it. Something that looks like this would be nice: "result = (otherCounter == new Counter(min,max) ? true : false);", but I know that's not right and it gets an error. How do I compare the equality of the variables in the two Counter objects, so that c1.equals(c2) will be false if Counter objects c1 and c2 are different?
public boolean equals(Object otherObject)
{
boolean result = true;
if (otherObject instanceof Counter)
{
Counter otherCounter = (Counter)otherObject;
result = (otherCounter.min == this.min) &&
(otherCounter.max == this.max) &&
(otherCounter.currentCount == this.currentCount) &&
(otherCounter.rolloverOccurrence == this.rolloverOccurrence) ? true : false;
}
return result;
}
Operator overloading is not possible in Java.
And to compare two object are equal or not you should use .equals() method no matter what.
Ex: obj1.equals(obj2)
It is because sometimes Java API (ex: Collections) will internally call equals method to sort the collection. So there is no simple way to compare but to use equals()
Your method is just fine like this except for the other answers you got here that state that there is not overloading of operators in Java, the thing with the result = true instead of false and commenting you remember to override hashCode if you didn't already do. Let me give you one more advise. The method can be written in some more compact way:
public boolean equals(Object obj) {
if (!(obj instanceof Counter)) {
return false;
}
Counter other = (Counter) obj;
return other.min == this.min && other.max == this.max &&
other.currentCount == this.currentCount &&
other.rolloverOccurrence == this.rolloverOccurrence;
}

What is the correct way to implement compareObjects()

I have compareObjects method implemented as below
public static int compareObjects(Comparable a, Comparable b){
if (a == null && b == null){
return 0;
} else if (a == null && b != null){
return -1;
} else if (a != null && b == null){
return 1;
} else {
return a.compareTo(b);
}
}
When I run this through findBugs, I get this suggestion on the line return a.compareTo(b):
There is a branch of statement that, if executed, guarantees that a null value will be dereferenced, which would generate a NullPointerException when the code is executed. Of course, the problem might be that the branch or statement is infeasible and that the null pointer exception can't ever be executed; deciding that is beyond the ability of FindBugs. Due to the fact that this value had been previously tested for nullness, this is a definite possibility.
At this point a can never be null. Why does FindBugs show me this suggestion? How can I correct this; what is the correct way to implement compareObjects()?
I think it might be because you don't need the extra && statements. After the first if statement you already know that one of them is null.
public static int compareObjects(Comparable a, Comparable b){
if (a == null && b == null){
return 0;
} else if (a == null){
return -1;
} else if (b == null){
return 1;
} else {
return a.compareTo(b);
}
}
Looking at it again , try this code:
if (a == null && b == null){
return 0;
}
if (a == null){
return -1;
}
if (b == null){
return 1;
}
return a.compareTo(b);
It may be a limitation in FindBugs; I agree that you've covered all the bases, but your null-check is split across two different conditions. Now these conditions happen to be complementary, so at least one of them will fire if a is null, but depending how sophisticated FindBugs is, it may not recognise this.
Two options here, then:
Just ignore the FindBugs warning. Due to its nature it will raise some false positives from time to time, so don't feel like you have to rewrite your code to make it 100% happy if you don't think the rewrite is worthwhile on its own merits.
You can use the #SuppressWarnings annotation to actually communicate this to FindBugs, if you want the report to show a nice big zero at the end. See this question for an example.
Restructure the condition so that the nullity check on a is more explicit, by nesting if blocks:
if (a == null) {
return b == null ? 0 : -1;
}
return b == null ? 1 : a.compareTo(b);
Depending on your tastes and style that might be a better rewrite anyway, in that is more clearly says "if a is null, do this calculation and return it, otherwise do this calculation". You can of course change the ternary condition into another if-else block if you prefer that.

Categories

Resources