[{"data":1,"prerenderedAt":135},["ShallowReactive",2],{"qa-\u002Fjava\u002Fcollections\u002Fcomparable-comparator":3},{"page":4,"siblings":115,"blog":132},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":105,"related":106,"seo":107,"seoDescription":108,"stem":109,"subtopic":110,"topic":111,"topicSlug":112,"updated":113,"__hash__":114},"qa\u002Fjava\u002Fcollections\u002Fcomparable-comparator.md","Comparable Comparator",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","Java","java",{},true,5,"\u002Fjava\u002Fcollections\u002Fcomparable-comparator",[23,28,32,36,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101],{"id":24,"difficulty":25,"q":26,"a":27},"comparable-vs-comparator","easy","What is the difference between Comparable and Comparator?","**`Comparable\u003CT>`** defines a type's **natural ordering** from the inside: the\nclass implements it and supplies a single `compareTo(T other)` method. It lives\nin **`java.lang`**. **`Comparator\u003CT>`** defines an **external, custom ordering**\nin a separate object via `compare(T a, T b)`; it lives in **`java.util`**.\n\n| | `Comparable\u003CT>` | `Comparator\u003CT>` |\n| -- | -- | -- |\n| Package | `java.lang` | `java.util` |\n| Method | `int compareTo(T o)` | `int compare(T a, T b)` |\n| Where | implemented **by** the class | a **separate** object |\n| Orderings | one (the natural one) | as many as you like |\n| Modifies class? | yes | no |\n\nRule of thumb: use **`Comparable`** for the one obvious ordering a type *is*\n(numbers by value, strings alphabetically), and **`Comparator`** for everything\nelse — especially for types you can't edit.\n",{"id":29,"difficulty":25,"q":30,"a":31},"comparable-implementation","How do you make a class sortable with Comparable?","Implement `Comparable\u003CYourType>` and override **`compareTo`** to return a\nnegative int, zero, or a positive int when `this` is less than, equal to, or\ngreater than the argument.\n\n```java\nclass Person implements Comparable\u003CPerson> {\n  String name; int age;\n  @Override public int compareTo(Person other) {\n    return Integer.compare(this.age, other.age); \u002F\u002F natural order = by age\n  }\n}\n```\n\nOnce a type is `Comparable`, it works automatically with `Collections.sort`,\n`Arrays.sort`, `TreeSet`, `TreeMap`, and `Stream.sorted()` **without** a\ncomparator argument. Rule of thumb: parameterize the interface\n(`Comparable\u003CPerson>`), never the raw `Comparable`.\n",{"id":33,"difficulty":14,"q":34,"a":35},"compareto-contract","What is the contract of compareTo \u002F compare?","The return value's **sign** is what matters, not its magnitude: **negative** if\nthe first argument sorts before the second, **zero** if equal, **positive** if\nafter. The relation must be:\n\n- **Antisymmetric** — `sgn(a.compareTo(b)) == -sgn(b.compareTo(a))`.\n- **Transitive** — if `a > b` and `b > c`, then `a > c`.\n- **Consistent** — equal inputs always give equal results.\n\n```java\nInteger.compare(3, 5);   \u002F\u002F negative (any negative int)\nInteger.compare(5, 5);   \u002F\u002F 0\nInteger.compare(7, 2);   \u002F\u002F positive\n```\n\nBreaking the contract (e.g. an ordering that isn't transitive) can make\n`Arrays.sort` throw `IllegalArgumentException: Comparison method violates its\ngeneral contract!`. Rule of thumb: define order, then never break transitivity.\n",{"id":37,"difficulty":38,"q":39,"a":40},"int-overflow-trap","hard","Why is \"return a - b;\" a bad way to implement a comparator?","Subtraction can **overflow**. If `a` is large positive and `b` is large\nnegative, `a - b` wraps past `Integer.MAX_VALUE` and becomes negative — so a\nvalue that should sort *after* sorts *before*, silently corrupting the order.\n\n```java\nint a = Integer.MAX_VALUE, b = -1;\nSystem.out.println(a - b);            \u002F\u002F -2147483648  (wrong sign!)\nSystem.out.println(Integer.compare(a, b)); \u002F\u002F positive (correct)\n```\n\nThe fix is **`Integer.compare(a, b)`** (or `Long.compare`, `Double.compare`),\nwhich is overflow-safe and reads clearly. Rule of thumb: never subtract to\ncompare — always use the `compare` static helpers.\n",{"id":42,"difficulty":14,"q":43,"a":44},"comparator-comparing","How does Comparator.comparing build a comparator from a key?","`Comparator.comparing(keyExtractor)` takes a function that pulls a\n**`Comparable` sort key** out of each element and returns a comparator that\norders by that key — no boilerplate `compare` body needed.\n\n```java\nList\u003CPerson> people = ...;\npeople.sort(Comparator.comparing(Person::getName));   \u002F\u002F by name\npeople.sort(Comparator.comparing(Person::getAge));    \u002F\u002F by age\n```\n\nThe extracted key (`getName`, `getAge`) must itself be `Comparable`, or you pass\na second argument: `comparing(Person::getCity, String.CASE_INSENSITIVE_ORDER)`.\nRule of thumb: prefer `comparing(...)` with a method reference over a hand-written\nlambda — it's shorter and reads like the sort you mean.\n",{"id":46,"difficulty":14,"q":47,"a":48},"thencomparing","How do you sort by multiple fields with thenComparing?","Chain **`thenComparing`** after `comparing`. It acts as a **tie-breaker**: the\nnext comparator is consulted only when the previous one returns zero.\n\n```java\npeople.sort(\n  Comparator.comparing(Person::getLastName)\n            .thenComparing(Person::getFirstName)\n            .thenComparingInt(Person::getAge)   \u002F\u002F primitive, no boxing\n);\n```\n\nYou can chain as many levels as you need; each runs only on ties from the level\nabove. Rule of thumb: list your sort keys in priority order, `comparing` first\nand `thenComparing` for each subsequent tie-breaker.\n",{"id":50,"difficulty":25,"q":51,"a":52},"reversed","How do you reverse a comparator's order?","Call **`.reversed()`** on any comparator to flip its direction, or use\n`Comparator.reverseOrder()` for the reverse of natural ordering.\n\n```java\npeople.sort(Comparator.comparing(Person::getAge).reversed()); \u002F\u002F oldest first\nList\u003CInteger> nums = ...;\nnums.sort(Comparator.reverseOrder());      \u002F\u002F descending naturals\nnums.sort(Collections.reverseOrder());     \u002F\u002F same idea, older API\n```\n\nWatch the **placement** with chains: `reversed()` reverses the **entire**\ncomparator built so far, not just the last `thenComparing`. To reverse only one\nfield, reverse that key: `thenComparing(Person::getAge, reverseOrder())`. Rule of\nthumb: parenthesize your chain so you know exactly what `reversed()` flips.\n",{"id":54,"difficulty":25,"q":55,"a":56},"natural-reverse-order","What do Comparator.naturalOrder and reverseOrder return?","**`Comparator.naturalOrder()`** returns a comparator that uses each element's own\n`compareTo` (its natural ordering); **`reverseOrder()`** returns the inverse.\nBoth work on any `Comparable` type.\n\n```java\nList\u003CString> s = new ArrayList\u003C>(List.of(\"b\", \"a\", \"c\"));\ns.sort(Comparator.naturalOrder());   \u002F\u002F [a, b, c]\ns.sort(Comparator.reverseOrder());   \u002F\u002F [c, b, a]\n```\n\nThey're most useful as **arguments** to other methods — e.g. as the key\ncomparator in `comparing(...)` or the inner comparator of `nullsFirst(...)`.\nRule of thumb: reach for `naturalOrder()`\u002F`reverseOrder()` instead of writing\n`(a, b) -> a.compareTo(b)` by hand.\n",{"id":58,"difficulty":14,"q":59,"a":60},"nulls-first-last","How do you handle null values when sorting?","A plain comparator throws **`NullPointerException`** on `null` elements. Wrap it\nwith **`Comparator.nullsFirst(...)`** or **`nullsLast(...)`** to decide where\nnulls land.\n\n```java\nList\u003CString> s = Arrays.asList(\"b\", null, \"a\");\ns.sort(Comparator.nullsFirst(Comparator.naturalOrder())); \u002F\u002F [null, a, b]\ns.sort(Comparator.nullsLast(Comparator.naturalOrder()));  \u002F\u002F [a, b, null]\n```\n\nIt also guards a **null key** in a chain:\n`comparing(Person::getName, nullsLast(naturalOrder()))`. Rule of thumb: if a\nfield can be `null`, wrap its comparator in `nullsFirst`\u002F`nullsLast` rather than\nhoping the data is clean.\n",{"id":62,"difficulty":14,"q":63,"a":64},"comparingint-boxing","Why use comparingInt \u002F comparingLong \u002F comparingDouble?","The generic `comparing(...)` returns a key of type `Comparable`, which means an\n`int` key gets **autoboxed** to `Integer` on every comparison. The primitive\nspecializations **`comparingInt`**, **`comparingLong`**, and **`comparingDouble`**\ntake a primitive-returning extractor and avoid that boxing.\n\n```java\n\u002F\u002F boxes each age to Integer\npeople.sort(Comparator.comparing(Person::getAge));\n\u002F\u002F no boxing — faster in hot paths\npeople.sort(Comparator.comparingInt(Person::getAge));\n```\n\nSame applies to the chained form: prefer `thenComparingInt`. Rule of thumb: when\nthe sort key is a primitive, use the `comparingInt\u002FLong\u002FDouble` variant.\n",{"id":66,"difficulty":25,"q":67,"a":68},"collections-sort","What is the difference between Collections.sort and List.sort?","Both sort a `List` in place. **`Collections.sort(list)`** is the older static\nhelper; **`list.sort(comparator)`** is a default method added to `List` in Java\n8 and is the modern idiom. Functionally they do the same thing.\n\n```java\nCollections.sort(list);                       \u002F\u002F natural order\nCollections.sort(list, comparator);           \u002F\u002F custom\nlist.sort(null);                              \u002F\u002F null == natural order\nlist.sort(Comparator.comparing(Person::getAge));\n```\n\n`Collections.sort` actually delegates to `list.sort` under the hood. Passing\n`null` as the comparator means \"use natural ordering\" (the elements must be\n`Comparable`). Rule of thumb: prefer `list.sort(...)` — it's the method on the\nobject you already have.\n",{"id":70,"difficulty":25,"q":71,"a":72},"arrays-sort","How does Arrays.sort work with comparators?","`Arrays.sort` sorts an **array**. For an **object** array you can pass a\ncomparator; for **primitive** arrays you cannot (only natural ascending order is\nsupported).\n\n```java\nInteger[] boxed = {3, 1, 2};\nArrays.sort(boxed, Comparator.reverseOrder()); \u002F\u002F [3, 2, 1] — needs Integer[]\n\nint[] prims = {3, 1, 2};\nArrays.sort(prims);                            \u002F\u002F [1, 2, 3] only — no comparator\n```\n\nTo sort primitives descending you must box to `Integer[]`, or sort ascending and\nreverse manually. Rule of thumb: comparators need object arrays; primitive\n`Arrays.sort` is natural-order only.\n",{"id":74,"difficulty":25,"q":75,"a":76},"stream-sorted","How do you sort a stream?","`Stream.sorted()` sorts by **natural ordering** (elements must be `Comparable`);\n`Stream.sorted(comparator)` sorts by a custom order. It's an intermediate\noperation that returns a new, sorted stream.\n\n```java\nList\u003CPerson> byAge = people.stream()\n    .sorted(Comparator.comparingInt(Person::getAge))\n    .collect(Collectors.toList());\n```\n\nUnlike `list.sort`, this does **not** mutate the source — it produces a new\nordering downstream. `sorted()` is also **stateful**: it must buffer all elements\nbefore emitting any. Rule of thumb: use stream `sorted` when you're already in a\npipeline and want a new collection, not an in-place sort.\n",{"id":78,"difficulty":14,"q":79,"a":80},"treemap-treeset-comparator","How do TreeMap and TreeSet use a comparator?","`TreeMap` and `TreeSet` keep elements **sorted**. By default they use the\nelements' natural ordering (`Comparable`), but you can pass a `Comparator` to the\nconstructor to control the order — and to allow non-`Comparable` types.\n\n```java\nTreeSet\u003CString> ci = new TreeSet\u003C>(String.CASE_INSENSITIVE_ORDER);\nci.add(\"Bravo\"); ci.add(\"alpha\");   \u002F\u002F sorted case-insensitively\n\nTreeMap\u003CPerson, String> m =\n    new TreeMap\u003C>(Comparator.comparing(Person::getName));\n```\n\nThe comparator is fixed at construction and used for **every** ordering and\nlookup operation. Rule of thumb: supply a comparator when the natural order isn't\nwhat you want — or when the key type isn't `Comparable` at all.\n",{"id":82,"difficulty":14,"q":83,"a":84},"priorityqueue-comparator","How does a PriorityQueue use a comparator?","A `PriorityQueue` is a **min-heap** by default — `poll()` returns the\n**smallest** element per natural ordering. Pass a comparator to change what\n\"smallest\" means, e.g. to build a max-heap.\n\n```java\nPriorityQueue\u003CInteger> min = new PriorityQueue\u003C>();              \u002F\u002F 1 first\nPriorityQueue\u003CInteger> max =\n    new PriorityQueue\u003C>(Comparator.reverseOrder());              \u002F\u002F largest first\nPriorityQueue\u003CPerson> byAge =\n    new PriorityQueue\u003C>(Comparator.comparingInt(Person::getAge));\n```\n\nThe heap only guarantees the **head** is the min\u002Fmax — iterating the queue does\n**not** yield sorted order. Rule of thumb: pass `reverseOrder()` for a max-heap,\nand only trust `peek`\u002F`poll`, never iteration order.\n",{"id":86,"difficulty":38,"q":87,"a":88},"consistent-with-equals","What does \"consistent with equals\" mean for compareTo?","An ordering is **consistent with equals** when `a.compareTo(b) == 0` exactly\nwhen `a.equals(b)` is true. It's strongly **recommended** but not required — and\nviolating it breaks sorted collections like `TreeSet`\u002F`TreeMap`, which judge\nequality by `compareTo`, not `equals`.\n\n```java\n\u002F\u002F BigDecimal is the classic inconsistency:\nnew BigDecimal(\"1.0\").equals(new BigDecimal(\"1.00\"));     \u002F\u002F false\nnew BigDecimal(\"1.0\").compareTo(new BigDecimal(\"1.00\"));  \u002F\u002F 0  -> \"equal\"\n```\n\nSo a `TreeSet\u003CBigDecimal>` treats `1.0` and `1.00` as the **same** element, while\na `HashSet` treats them as distinct. Rule of thumb: keep `compareTo` consistent\nwith `equals` unless you have a specific reason, and document it when you don't.\n",{"id":90,"difficulty":38,"q":91,"a":92},"treeset-dedup-compareto","Why does TreeSet use compareTo instead of equals to detect duplicates?","A `TreeSet` is backed by a balanced tree, so it locates and de-duplicates\nelements purely by **comparison**: if `compareTo`\u002F`compare` returns **0**, the\nelement is considered a **duplicate** and is rejected — `equals` and `hashCode`\nare never consulted.\n\n```java\n\u002F\u002F comparator looks only at age:\nTreeSet\u003CPerson> set = new TreeSet\u003C>(Comparator.comparingInt(Person::getAge));\nset.add(new Person(\"Ada\", 30));\nset.add(new Person(\"Bob\", 30));   \u002F\u002F NOT added — same age -> compare == 0\nSystem.out.println(set.size());   \u002F\u002F 1\n```\n\nThis surprises people: two objects that aren't `equals` can still collide in a\n`TreeSet` if the comparator rates them equal. Rule of thumb: make the\n`TreeSet`\u002F`TreeMap` comparator total enough that only truly-equal elements\ncompare to 0.\n",{"id":94,"difficulty":14,"q":95,"a":96},"sort-stability","What is a stable sort and which Java sorts are stable?","A **stable** sort preserves the relative order of elements that compare as\n**equal**. This matters when you sort by multiple keys in passes, or want ties to\nkeep their original sequence.\n\n```java\n\u002F\u002F sort by city, then (stably) by name keeps city groups intact\npeople.sort(Comparator.comparing(Person::getName));\npeople.sort(Comparator.comparing(Person::getCity)); \u002F\u002F ties stay name-ordered\n```\n\n`Collections.sort`, `List.sort`, and `Arrays.sort` on **objects** (TimSort) are\n**guaranteed stable**. `Arrays.sort` on **primitives** uses a dual-pivot\nquicksort and is **not** stable (irrelevant for primitives, since equal ints are\nindistinguishable). Rule of thumb: rely on stability only for object sorts.\n",{"id":98,"difficulty":25,"q":99,"a":100},"lambda-vs-method-ref","How do lambdas and method references express comparators?","`Comparator\u003CT>` is a **functional interface** (one abstract method, `compare`),\nso you can write it as a lambda or, more cleanly, build it with the factory\nmethods and method references.\n\n```java\n\u002F\u002F verbose lambda\nComparator\u003CPerson> c1 = (a, b) -> a.getName().compareTo(b.getName());\n\u002F\u002F factory + method reference — preferred\nComparator\u003CPerson> c2 = Comparator.comparing(Person::getName);\n```\n\nThe factory form is shorter, harder to get wrong (no manual `compareTo`), and\ncomposes with `thenComparing`\u002F`reversed`. Rule of thumb: reserve raw `(a, b) ->`\nlambdas for genuinely custom logic; use `Comparator.comparing(...)` for the\ncommon \"sort by a field\" case.\n",{"id":102,"difficulty":14,"q":103,"a":104},"comparator-reuse","Should you store comparators as constants and reuse them?","Comparators are typically **stateless and thread-safe**, so the idiom is to build\none once as a `static final` constant and reuse it everywhere rather than\nre-creating it on every sort.\n\n```java\npublic static final Comparator\u003CPerson> BY_NAME_THEN_AGE =\n    Comparator.comparing(Person::getLastName)\n              .thenComparing(Person::getFirstName)\n              .thenComparingInt(Person::getAge);\n\npeople.sort(BY_NAME_THEN_AGE);\n```\n\nA named constant documents the ordering, avoids rebuilding the chain in hot\nloops, and can be shared across `TreeSet`, `PriorityQueue`, and `sort` calls.\nRule of thumb: name and cache the comparators you use more than once.\n",20,null,{"description":11},"Java Comparable and Comparator interview questions — natural vs custom ordering, compareTo vs compare, comparator chaining and reversal, sorting collections, and consistency with equals.","java\u002Fcollections\u002Fcomparable-comparator","Comparable & Comparator","Collections","collections","2026-06-20","gILDt_5jcrQdvGndx3dEU40Jk25bFoZCd1lxPrI2iDU",[116,120,123,127,131],{"subtopic":117,"path":118,"order":119},"Lists, Maps & Sets","\u002Fjava\u002Fcollections\u002Flist-map-set",1,{"subtopic":121,"path":122,"order":12},"HashMap Internals","\u002Fjava\u002Fcollections\u002Fhashmap-internals",{"subtopic":124,"path":125,"order":126},"Set Implementations","\u002Fjava\u002Fcollections\u002Fset-implementations",3,{"subtopic":128,"path":129,"order":130},"Queue & Deque","\u002Fjava\u002Fcollections\u002Fqueue-deque",4,{"subtopic":110,"path":21,"order":20},{"path":133,"title":134},"\u002Fblog\u002Fjava-comparable-vs-comparator","Java Comparable vs Comparator — Sorting, Chaining & the Pitfalls",1782244116275]