When ordering objects, why can't you use relational operators, and what do you use instead?
answer
- < and > don't compile on objects (no operator overloading)
- Comparable.compareTo returns negative/zero/positive by sign
- Comparator for external/multiple orderings
- TreeSet/TreeMap use compareTo, so keep it consistent with equals
- Use Integer.compare, not a - b (overflow)
basics
~10 sRelational operators (<, >) only work on numbers, not objects. To order objects you implement Comparable's compareTo (or pass a Comparator) and check whether its result is negative, zero, or positive.
solid answer
~40 sRelational operators are restricted to numeric primitives and char, so they simply don't compile on object types like String or your own classes. Ordering of objects is expressed through the Comparable interface — a class implements compareTo(other), returning a negative number if this is less, zero if equal, and positive if greater. For ordering you don't control or want to vary, you pass a Comparator instead. The contract is strict: compareTo must be a total order — antisymmetric, transitive, and consistent — and it is strongly recommended that compareTo's notion of equality agree with equals (return 0 exactly when equals is true), or sorted collections like TreeSet/TreeMap will behave inconsistently with their general-purpose siblings. Read the result by sign: a.compareTo(b) < 0 means a comes first.
code
java · 9 linesrecord Money(int cents) implements Comparable<Money> {
@Override public int compareTo(Money other) {
return Integer.compare(this.cents, other.cents); // overflow-safe, NOT this.cents - other.cents
}
}
Money a = new Money(150), b = new Money(200);
System.out.println(a.compareTo(b) < 0); // true: a is cheaper
// System.out.println(a < b); // compile error: < not allowed on objectsgo deeper
Knows you cannot use < on objects and that Comparable/compareTo exists.
Reads compareTo by sign and can implement it; knows Comparator for custom orderings.
States the total-order contract, the consistent-with-equals recommendation, and the TreeSet dedup consequence; avoids the subtraction overflow.
Designs ordering APIs, reasons about contract violations causing sort failures, and weighs natural vs supplied ordering and locale/collation concerns.
## Why < and > don't work on objects The relational operators `<`, `<=`, `>`, `>=` are defined only for **numeric primitive types** and `char`. Apply one to a `String`, a `BigDecimal`, a `LocalDate`, or your own class and you get a **compile error** — there is no operator overloading in Java, so the language can't guess what "greater" means for an arbitrary object. ## The replacement: Comparable `java.lang.Comparable<T>` declares one method: ```java int compareTo(T other); ``` It returns an `int` interpreted by **sign**, not value: - **negative** → `this` is *less than* `other` (comes first) - **zero** → they are *equal in ordering* - **positive** → `this` is *greater than* `other` So the relational *idea* becomes a sign check: ```java if (a.compareTo(b) < 0) { /* a comes before b */ } ``` ## Comparator: ordering you supply externally When you can't modify the class, want multiple orderings, or want to reverse, pass a **`Comparator<T>`** to sorts and sorted collections: ```java list.sort(Comparator.comparing(Person::getName).thenComparing(Person::getAge)); ``` `Comparator` has the same negative/zero/positive contract via `compare(a, b)`. ## The ordering contract (must hold) A correct ordering is a **total order**: - **antisymmetric/consistent sign**: `sgn(a.compareTo(b)) == -sgn(b.compareTo(a))` - **transitive**: if `a > b` and `b > c` then `a > c` - **consistent**: equal-ranked elements compare equally to all others Violating these can make sorts throw `IllegalArgumentException: Comparison method violates its general contract` or produce wrong results. ## "Consistent with equals" It is *strongly recommended* that `compareTo` returns 0 exactly when `equals` returns true. Sorted collections (`TreeSet`, `TreeMap`) use **compareTo/compare, not equals**, to decide membership and uniqueness. If the two disagree, a `TreeSet` may treat two `equals`-distinct elements as the same (deduping them) — surprising and a classic bug (e.g. `BigDecimal` `new BigDecimal("1.0")` vs `"1.00"`: equal by compareTo, *not* by equals). ## Don't subtract to compare A common bug is `return a - b;` for ints — it overflows for large/negative values. Use `Integer.compare(a, b)`, which is overflow-safe. ## Why it matters Understanding that ordering is a method contract — not an operator — is what lets you sort domain objects correctly, plug into `TreeMap`/`TreeSet`, and avoid the silent dedup and overflow traps.
- Why is returning a - b from compareTo dangerous?Integer subtraction can overflow for large or negative operands, flipping the sign and violating the ordering contract. Use Integer.compare(a, b) which is overflow-safe.
- What does it mean for compareTo to be inconsistent with equals, and where does it bite?compareTo can return 0 while equals returns false. TreeSet/TreeMap decide uniqueness via compareTo, so such elements get deduped or lost even though equals says they differ — e.g. BigDecimal 1.0 vs 1.00.
saying these in an interview costs you the question
- Trying to write obj1 < obj2 for object ordering
- Returning a - b from compareTo (overflow risk)
- Assuming TreeSet uses equals for uniqueness (it uses compareTo)
- Letting compareTo disagree with equals without realizing the dedup effect