Java Comparison Operators Explained: ==, !=, <, > and equals() Differences

目次

1. What You Will Learn in This Article (Key Takeaways First)

In Java, comparison operators are fundamental language features used to compare values such as numbers and characters.
However, many beginners struggle when comparing objects like String or Integer, especially when using the == operator incorrectly.

This section summarizes the key points upfront, so you can quickly understand when comparison operators are safe to use—and when they are not.

1.1 Comparison Operators Fall into Two Categories

Java comparison operators can be grouped into two main types:

  • Relational operators (order comparison)
    <, <=, >, >=
  • Equality operators (equality comparison)
    ==, !=

When dealing with primitive types (such as int, double, or char), these operators behave exactly as you would expect.

int a = 10;
int b = 20;

System.out.println(a < b);   // true
System.out.println(a == b);  // false

1.2 Important: == Does NOT Always Compare Values

This is the most common source of confusion in Java.

  • For primitive types, == compares actual values
  • For reference types (objects), == compares whether both variables point to the same object

This difference is critical.

String s1 = new String("Java");
String s2 = new String("Java");

System.out.println(s1 == s2);      // false
System.out.println(s1.equals(s2)); // true

Even though the text looks identical, s1 and s2 are different objects in memory.

👉 Rule of thumb:
If you want to check whether two objects have the same content, use equals().

1.3 Quick Decision Guide (Cheat Sheet)

If you remember only one thing, remember this:

  • Primitive values (int, boolean, char, etc.)
    → Use comparison operators (==, <, >, etc.)
  • Object content comparison (String, Integer, custom objects)
    → Use equals() or Objects.equals()
  • Ordering or sorting (which is larger/smaller)
    → Use compareTo() or a Comparator

Key insight:
== may look simple, but for objects it answers
“Are these the same object?”, not
“Do these have the same value?”

1.4 What You’ll Be Able to Do After Reading This Article

By the end of this article, you will be able to:

  • Use Java comparison operators correctly and safely
  • Avoid common bugs caused by == vs equals()
  • Understand why Integer comparisons sometimes behave inconsistently
  • Choose the right approach when comparing values, objects, or order

In the next section, we’ll start with a complete overview of all Java comparison operators, before diving deeper into common pitfalls and best practices.

2. Java Comparison Operators (Complete List)

In this section, we’ll organize all Java comparison operators and clarify what they can and cannot compare.
The goal is to eliminate ambiguity before diving into more complex cases.

2.1 Comparison Operators Always Return a Boolean

Every comparison operator in Java returns a value of type boolean:

  • true → the condition is satisfied
  • false → the condition is not satisfied

This is why comparison operators are commonly used in if, while, and other control statements.

int x = 5;
int y = 10;

boolean result = x < y;  // true

Comparison operators do not modify values—they only evaluate conditions.

2.2 Relational Operators: <, <=, >, >=

These operators compare order or magnitude.
They are primarily used with numeric types and char.

OperatorMeaning
<less than
<=less than or equal to
>greater than
>=greater than or equal to

Example with numbers

int a = 10;
int b = 20;

System.out.println(a < b);   // true
System.out.println(a >= b);  // false

Example with char

Characters are compared using their Unicode values.

char c1 = 'A';
char c2 = 'B';

System.out.println(c1 < c2); // true

Note:
These operators cannot be used with String. Doing so results in a compile-time error.

2.3 Equality Operators: == and !=

Equality operators check whether two operands are equal or not.

OperatorMeaning
==equal to
!=not equal to

Safe usage with primitive types

int x = 5;
int y = 5;

System.out.println(x == y); // true
System.out.println(x != y); // false

Here, Java compares actual values, which is straightforward and safe.

2.4 Comparing boolean Values

boolean values can also be compared using == and !=.

boolean f1 = true;
boolean f2 = false;

System.out.println(f1 == f2); // false

In real-world code, however, it’s more readable to write:

if (isEnabled) {
    // do something
}

instead of:

if (isEnabled == true) { ... }

2.5 Types That Work Well with Comparison Operators

Safe to use comparison operators directly:

  • int, long, double, float
  • char
  • boolean (only == / !=)

Not safe or not allowed:

  • String
  • Wrapper classes (Integer, Long, etc.)
  • Custom objects

These types require different comparison techniques, which we’ll cover next.

2.6 Key Takeaway from This Section

  • Comparison operators always return true or false
  • They work reliably with primitive types
  • Using them with objects can lead to bugs or compile errors

In the next section, we’ll focus on primitive types, where comparison operators behave exactly as expected.

3. Comparison Operators with Primitive Types (Safe Zone)

Primitive types are the safest and simplest case for comparison operators.
Understanding this section clearly helps you recognize when things start to get tricky.

3.1 What Are Primitive Types?

Primitive types store actual values, not references.

Common examples include:

  • Numeric types: int, long, double, float
  • Character type: char
  • Boolean type: boolean

Because there are no object references involved, comparisons behave predictably.

3.2 Comparing Integers and Long Values

int a = 100;
int b = 100;

System.out.println(a == b); // true
System.out.println(a < b);  // false

Java compares the numeric values directly.

Mixed numeric types

int x = 10;
long y = 10L;

System.out.println(x == y); // true

Java performs automatic type promotion before comparison.

3.3 Comparing Characters (char)

Although char represents a character, Java treats it as a number internally.

char c1 = 'A';
char c2 = 'a';

System.out.println(c1 < c2); // true

This comparison is based on Unicode values, not alphabetical rules in a human language.

3.4 Comparing Boolean Values

boolean flag1 = true;
boolean flag2 = false;

System.out.println(flag1 != flag2); // true

In practice, avoid redundant comparisons:

if (isLoggedIn) { ... }      // preferred
if (isLoggedIn == true) { } // unnecessary

3.5 Floating-Point Comparison Pitfall (double / float)

This is a classic Java pitfall.

double d1 = 0.1 + 0.2;
double d2 = 0.3;

System.out.println(d1 == d2); // may be false

Floating-point numbers are stored with precision limitations.

Recommended approach: use a tolerance (epsilon)

double epsilon = 0.000001;

if (Math.abs(d1 - d2) < epsilon) {
    // treat as equal
}

For financial or high-precision calculations, consider BigDecimal.

3.6 Summary of the Safe Zone

  • Primitive types can be compared directly
  • char comparisons use Unicode values
  • Floating-point equality requires special care
  • Up to this point, comparison operators behave intuitively

Next, we’ll move into the danger zone:
why using == with objects leads to unexpected results.

4. Why Using == with Objects Causes Problems

This is where many Java beginners—and even intermediate developers—run into trouble.
The behavior of == changes once you start working with reference types (objects).

4.1 == Compares Object References, Not Content

For objects, the == operator checks whether both variables point to the same object in memory.

String s1 = new String("Java");
String s2 = new String("Java");

System.out.println(s1 == s2); // false

Even though both strings look identical, they are different objects, so the comparison fails.

4.2 equals() Compares Object Content

The equals() method is designed to compare logical equality, meaning the actual content of objects.

System.out.println(s1.equals(s2)); // true

The String class overrides equals() so that it compares character sequences, not memory addresses.

Golden rule:

  • Same object? → ==
  • Same value/content? → equals()

4.3 Why == Sometimes Works with String Literals

This example confuses many developers:

String a = "Java";
String b = "Java";

System.out.println(a == b); // true

This happens because of the String Pool.

  • String literals are stored in a shared pool
  • Identical literals may reference the same object

However, this behavior is an implementation detail, not something you should rely on.

String x = "Java";
String y = new String("Java");

System.out.println(x == y);      // false
System.out.println(x.equals(y)); // true

👉 Always use equals() for String content comparison.

4.4 Null and equals() — Another Common Pitfall

Calling equals() on a null reference causes a runtime error.

String str = null;
str.equals("Java"); // NullPointerException

Safe pattern 1: Call equals() on the constant

if ("Java".equals(str)) {
    // safe
}

Safe pattern 2: Use Objects.equals()

if (Objects.equals(str, "Java")) {
    // safe and clean
}

4.5 Summary of This Section

  • == compares object references
  • equals() compares content
  • String Pool behavior can hide bugs
  • Always consider null safety

Next, we’ll look at another subtle trap:
comparing wrapper classes like Integer and Long.

5. Comparing Wrapper Classes (Integer, Long, etc.)

Wrapper classes look like numbers, but they are still objects.

5.1 What Are Wrapper Classes?

Wrapper classes allow primitive values to be treated as objects.

PrimitiveWrapper
intInteger
longLong
doubleDouble
booleanBoolean

5.2 Why == Produces Inconsistent Results

Integer a = 100;
Integer b = 100;

System.out.println(a == b); // true
Integer x = 1000;
Integer y = 1000;

System.out.println(x == y); // false

This happens due to Integer caching (typically from -128 to 127).

The result of == depends on internal JVM behavior, not value equality.

5.3 Correct Way to Compare Wrapper Values

Use equals() for value comparison.

System.out.println(x.equals(y)); // true

5.4 Autoboxing and Unboxing Pitfalls

Integer a = 100;
int b = 100;

System.out.println(a == b); // true

This works due to automatic unboxing, but:

  • If a is null → NullPointerException
  • The intent of the code becomes unclear

Explicit comparison is safer.

5.5 Recommended Comparison Patterns

  • Value comparison → equals() / Objects.equals()
  • Null-safe comparison → Objects.equals()
  • Reference comparison → == (rare and intentional)

5.6 Section Summary

  • Wrapper classes are reference types
  • == is unreliable for value comparison
  • Use equals() consistently

Next, let’s focus on null-safe comparison techniques.

6. Null-Safe Comparison Techniques

Null-related bugs are extremely common in Java applications.

6.1 Basic Rules with null

  • null == null → true
  • Calling a method on null → runtime error
  • Relational operators (<, >) with null → compile error

6.2 Dangerous Pattern

str.equals("Java"); // unsafe

6.3 Safe Pattern #1: Constant First

"Java".equals(str);

6.4 Safe Pattern #2: Objects.equals()

Objects.equals(str, "Java");

This handles all null cases internally.

6.5 When to Use Objects.equals()

  • Comparing variables
  • Nullable values
  • Cleaner conditional logic

6.6 Design Tip: Reduce Null Usage

  • Initialize values early
  • Use Optional where appropriate
  • Fewer nulls → simpler comparisons

6.7 Section Summary

  • Never call methods on nullable references
  • Prefer null-safe comparison utilities
  • Design to minimize null usage

Next, we’ll cover ordering comparisons using compareTo().

7. Comparing Order with compareTo()

Comparison operators cannot determine ordering for objects.

7.1 What Is compareTo()?

compareTo() compares order and returns:

  • Negative → less than
  • Zero → equal
  • Positive → greater than

7.2 String Ordering Example

String a = "Apple";
String b = "Banana";

if (a.compareTo(b) < 0) {
    System.out.println("Apple comes first");
}

7.3 Wrapper Classes Also Support compareTo()

Integer x = 10;
Integer y = 20;

System.out.println(x.compareTo(y)); // negative

7.4 equals() vs compareTo()

  • Equality check → equals()
  • Ordering/sorting → compareTo()

7.5 Connection to Sorting

Methods like Collections.sort() rely on compareTo() internally.

7.6 Section Summary

  • Comparison operators can’t compare object order
  • compareTo() is the correct tool
  • Essential for sorting and ordered collections

8. Common Mistakes (Quick Checklist)

8.1 Using == with Strings

str1 == str2
str1.equals(str2)

8.2 Using == with Wrapper Classes

Integer a == b
a.equals(b)

8.3 Comparing Floating-Point Values Directly

a == b
✅ use tolerance or BigDecimal

8.4 Forgetting Null Checks

obj.equals(x)
Objects.equals(obj, x)

8.5 Using < with Objects

str1 < str2
str1.compareTo(str2)

9. Final Summary: How to Choose the Right Comparison

9.1 Decision Guide

  • Primitive types → comparison operators
  • Object contentequals() / Objects.equals()
  • Ordering and sortingcompareTo() / Comparator

9.2 Best Practices

  • Understand what == actually means
  • Always consider null safety
  • Avoid relying on JVM internals

9.3 What to Learn Next

  • Logical operators (&&, ||)
  • if and switch statements
  • Comparator for custom sorting
  • Proper equals() / hashCode() implementation

FAQ

Q1. What is the difference between == and equals() in Java?

== compares references for objects, while equals() compares content.

Q2. Why does == sometimes work with Strings?

Because of the String Pool. This behavior should not be relied upon.

Q3. What is the safest way to compare nullable values?

Use Objects.equals(a, b).

Q4. How do I compare Strings alphabetically?

Use compareTo().

Q5. Are comparison operators enough in Java?

They are sufficient for primitives, but objects require equals() and compareTo().