They're two completely different things. == compares the object reference, if any, contained by a variable. .equals() checks to see if two objects are equal according to their contract for what equality means. It's entirely possible for two distinct object instances to be "equal" according to their contract. And then there's the minor detail that since equals is a method, if you try to invoke it on a null reference, you'll get a NullPointerException.

For instance:

class Foo {
    private int data;

    Foo(int d) {
        this.data = d;
    }

    @Override
    public boolean equals(Object other) {
        if (other == null || other.getClass() != this.getClass()) {
           return false;
        }
        return ((Foo)other).data == this.data;
    }

    /* In a real class, you'd override `hashCode` here as well */
}

Foo f1 = new Foo(5);
Foo f2 = new Foo(5);
System.out.println(f1 == f2);
// outputs false, they're distinct object instances

System.out.println(f1.equals(f2));
// outputs true, they're "equal" according to their definition

Foo f3 = null;
System.out.println(f3 == null);
// outputs true, `f3` doesn't have any object reference assigned to it

System.out.println(f3.equals(null));
// Throws a NullPointerException, you can't dereference `f3`, it doesn't refer to anything

System.out.println(f1.equals(f3));
// Outputs false, since `f1` is a valid instance but `f3` is null,
// so one of the first checks inside the `Foo#equals` method will
// disallow the equality because it sees that `other` == null
Answer from T.J. Crowder on Stack Overflow
Top answer
1 of 16
213

They're two completely different things. == compares the object reference, if any, contained by a variable. .equals() checks to see if two objects are equal according to their contract for what equality means. It's entirely possible for two distinct object instances to be "equal" according to their contract. And then there's the minor detail that since equals is a method, if you try to invoke it on a null reference, you'll get a NullPointerException.

For instance:

class Foo {
    private int data;

    Foo(int d) {
        this.data = d;
    }

    @Override
    public boolean equals(Object other) {
        if (other == null || other.getClass() != this.getClass()) {
           return false;
        }
        return ((Foo)other).data == this.data;
    }

    /* In a real class, you'd override `hashCode` here as well */
}

Foo f1 = new Foo(5);
Foo f2 = new Foo(5);
System.out.println(f1 == f2);
// outputs false, they're distinct object instances

System.out.println(f1.equals(f2));
// outputs true, they're "equal" according to their definition

Foo f3 = null;
System.out.println(f3 == null);
// outputs true, `f3` doesn't have any object reference assigned to it

System.out.println(f3.equals(null));
// Throws a NullPointerException, you can't dereference `f3`, it doesn't refer to anything

System.out.println(f1.equals(f3));
// Outputs false, since `f1` is a valid instance but `f3` is null,
// so one of the first checks inside the `Foo#equals` method will
// disallow the equality because it sees that `other` == null
2 of 16
52

In addition to the accepted answer (https://stackoverflow.com/a/4501084/6276704):

Since Java 1.7, if you want to compare two Objects which might be null, I recommend this function:

Objects.equals(onePossibleNull, twoPossibleNull)

java.util.Objects

This class consists of static utility methods for operating on objects. These utilities include null-safe or null-tolerant methods for computing the hash code of an object, returning a string for an object, and comparing two objects.

Since: 1.7

🌐
DeepSource
deepsource.com › directory › java › issues › JAVA-E0110
`equals` method does not handle null valued operands (JAVA-E0110) ・ Java
One property of any non-static method in Java is that the receiver object (this) is always non-null. This code violates the contract of equals because any null value passed is automatically not equal to this.
🌐
JoeHx Blog
joehxblog.com › does-null-equal-null-in-java
Does Null Equal Null in Java? – JoeHx Blog
October 31, 2018 - true: true false: false null == null: true string == null: true number == null: true Objects.equals(null, null): true Objects.equals(string, null): true Objects.equals(number, null): true Objects.equals(string, number): true · The first two outputted lines were just to get a feel as to how Java outputs the raw boolean values true and false.
🌐
Coderanch
coderanch.com › t › 523760 › java › null-null-java
null==something vs something==null in java (Beginning Java forum at Coderanch)
The only exception being comparing against String constants: "value".equals(var). But that's only because that's faster than the alternative: var != null && var.equals("value").
🌐
EqualsVerifier
jqno.nl › equalsverifier › manual › null
Dealing with null - EqualsVerifier
2 weeks ago - For safety, EqualsVerifier requires you to add null checks for non-primitive fields you reference in your equals or hashCode method. If you don’t, you will get the following error message: Non-nullity: equals throws NullPointerException on field o.
Find elsewhere
🌐
Medium
medium.com › @AlexanderObregon › javas-objects-equals-method-explained-3a84c963edfa
Java’s Objects.equals() Method Explained | Medium
5 days ago - The Objects.equals() method makes object comparisons in Java easier while handling null values safely. It helps prevent NullPointerException, keeps code readable, and makes equality checks more reliable.
🌐
TutorialsPoint
tutorialspoint.com › comparing-strings-with-possible-null-values-in-java
Comparing Strings with (possible) null values in java?
In the same way the equals() method of the object class accepts two String values and returns a boolean value, which is true if both are equal (or, null) and false if not. import java.util.Scanner; public class CompringStrings { public static void main(String args[]) { Scanner sc = new ...
🌐
Errorprone
errorprone.info › bugpattern › EqualsNull
EqualsNull
The contract of Object.equals() states that for any non-null reference value x, x.equals(null) should return false. Thus code such as ... either returns false, or throws a NullPointerException if x is null. The nested block may never execute. This check replaces x.equals(null) with x == null, ...
🌐
Quora
quora.com › Why-is-null-null-true-in-java
Why is null == null true in java? - Quora
Answer (1 of 8): In java only references can have the value null. As per the Java Language Specification it's "merely a special literal that can be of any reference type". For references == returns true if and only if the value of the two references are the same (or informally "they point to the...
🌐
Coderanch
coderanch.com › t › 545457 › java › comparing-values-equalsIgnoreCase-equals-NULL
comparing two values with equalsIgnoreCase and equals with NULL as first value. (Java in General forum at Coderanch)
If one is null and other has values,if these are assigned at run time ; how do I compare with equalsIgnoreCase and equals() ? Apparently null is different from any other value,so I HAVE TO EXPECT null and other values in both elements. This happends for only first element. How do I write a refined code for comparing two values considering or expecting null ? if I use the following way,its not correct ... Find the java.util.Objects class, which has equals() methods overloaded to take two parameters, and can cope with null values.
Top answer
1 of 1
14

First up, yes, you're right that the second null check is redundant. If obj is null then the method will return false on the first check:

    if (!(obj instanceof ArrayOfColumn)) return false;

Of course, that would better be written:

    if (!(obj instanceof ArrayOfColumn)) {
        return false;
    }

But, that's the least of my concerns. The synchronized equals is probably there because other methods are synchronized, but synchronization comes at a cost. Unless you are sure you need it, remove it.

Additionally, synchronized methods are seldom the best solution. It is normally better to have tighter control of your locks so that nobody but you can hold them. That normally means using a private, internal "monitor" for synchronization:

private final Objct lock = new Object();

private boolean equals(Object obj) {
    synchronized(lock) {
        .....
    }
}

Using the private lock prevents other people from hanging your application by using your class as their own monitor. Imagine if your class is called MyClass, and someone does:

 private MyClass instance = new MyClass();

 synchronized(instance) {
     Thread.sleep(10000);
 }

If they did the above, your methods in other threads would never run, and your application would "hang".

Now, abut the __equalsCalc variable. It does nothing useful. It is set, and then cleared, inside the synchronized method, and, as a result, it will never, ever have any value in it that is useful. It is completely redundant and a waste of time.

Oh, and what's with the fully qualified java.lang.Object? Just use Object.

I would rewrite the method as (using the same synchronized method to be compatible with other methods in your class):

public synchronized boolean equals(Object obj) {
    if (!(obj instanceof ArrayOfColumn)) {
        return false;
    }
    if (obj == this) {
        return true;
    }
    ArrayOfColumn other = (ArrayOfColumn) obj;
    if (getColumn() == null) {
        return other.getColumn() == null;
    }
    return other.getColumn() != null && Arrays.equals(column, other.getColumn());
}

Note that you still have a synchronization vulnerability - the other column's column could be changed between checking for whether it's column is null, and using the column in the equals. You could still get null pointer exceptions if someone changes the other column in the middle of your equals. You should consider synchronizing on that other column too:

public synchronized boolean equals(Object obj) {
    if (!(obj instanceof ArrayOfColumn)) {
        return false;
    }
    if (obj == this) {
        return true;
    }
    ArrayOfColumn other = (ArrayOfColumn) obj;
    synchronized(other) {
        if (getColumn() == null) {
            return other.getColumn() == null;
        }
        return other.getColumn() != null && Arrays.equals(column, other.getColumn());
    }
}

Unfortunately, cross-synchronizing like that can lead to deadlocks if you are not careful.

🌐
Coderanch
coderanch.com › t › 396208 › java › null-comparison
null comparison (Beginning Java forum at Coderanch)
Hi Tyler, Compare null values are null do the following instead of using the equals method: if (ipArray[s] == null) //is null if(ipArray[s] != null) // if not null. You can't do: ipArray[s].equals(null) as there is no instance created for the value so there will not be a pointer to the object.
🌐
Codemia
codemia.io › knowledge-hub › path › compare_two_objects_in_java_with_possible_null_values
Compare two objects in Java with possible null values
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises