Beginner's Guide To compareto In Java (With Code Examples)

Maaike van Putten
Maaike van Putten
hero image

Comparing numbers in Java is simple. You can just use <, >, or ==.

But what if you need to compare objects, like sorting names alphabetically or ranking players by score? Java doesn’t let you use < or > on objects, so how do you figure out which one comes first?

That’s where compareTo comes in. It’s Java’s built-in method for comparing objects, helping you sort lists, rank values, and organize data the way you want.

But if you’ve never used it before, it might seem a little weird. Why does it return -1, 0, or 1 instead of true or false?

Don’t worry because we’ll cover all that and more, so that by the end of this guide, you’ll not only understand how compareTo works - you’ll be confident using it to compare strings, numbers, and even custom objects. Ready to see it in action?

Let’s go!

Sidenote: If you find that you’re struggling with the content in this guide, or perhaps feel that you could use some more training, or simply want to build some more impressive projects for your portfolio, then check out my Java programming bootcamp:

Learn Java coding

Updated for 2025, you'll learn Java programming fundamentals all the way from complete beginner to advanced skills.

Better still, you’ll be able to reinforce your learning with over 80 exercises and 18 quizzes. This is the only course you need to go from complete programming beginner to being able to get hired as a Backend Developer!

With that out of the way, let’s get into these interview questions!

What is compareTo and how does it work?

At some point in your coding career, you'll need to compare things in Java.

Maybe you're sorting a list, checking if one number is bigger than another, or figuring out if two values are the same. If you're working with numbers like int or double, comparisons are easy:

int a = 5;
int b = 10;

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

But what if you're working with objects like String or Integer?

Unlike numbers, Java doesn't allow direct comparisons using < or > because objects don’t have a built-in way to determine which one is "greater" or "smaller." That’s where compareTocomes in.

Java uses compareTo to decide how objects should be ordered:

  • -1 → The first value comes before the second
  • 0 → The two values are equal
  • 1 → The first value comes after the second

Since sorting isn’t just about knowing whether two values are different - but rather how they should be arranged — Java repeatedly calls compareTo to position elements correctly in a list. This allows it to sort objects automatically, without requiring custom logic each time.

For example

Imagine you’re building a leaderboard for a game. You have a list of players, and you need to rank them based on their scores.

The problem? Java doesn’t automatically know how to order them and so you have to define the logic. Here’s how you can use compareTo to sort players by score:

class Player implements Comparable<Player> {
	String name;
	int score;

	public Player(String name, int score) {
    	this.name = name;
    	this.score = score;
	}

	@Override
	public int compareTo(Player other) {
    	return Integer.compare(other.score, this.score); // Higher scores come first
	}
}

Now, let’s sort a list of players:

import java.util.*;

public class Leaderboard {
	public static void main(String[] args) {
    	List<Player> players = new ArrayList<>();
    	players.add(new Player("Alice", 50));
    	players.add(new Player("Bob", 75));
    	players.add(new Player("Charlie", 60));

    	Collections.sort(players); // Uses compareTo()

    	for (Player p : players) {
        	System.out.println(p.name + ": " + p.score);
    	}
	}
}

Expected output:

Bob: 75
Charlie: 60
Alice: 50

So what’s happening here?

Well, Java calls compareTo on each pair of players:

  1. Comparing Alice (50) and Bob (75)
    • Alice.compareTo(Bob)Integer.compare(75, 50) → returns 1
    • Java moves Bob before Alice
  2. Comparing Charlie (60) and Bob (75)
    • Charlie.compareTo(Bob)Integer.compare(75, 60) → returns 1
    • Java keeps Bob at the top
  3. Comparing Charlie (60) and Alice (50)
    • Charlie.compareTo(Alice)Integer.compare(60, 50) → returns -1
    • Java moves Charlie ahead of Alice

Once all comparisons are made, Java arranges the list based on these return values.

Tl;DR

Every call to compareTo tells Java how to position elements in the list:

  • -1 moves an item up in the list
  • 1 moves it down
  • 0 keeps it in place

Sorting algorithms rely on these return values to organize lists automatically.

Now that you’ve seen how compareTo works with custom objects, let’s see how Java uses it for built-in types like String and Integer.

How does compareTo work with Strings?

You probably compare strings all the time — checking if two names are the same or sorting a list alphabetically. But how does Java actually do it?

Java uses compareTo to compare strings letter by letter based on their Unicode values. That means it follows the same order you’d expect in a dictionary.

For example

public class CompareStrings {
	public static void main(String[] args) {
    	String name1 = "Alice";
    	String name2 = "Bob";

    	int result = name1.compareTo(name2);
    	System.out.println(result);
	}
}

Java looks at "Alice" and "Bob" and checks the first letter of each:

  • 'A' comes before 'B', so "Alice".compareTo("Bob") returns a negative number (-1)
  • If we flipped it ("Bob".compareTo("Alice")), it would return a positive number (1)

Simple enough right? But what if the first letters are the same? Heck, what if the names are almost identical?

For example

Let’s try comparing "Alice" and "Alicia":

public class CompareStrings {
	public static void main(String[] args) {
    	String name1 = "Alice";
    	String name2 = "Alicia";

    	int result = name1.compareTo(name2);
    	System.out.println(result);
	}
}

Since "Alice" and "Alicia" start with the same five letters, Java keeps going until it finds a difference. It gets to 'e' in "Alice" and 'i' in "Alicia", and since 'e' comes before 'i', Java returns -1— meaning "Alice" comes first.

However, if the words were exactly the same ("Alice".compareTo("Alice")), compareTo would return 0, because there’s nothing to compare!

So the next time you sort a list of names, remember — Java is just running compareTo behind the scenes, checking letters one by one.

Speaking of sorting, numbers work in a similar way. Let’s check that out next.

Does compareTo work the same way for numbers?

Since compareTo sorts Strings alphabetically by checking each letter, you might wonder if it does the same thing for numbers?

The answer is yes, but it’s much simpler. Instead of checking letters, Java compares the actual values:

Integer num1 = 5;
Integer num2 = 10;

System.out.println(num1.compareTo(num2)); // -1

Just like before:

  • If the first number is smaller, compareTo returns -1
  • If they’re equal, it returns 0
  • If the first number is larger, it returns 1

So, why not just use < and >?

If you’re working with primitive types you can just use < and >. But with objects like Integer and Double, Java doesn’t allow direct comparisons:

Integer num1 = 5;
Integer num2 = 10;

System.out.println(num1 < num2); // ERROR

Since Integer is an object, you have to use compareTo instead.

(Most of the time, you won’t need it — but when sorting numbers in a list or working with BigDecimal, compareTo is essential).

Now that we’ve seen how compareTo works with Strings and numbers, let’s talk about sorting custom objects. Java already knows how to compare built-in types, but what happens when you need to sort objects of your own?

How to make your class comparable

Unlike built-in types like String or Integer, Java doesn’t know how to compare custom objects— unless you explicitly tell it how. That’s where Comparable<T> comes in.

To make your objects sortable, your class needs to implement the Comparable<T> interface and define a compareTo method.

class Person implements Comparable<Person> {
	String name;
	int age;

	public Person(String name, int age) {
    	this.name = name;
    	this.age = age;
	}

	@Override
	public int compareTo(Person other) {
    	return Integer.compare(this.age, other.age); // Sort by age
	}
}

Now, Java understands how to compare two Person objects based on their age. This allows them to be sorted automatically using Collections.sort():

List<Person> people = new ArrayList<>();
people.add(new Person("Charlie", 20));
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 30));

Collections.sort(people); // Works because Person implements Comparable<Person>

TL;DR

Why does Comparable<T> matter?

  • Without it, Java won’t know how to sort custom objects
  • With it, you can use Collections.sort() without extra code
  • It makes your objects reusable—whenever sorting is needed, compareTo does the work automatically

Now that we know how to make a class comparable, let’s apply it in a real-world scenario.

How to use compareTo with custom objects

Let’s say you’re building a user management system, and you want to store a list of users sorted by age.

The problem? Java doesn’t automatically know how to compare two Person objects. Unlike numbers, objects don’t have a built-in way to determine which one is "greater" or "smaller."

That’s why Java requires you to explicitly define how objects should be compared using compareTo. But what should we compare? Names? Ages? There’s no default answer — you decide what makes sense for your use case.

Here’s how to define sorting logic for a Person class by age:

class Person implements Comparable<Person> {
	String name;
	int age;

	public Person(String name, int age) {
    	this.name = name;
    	this.age = age;
	}

	@Override
	public int compareTo(Person other) {
    	return Integer.compare(this.age, other.age); // Sort by age
	}
}

Now, Java understands how to compare two Person objects based on their age. This allows them to be sorted automatically using Collections.sort():

List<Person> people = new ArrayList<>();
people.add(new Person("Charlie", 20));
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 30));

Collections.sort(people); // Works because Person implements Comparable<Person>

Without compareTo, Java wouldn’t know how to order custom objects in a list. But how does this actually work behind the scenes? Let’s break it down and see how to make objects sortable.

How to make objects sortable with compareTo

Unlike built-in types like String or Integer, Java has no built-in way to compare custom objects — unless you define the rules yourself.

And so to make your objects sortable, you need to tell Java how to compare them by implementing the Comparable<T> interface and define a compareTo method.

For example

Here’s how to define sorting logic for a Person class by age:

class Person implements Comparable<Person> {
	String name;
	int age;

	public Person(String name, int age) {
    	this.name = name;
    	this.age = age;
	}

	@Override
	public int compareTo(Person other) {
    	return Integer.compare(this.age, other.age);
	}
}

Now, Java understands how to compare two Person objects based on their age. This allows them to be sorted automatically using Collections.sort().

Let’s test this:

public class ComparePeople {
	public static void main(String[] args) {
    	Person alice = new Person("Alice", 25);
    	Person bob = new Person("Bob", 30);

    	System.out.println(alice.compareTo(bob)); // -1 (Alice is younger than Bob)
    	System.out.println(bob.compareTo(alice)); // 1  (Bob is older than Alice)
	}
}

Since compareTo defines the ranking, Java can now sort Person objects automatically.

import java.util.*;

public class ComparePeople {
	public static void main(String[] args) {
    	List<Person> people = new ArrayList<>();
    	people.add(new Person("Charlie", 20));
    	people.add(new Person("Alice", 25));
    	people.add(new Person("Bob", 30));

    	Collections.sort(people); // Sorts by age because of compareTo()

    	for (Person person : people) {
        	System.out.println(person.name + " (" + person.age + ")");
    	}
	}
}

Output:

Charlie (20)  
Alice (25)  
Bob (30)  

Since compareTo defines how Person objects should be ranked, Java can automatically sort them in the correct order.

Why does this matter?

Without compareTo, sorting custom objects would be a hassle. You’d have to manually write sorting logic every time you needed to order a list.

Think about other objects you might need to compare:

  • Sorting Product objects by price
  • Ordering Employee records by salary
  • Ranking Player objects by score

Instead of re-writing sorting logic every time, implementing compareTo makes objects sortable everywhere, saving time and keeping your code clean.

Handy right?

But of course there is a catch in that small mistakes in how you implement compareTo can lead to weird sorting behavior, hard-to-debug errors, or even crashes.

So, before you start using it everywhere, let’s go over some common pitfalls and best practices to make sure your comparisons are rock solid.

Common mistakes and best practices

Mistake #1: Forgetting to handle equality (0 return value)

Imagine you’re sorting a list of Person objects by age. You write a compareTo method like this:

@Override
public int compareTo(Person other) {
	return this.age - other.age;
}

At first glance, it looks fine because it returns a negative number if this.age is smaller and a positive number if it's larger.

Why is this a problem?

If two objects have the same age, this.age - other.age results in 0, which means they are equal. That’s not a problem by itself, but this approach has two major issues:

  1. Unstable sorting behavior – If your sorting algorithm depends on strict ordering, elements with the same value might stay out of order in different runs
  2. Integer overflow risk – If this.age is a very large number and other.age is a very small number, subtracting them could cause integer overflow, leading to unexpected results

How to fix it

Instead of subtracting values, use Integer.compare(), which is built to handle comparisons safely.

@Override
public int compareTo(Person other) {
	return Integer.compare(this.age, other.age);
}

Why is this better?

  • It correctly handles equal values (0 return)
  • It avoids integer overflow for large or small numbers

Mistake #2: Flipping the comparison logic

Beginners sometimes write compareTo backward, which completely reverses the sorting order.

Incorrect approach:

@Override
public int compareTo(Person other) {
	if (this.age < other.age) return 1;  // Wrong: should return -1
	if (this.age > other.age) return -1; // Wrong: should return 1
	return 0;
}

Why does this happen?

It’s easy to assume that higher numbers should come first and accidentally flip the logic. But compareTo follows a strict convention:

  • Negative number (-1) → this is smaller than other
  • Zero (0) → They are equal
  • Positive number (1) → this is greater than other

How to fix it

Always follow standard ordering:

@Override
public int compareTo(Person other) {
	return Integer.compare(this.age, other.age);
}

Need to reverse the order? Instead of flipping compareTo, sort with Collections.reverseOrder():

Collections.sort(people, Collections.reverseOrder());

Mistake #3: Forgetting to implement Comparable<T>

Sometimes, developers write a compareTo method but forget to declare that the class implements Comparable<T>:

Incorrect approach:

class Person {
	String name;
	int age;

	public int compareTo(Person other) {
    	return Integer.compare(this.age, other.age);
	}
}

Why is this a problem?

  • Java won’t recognize compareTo as an official method
  • The class won’t work with Collections.sort()
  • You’ll get a compile-time error when trying to use compareTo()

How to fix it

Always declare implements Comparable<T>:

class Person implements Comparable<Person> {
	String name;
	int age;

	@Override
	public int compareTo(Person other) {
    	return Integer.compare(this.age, other.age);
	}
}

This tells Java that Person objects can be compared, allowing sorting and comparisons to work properly.

Mistake #4: Comparing multiple fields incorrectly

Sometimes, you need to compare objects by more than one field. For example, if two people are the same age, you might want to sort them alphabetically by name.

Incorrect approach:

@Override
public int compareTo(Person other) {
	return this.age - other.age + this.name.compareTo(other.name);
}

Why is this a problem?

  1. Incorrect ordering – Since this.age - other.age produces a single number, adding the name comparison could cause wrong results
  2. Integer overflow – Just like before, this.age - other.age can cause overflow issues

How to fix it

Instead of adding values, compare the fields separately:

@Override
public int compareTo(Person other) {
	int ageComparison = Integer.compare(this.age, other.age);
	if (ageComparison == 0) {
    	return this.name.compareTo(other.name); // Compare by name if ages are the same
	}
	return ageComparison;
}
@Override
public int compareTo(Person other) {
	int ageComparison = Integer.compare(this.age, other.age);
	if (ageComparison == 0) {
    	return this.name.compareTo(other.name); // Compare by name if ages are the same
	}
	return ageComparison;
}

Mistake #5: Not making compareTo consistent with equals()

If two objects are considered equal by .equals(), they must return 0 in compareTo. Otherwise, sorting and collections won’t behave correctly.

Incorrect approach:

@Override
public boolean equals(Object obj) {
	if (this == obj) return true;
	if (!(obj instanceof Person)) return false;
	Person other = (Person) obj;
	return this.name.equals(other.name);
}

@Override
public int compareTo(Person other) {
	return Integer.compare(this.age, other.age); // Ignores name comparison
}

Why is this a problem?

  • .equals() says two people are equal if their names match, but compareTo only checks age
  • This means a person with the same name but different ages might appear twice in a sorted set, violating the contract of sorted collections

How to fix it

Ensure compareTo respects equality rules:

@Override
public int compareTo(Person other) {
	int nameComparison = this.name.compareTo(other.name);
	if (nameComparison == 0) {
    	return Integer.compare(this.age, other.age);
	}
	return nameComparison;
}

@Override
public boolean equals(Object obj) {
	if (this == obj) return true;
	if (!(obj instanceof Person)) return false;
	Person other = (Person) obj;
	return this.name.equals(other.name) && this.age == other.age;
}

TL;DR: Best practices for using compareTo

To avoid common pitfalls, follow these best practices:

  1. Use Integer.compare() instead of this.age - other.age to prevent integer overflow
  2. Keep compareTo consistent with equals() to avoid sorting inconsistencies
  3. Only compare multiple fields when necessary (e.g., if two objects are identical by the primary field)
  4. Use Comparator when you need multiple sorting options instead of modifying compareTo()

By following these, you’ll ensure that your comparisons are accurate, stable, and efficient.

Time to put compareTo into practice

Now that you understand how compareTo works, the best way to master it is to try it yourself. Create your own classes, implement Comparable<T>, and experiment with sorting different objects.

Test edge cases, tweak comparison logic, and see how small changes affect sorting. The more you practice, the more intuitive it will become.

So go ahead — write some code, sort some objects, and make Java do the work for you!

P.S.

Remember, if you want to fast-track your Java knowledge and get as much hands-on practice as possible, then check out my Java programming bootcamp:

Learn Java coding

Updated for 2025, you'll learn Java programming fundamentals all the way from complete beginner to advanced skills.

Better still, you’ll be able to reinforce your learning with over 80 exercises and 18 quizzes. This is the only course you need to go from complete programming beginner to being able to get hired as a Backend Developer!

Plus, once you join, you'll have the opportunity to ask questions in our private Discord community from me, other students and working DevOps professionals.


More from Zero To Mastery

How To Ace The Coding Interview preview
How To Ace The Coding Interview

Are you ready to apply for & land a coding job but not sure how? This coding interview guide will show you how it works, how to study, what to learn & more!

How To Get A Job In Tech & Succeed When You’re There! preview
Popular
How To Get A Job In Tech & Succeed When You’re There!

Are you looking to get a job in tech? These are the steps (+ tips, tricks, and resources) from a Senior Developer to get hired in tech with zero experience!

How to Get More Interviews, More Job Offers, and Even a Raise preview
How to Get More Interviews, More Job Offers, and Even a Raise

This is Part 3 of a 3 part series on how I taught myself programming, and ended up with multiple job offers in less than 6 months!