Fundamentals 16 min read

Why Does Objects.equals Sometimes Return False? Uncover Java’s Equality Pitfalls

This article explains why Java's Objects.equals can yield unexpected false results, compares different equality‑checking methods, shows how type mismatches and null values cause pitfalls, and provides practical code examples and solutions for safe object comparison.

macrozheng
macrozheng
macrozheng
Why Does Objects.equals Sometimes Return False? Uncover Java’s Equality Pitfalls

Preface

While reviewing a colleague's code I discovered that using

Objects.equals

to compare two values returned a result different from the expectation, which sparked my interest.

I originally expected the comparison to return true, but it actually returned false.

Having encountered similar pitfalls with

Objects.equals

before, I felt it was necessary to record this issue and share it.

1. The Scene

Assume a requirement: if the currently logged‑in user is the designated system administrator, send an email. The admin has no special flag; its user id is 888 in development, testing, and production.

The implementation looks straightforward:

<code>UserInfo userInfo = CurrentUser.getUserInfo();

if (Objects.isNull(userInfo)) {
    log.info("Please log in first");
    return;
}

if (Objects.equals(userInfo.getId(), 888)) {
    sendEmail(userInfo);
}
</code>

After logging in with the admin account (id=888) and performing the operation, no email was received.

The

UserInfo

class is defined as:

<code>@Data
public class UserInfo {
    private Long id;
    private String name;
    private Integer age;
    private String address;
}
</code>

The problem lies in the type mismatch: the

id

field is

Long

, while the literal

888

is an

int

. Because the two types differ,

Objects.equals

returns false.

2. Methods for Equality Comparison

2.1 Using the == Operator

The fastest way to compare primitive values is the

==

operator.

<code>int a = 1;
int b = 1;
byte c = 1;
Integer d1 = new Integer(1);
Integer d2 = new Integer(1);
System.out.println(a == b); // true
System.out.println(a == c); // true
System.out.println(a == d1); // true
System.out.println(d2 == a); // true
System.out.println(d1 == d2); // false
</code>

For primitive types the

==

operator compares values directly. For wrapper classes,

==

compares object references, which can yield false even when the values are equal.

When an Integer is compared with an int , automatic unboxing occurs, so the values are compared.

Two distinct

Integer

objects (e.g., created with

new

) are not guaranteed to be

==

even if they hold the same value.

Comparing two Integer objects with == checks whether they reference the same memory address.

Integer values between -128 and 127 are cached, so

Integer d3 = 1; Integer d4 = 1;

results in

d3 == d4

being true, while values outside that range (e.g., 128) are not cached, making

d5 == d6

false.

2.2 Using the equals Method

The

==

operator cannot compare the internal data of two distinct objects. For such cases, the

equals

method should be used.

<code>String g = new String("abc");
String h = new String("abc");
System.out.println(g == h); // false
</code>

Although the references differ, the string contents are identical. The

String

class overrides

equals

to compare character arrays element‑by‑element, returning true when the contents match.

<code>String e = "abc";
String f = "abc";
System.out.println(e.equals(f)); // true
</code>

3. NullPointerException

Both

==

and

equals

can throw a

NullPointerException

when one operand is

null

. For example:

<code>int a = 1;
Integer c = null;
System.out.println(a == c); // NullPointerException
</code>

Similarly, invoking

e.equals(f)

when

e

is

null

throws an exception.

The solution is to perform a null check before calling

equals

, or use a utility method such as:

<code>private static boolean equals(String e, String f) {
    if (e == null) {
        return f == null;
    }
    return e.equals(f);
}
</code>

4. Purpose of Objects.equals

The

Objects

class in

java.util

provides helper methods, among which

Objects.equals(Object a, Object b)

is widely used.

<code>public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}
</code>

This method first checks reference equality, then null‑safety, and finally delegates to

a.equals(b)

. It avoids NullPointerExceptions and is convenient for safe comparisons.

5. Pitfalls of Objects.equals

A hidden pitfall appears when the two arguments have different wrapper types. Example:

<code>Integer a = 1;
long b = 1L;
System.out.println(Objects.equals(a, b)); // false
</code>

Even though the numeric values are equal,

Objects.equals

returns false because

Integer.equals

only returns true when the argument is also an

Integer

. The same behavior exists for

Long.equals

,

Byte.equals

,

Short.equals

,

Double.equals

,

Float.equals

,

Boolean.equals

, and

Character.equals

.

When using Objects.equals , ensure that both parameters are of the same type; otherwise equal numeric values may still be considered unequal.

To fix the issue, cast one argument to the other's type before comparison, or simply use the

==

operator for primitive values.

<code>System.out.println(Objects.equals(a, (int) b)); // true
System.out.println(Objects.equals(b, (long) a)); // true
</code>

In summary, while

Objects.equals

is a handy null‑safe comparator, developers must be aware of type‑mismatch pitfalls, especially when dealing with primitive wrapper classes.

JavanullpointerexceptionPitfallsEqualityObjects.equals
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.