Question
I want to sort an ArrayList of custom Java objects by one of their properties, which is a Date returned by getStartDate().
I have read about sorting ArrayList objects using a Comparator, but many examples use compareTo(), which confused me because I thought that method was mainly associated with types like String.
Usually, I compare two dates like this:
item1.getStartDate().before(item2.getStartDate())
So I was wondering whether I could create a comparator like this:
public class CustomComparator {
public boolean compare(Object object1, Object object2) {
return object1.getStartDate().before(object2.getStartDate());
}
}
public class RandomName {
// ...
Collections.sort(Database.arrayList, new CustomComparator());
// ...
}
What is the correct way to sort an ArrayList of custom objects by a Date field in Java?
Short Answer
By the end of this page, you will understand how sorting works in Java for custom objects, why Comparator uses an int-returning compare() method instead of a boolean, and how to sort an ArrayList by a Date property safely and clearly.
Concept
In Java, sorting works by asking one question repeatedly: which of these two items should come first?
For custom objects, Java cannot guess the correct order unless you tell it how to compare them. That is where a Comparator comes in.
A Comparator<T> is an object that defines sorting rules for type T. Its compare(T a, T b) method must return:
- a negative number if
ashould come beforeb - 0 if they are equal for sorting purposes
- a positive number if
ashould come afterb
This is why returning boolean is incorrect. Sorting needs more than just true/false. It needs to know whether one item is less than, equal to, or greater than another.
compareTo() is related, but it is not only for String. Many Java classes implement Comparable, including String, Integer, and Date. For example, Date already has a compareTo() method.
That means when comparing two Date values, you can write:
item1.getStartDate().compareTo(item2.getStartDate())
This works well inside a comparator.
Why this matters in real programming:
- sorting events by date
- ordering messages by timestamp
- showing tasks by deadline
- listing logs from oldest to newest
- presenting records in user-friendly order
Without a correct comparator, sorting custom objects will either fail to compile or produce incorrect results.
Mental Model
Think of sorting like arranging index cards on a desk.
Each card is a custom object. Java picks up two cards at a time and asks your comparator:
- Should card A go before card B?
- Should card B go before card A?
- Or are they equal in order?
A boolean answer is too limited because it only gives part of the story. Java needs a full ranking answer:
- negative = A first
- zero = same position
- positive = B first
So a comparator is like a sorting rulebook that explains how to order your objects based on one property, such as a start date.
Syntax and Examples
Basic comparator syntax
import java.util.Comparator;
public class CustomComparator implements Comparator<MyItem> {
@Override
public int compare(MyItem item1, MyItem item2) {
return item1.getStartDate().compareTo(item2.getStartDate());
}
}
Then use it like this:
Collections.sort(myList, new CustomComparator());
Complete example
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
class Event {
private String name;
private Date startDate;
public Event(String name, Date startDate) {
this.name = name;
this.startDate = startDate;
}
public String getName() {
return name;
}
public Date getStartDate() {
return startDate;
}
@Override
public String toString() {
return name + " - " + startDate;
}
}
class EventDateComparator implements Comparator<Event> {
@Override
public int compare(Event e1, Event e2) {
return e1.getStartDate().compareTo(e2.getStartDate());
}
}
public class Main {
public static void main(String[] args) {
ArrayList<Event> events = new ArrayList<>();
events.add(new Event("Meeting", new Date(124, 5, 10)));
events.add(new Event("Workshop", new Date(124, 4, 20)));
events.add(new Event("Launch", new Date(124, 6, 1)));
Collections.sort(events, new EventDateComparator());
for (Event event : events) {
System.out.println(event);
}
}
}
Simpler modern style
If you are using Java 8+, you can write:
events.sort(Comparator.comparing(Event::getStartDate));
This is shorter and commonly used in modern Java code.
Descending order
events.sort(Comparator.comparing(Event::getStartDate).reversed());
This sorts from newest to oldest.
Step by Step Execution
Consider this code:
ArrayList<Event> events = new ArrayList<>();
events.add(new Event("A", new Date(124, 4, 20)));
events.add(new Event("B", new Date(124, 4, 18)));
events.add(new Event("C", new Date(124, 4, 25)));
events.sort(Comparator.comparing(Event::getStartDate));
What happens step by step
- Java stores three
Eventobjects in the list. events.sort(...)starts the sorting process.- Java compares pairs of
Eventobjects. - For each comparison, it calls
getStartDate()on both objects. - The comparator compares the two
Dateobjects. - If the first date is earlier, it returns a negative value.
- If the dates are the same, it returns
0. - If the first date is later, it returns a positive value.
- Java rearranges the list based on those results.
- The final order becomes:
B
A
C
because May 18 comes before May 20, and May 20 comes before May 25.
Small trace
Suppose Java compares A and B:
A.getStartDate().compareTo(B.getStartDate())
A= May 20B= May 18- result is positive
- so
Bshould come beforeA
Then Java compares A and C:
A= May 20C= May 25- result is negative
- so
Ashould stay beforeC
Real World Use Cases
Sorting custom objects by a property is extremely common.
Examples
- Calendar apps: sort events by start date
- Task managers: sort tasks by due date
- E-commerce systems: sort orders by creation time
- Messaging apps: sort conversations by latest message date
- Logging tools: sort log entries by timestamp
- Booking systems: sort reservations by check-in date
Why comparators are useful
A single object can be sorted in different ways depending on the feature:
- by date
- by name
- by priority
- by price
Using a Comparator lets you define different sorting rules without changing the class itself.
Real Codebase Usage
In real projects, developers often use comparators in a few common patterns.
1. Sorting by one field
users.sort(Comparator.comparing(User::getCreatedAt));
2. Sorting by multiple fields
If two dates are the same, sort by name:
events.sort(
Comparator.comparing(Event::getStartDate)
.thenComparing(Event::getName)
);
3. Handling null values safely
If some dates may be null:
events.sort(
Comparator.comparing(Event::getStartDate, Comparator.nullsLast(Date::compareTo))
);
4. Early validation before sorting
Developers often validate data before sorting:
if (events == null || events.isEmpty()) {
return;
}
events.sort(Comparator.comparing(Event::getStartDate));
5. Keeping comparison logic reusable
A comparator may be stored as a constant:
public static final Comparator<Event> BY_START_DATE =
Comparator.comparing(Event::getStartDate);
This makes sorting rules easier to reuse across services, controllers, and tests.
Common Mistakes
1. Returning boolean from compare()
This is incorrect:
public boolean compare(Object object1, Object object2) {
return object1.getStartDate().before(object2.getStartDate());
}
Why it is wrong:
Comparator.compare()must returnint- sorting needs three outcomes, not just true/false
2. Not implementing Comparator<T>
Broken example:
public class CustomComparator {
public int compare(MyItem a, MyItem b) {
return a.getStartDate().compareTo(b.getStartDate());
}
}
This defines a method, but the class does not actually implement Comparator<MyItem>.
Correct version:
public class CustomComparator implements Comparator<MyItem> {
@Override
public int compare(MyItem a, MyItem b) {
return a.getStartDate().compareTo(b.getStartDate());
}
}
3. Using raw Object types instead of generics
Broken style:
public int compare(Object a, Object b)
Problems:
- loses type safety
- requires casting
- makes code harder to read
Better:
public int compare(Event a, Event b)
4. Forgetting parentheses when creating the comparator
Broken:
Collections.sort(events, new CustomComparator);
Correct:
Collections.sort(events, new CustomComparator());
5. Ignoring null dates
If getStartDate() can return null, this may fail:
return a.getStartDate().compareTo(b.getStartDate());
Safer version:
return Comparator.nullsLast(Date::compareTo)
.compare(a.getStartDate(), b.getStartDate());
6. Confusing Comparator with Comparable
Comparable= the class defines its own default orderingComparator= external sorting rule
If you only need one natural order for the class, Comparable may make sense.
If you need multiple sorting rules, use Comparator.
Comparisons
Comparator vs Comparable
| Feature | Comparator | Comparable |
|---|---|---|
| Where sorting logic lives | Outside the class | Inside the class |
| Method | compare(a, b) | compareTo(other) |
| Return type | int | int |
| Good for multiple sort orders | Yes | No |
| Good for natural/default order | Sometimes | Yes |
before() vs compareTo() for Date
| Approach | Returns | Best use |
|---|---|---|
date1.before(date2) | boolean | Simple yes/no check |
date1.compareTo(date2) | int | Sorting and ordering |
Old style vs modern style
| Style | Example | Notes |
|---|---|---|
| Separate comparator class | new EventDateComparator() | Clear and reusable |
| Anonymous class | new Comparator<Event>() { ... } | Older Java style |
| Lambda / method reference | Comparator.comparing(Event::getStartDate) | Short and common in Java 8+ |
Collections.sort() vs List.sort()
| Method | Example | Notes |
|---|---|---|
Collections.sort(list, comparator) | Classic approach | Works well and is widely seen |
list.sort(comparator) | Modern approach | Shorter and preferred in newer code |
Cheat Sheet
Quick rules
- Use
Comparator<T>to sort custom objects. compare(T a, T b)must return anint.- Return:
- negative if
acomes first 0if equal- positive if
bcomes first
- negative if
Datealready implementsComparable<Date>.- For dates, use
date1.compareTo(date2)inside the comparator.
Common syntax
Comparator class
class EventDateComparator implements Comparator<Event> {
@Override
public int compare(Event e1, Event e2) {
return e1.getStartDate().compareTo(e2.getStartDate());
}
}
Sort with Collections.sort
Collections.sort(events, new EventDateComparator());
Sort with List.sort
events.sort(Comparator.comparing(Event::getStartDate));
Descending order
events.sort(Comparator.comparing(Event::getStartDate).reversed());
Handle null dates
events.sort(
Comparator.comparing(Event::getStartDate, Comparator.nullsLast(Date::compareTo))
);
Remember
before()is for true/false checkscompareTo()is for sorting- prefer generics over
Object - include
()when creating a new comparator object
FAQ
Can I sort custom objects in Java without changing the class?
Yes. Use a Comparator when you want to define sorting outside the class.
Why does Comparator.compare() return int instead of boolean?
Because sorting needs to know whether one item is less than, equal to, or greater than another.
Is compareTo() only for String?
No. Many Java classes implement Comparable, including String, Integer, and Date.
How do I sort by a Date field in Java?
Use a comparator that compares the date values, such as:
Comparator.comparing(MyClass::getStartDate)
What if two objects have the same date?
The comparator returns 0 for that comparison. You can add a second rule with thenComparing() if needed.
Should I use Collections.sort() or list.sort()?
Both work. list.sort() is the more modern and shorter style.
What happens if a date is null?
A normal comparison may throw a NullPointerException. Use Comparator.nullsFirst() or Comparator.nullsLast().
When should I use Comparable instead of Comparator?
Use Comparable when the class has one natural default order. Use Comparator when you want flexible or multiple sorting rules.
Mini Project
Description
Create a small Java program that manages a list of events and sorts them by their start date. This project demonstrates how to define custom objects, store them in an ArrayList, and order them using a comparator.
Goal
Build a program that prints events in chronological order based on a Date property.
Requirements
- Create an
Eventclass withnameandstartDatefields. - Add at least four
Eventobjects to anArrayList. - Sort the list by
startDatefrom earliest to latest. - Print the sorted events to the console.
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.