← Skill tree CS Skill Tree 0 CSCD211

Arrays.sort with a Comparator

Textbook: BJP (Reges and Stepp)

Before You Start

Check each box you can do from memory. A box you cannot check yet is not a problem; it points you to a quick refresher, not a grade.

Not sure? Take the 60-second self-check.

1. Return type. What does Arrays.sort(arr, cmp) return?

Check

void. The method mutates the array in place and returns nothing.

2. Primitive vs. reference. Can you pass a Comparator<int> to Arrays.sort on an int[]?

Check

No. Java has no generic type Comparator<int>. The Arrays.sort(int[], Comparator) overload does not exist. To sort a primitive array with a custom comparator, convert to Integer[] first.

3. Stability. After Arrays.sort(players, byTeam) with a comparator that returns 0 for two players on the same team, what is the relative order of those two players?

Check

Their original relative order is preserved. Arrays.sort for object arrays uses TimSort, which is a stable sort: equal elements maintain their original order.


Try This First

Predict what the variable sorted holds after this code runs:

Player[] players = loadRoster();
Player[] sorted = Arrays.sort(players, new TeamComparator());
Check

The code does not compile. Arrays.sort returns void; the result cannot be assigned. The correct form is:

Player[] players = loadRoster();
Arrays.sort(players, new TeamComparator());
// players is now sorted in place; use players directly

What You Need To Walk In With

The Insight: Arrays.sort is not a function that produces a sorted copy. It is a command that reorders the existing array in place. After the call, the original array reference still points to the same array object, but the elements are in a different order. There is no return value to capture, and there is no new array.

This pattern holds consistently across Java: every mutating sort in the standard library (Arrays.sort, Collections.sort, list.sort) returns void. The convention is that a method either modifies its argument OR returns a new object, not both. Once you recognize this, writing the correct call and avoiding the assignment mistake becomes automatic. You can: write a single-line Arrays.sort call with any Comparator, predict that the array is modified in place and no value is returned, produce a sorted copy with clone() when the original must be preserved, and identify which exception each failure condition throws.


How It Works

The method signature

From the Java 25 Arrays API:

public static <T> void sort(T[] a, Comparator<? super T> c)

Key points:

The F19 Lab 1 calls

// F19.Lab1.CSCD211Lab1.java cases 4, 5, 6
Arrays.sort(nflPlayers, new TeamComparator());
Arrays.sort(nflPlayers, new PositionComparator());
Arrays.sort(nflPlayers, new GamesPlayedComparator());

Each call reorders nflPlayers in place. The array holds the same 32 Player objects throughout; only their positions in the array change.

Producing a sorted copy

If the original order must be preserved, clone before sorting:

Player[] byTeam = nflPlayers.clone();
Arrays.sort(byTeam, new TeamComparator());
// nflPlayers is unchanged; byTeam is sorted

Primitive arrays and the absence of a Comparator overload

Arrays.sort(int[]) sorts ascending using the built-in numeric ordering. There is no Arrays.sort(int[], Comparator<int>) because Comparator<int> is not a valid Java type (Java generics do not work with primitive types). To sort a primitive array in a custom order, the only standard-library options are:

  1. Box to Integer[] and use Arrays.sort(Integer[], Comparator<Integer>).
  2. Sort ascending and then reverse the array manually.

Worked Example: Predict Then Check

Player[] players = { pC, pA, pB };  // players in arbitrary order
System.out.println("Before: " + Arrays.toString(players));

Arrays.sort(players, new TeamComparator());
System.out.println("After:  " + Arrays.toString(players));

// pC.team = "Bears", pA.team = "Aces", pB.team = "Bears"

Predict: (a) what players contains before the sort, (b) what it contains after, (c) what value Arrays.sort returns.

Reasoning

Before: [pC, pA, pB] in the order given at construction.

TeamComparator orders by team name: "Aces" < "Bears". pA (Aces) comes first. pC and pB both have "Bears" and compare equal; their original relative order (C before B) is preserved by TimSort’s stability.

Arrays.sort returns void.

Show answer

Before: [pC, pA, pB]

After: [pA, pC, pB] (Aces first, then Bears in original relative order)

Return value: none (void).


Quick check

Check your understanding

Given this code, what does the variable result hold after the call completes? Player[] roster = loadRoster(); Player[] result = Arrays.sort(roster, new TeamComparator());

Tier 1 · BJP (Reges and Stepp), Ch 13


Common Misconceptions

Misconception 1: expecting Arrays.sort to return the sorted array

Wrong mental model:Player[] sorted = Arrays.sort(players, cmp); stores the sorted result.”

Why it breaks: Arrays.sort returns void. The assignment is a compile error: “incompatible types: void cannot be converted to Player[]”.

How to correct: Sort in place and use the original reference:

Arrays.sort(players, cmp);
// players is now sorted; use players

If a sorted copy is needed:

Player[] sorted = players.clone();
Arrays.sort(sorted, cmp);

Quick check

Check your understanding

A student needs the original roster preserved while also having a sorted copy. Which of the following achieves that correctly?

Tier 2 · BJP (Reges and Stepp), Ch 13


Misconception 2: sorting a primitive array with a Comparator

Wrong mental model:Arrays.sort(intArr, (a, b) -> b - a) sorts int[] descending.”

Why it breaks: Arrays.sort has no overload that accepts a Comparator for int[]. The compiler reports “no suitable method found for sort(int[], (a, b) -> ...)”. Java generics cannot be parameterized with primitive types.

How to correct for descending int[]:

// Option 1: box to Integer[] first
Integer[] boxed = Arrays.stream(intArr).boxed().toArray(Integer[]::new);
Arrays.sort(boxed, Comparator.reverseOrder());

// Option 2: sort ascending then reverse in-place (only for fully reversing)
Arrays.sort(intArr);
for (int i = 0, j = intArr.length - 1; i < j; i++, j--) {
    int tmp = intArr[i]; intArr[i] = intArr[j]; intArr[j] = tmp;
}

Misconception 3: assuming Arrays.sort handles null elements gracefully

Wrong mental model: “If the array has some null elements, Arrays.sort will put them at the end or skip them.”

Why it breaks: Arrays.sort calls the comparator on every pair. If the comparator dereferences a null argument (which the standard coding pattern requires a check for), the call throws NullPointerException. Arrays.sort does not filter nulls.

How to correct: Either remove nulls before sorting, or use a null-tolerant wrapper:

Arrays.sort(players, Comparator.nullsLast(new TeamComparator()));

Comparator.nullsLast(cmp) places nulls after all non-null elements and delegates non-null pairs to cmp. reversed, nullsFirst, and nullsLast covers this wrapper in detail.


Formal Definition and Interface Contract

From the Java 25 Arrays API:

Sorts the specified array of objects according to the order induced by the specified comparator. All elements in the array must be mutually comparable using the specified comparator (that is, c.compare(e1, e2) must not throw a ClassCastException for any elements e1 and e2 in the array).

This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.

Throws: IllegalArgumentException if the comparator is found to violate the Comparator contract.

Runtime exception summary:

Condition Exception
a is null NullPointerException
c is null and array has >1 element NullPointerException
An array element is null and comparator dereferences it NullPointerException
Comparator violates transitivity IllegalArgumentException

Mental Model

Think of Arrays.sort as an in-place rearrangement command, not a query. It is like telling a group of people standing in a line “arrange yourselves by height.” After the command, the line is reordered; no new line is created. The line (the array) is the same physical structure, but the positions are different. If you want to keep the original line intact, you need to copy the line first and then rearrange the copy.


Connections

Within CSCD 210/211: The F19 Lab 1 main class calls Arrays.sort three times, illustrated in Instantiating a Comparator and Passing It to Arrays.sort. This lesson formally defines what that call does, what it returns, and what can go wrong.

Looking back: Instantiating a Comparator and Passing It to Arrays.sort covered how to pass a named comparator to Arrays.sort. This lesson covers the contract of that call.

Looking ahead: list.sort (and Collections.sort) with a Comparator covers list.sort(cmp) and Collections.sort(list, cmp) for List<T>, which have the same stability guarantee but operate on a list rather than an array.


Go Deeper (optional)

Nothing here is required to write correct, working Java. Read on only if a connection pulls you in.

The void-return convention you see in Arrays.sort is not an accident. It is the same discipline David Parnas described in his 1972 paper on information hiding: a well-designed module does exactly one thing, and a sorting routine’s one job is to rearrange its argument. Returning a value would imply the method is also producing something new, muddying the contract. When you want a new sorted sequence instead of an in-place rearrangement, the idiom switches: Arrays.stream(arr).sorted().toArray() returns a fresh array and leaves the original untouched, which is the functional style.

A Comparator is also a specific mathematical structure. It imposes a total order on a set: a binary relation that is irreflexive (nothing comes before itself), asymmetric (if A before B then not B before A), and transitive (if A before B and B before C then A before C). These are exactly the axioms of a strict total order, and they are the same rules the Comparator contract enforces. When Arrays.sort throws IllegalArgumentException for a broken comparator, it has detected a violation of one of those axioms, usually transitivity.

The Comparator itself is an early example of the Strategy design pattern: instead of baking one ordering into the sort algorithm, the algorithm accepts an interchangeable strategy object that decides what “less than” means. This is the simplest form of what functional programmers call a first-class function, and it is why Java could later replace new TeamComparator() with the lambda (a, b) -> a.team.compareTo(b.team) without changing Arrays.sort at all.

In production code, in-place sorting is the default for efficiency: no allocation, no garbage collection pressure. The clone-before-sort pattern you practiced in Level 3 is the standard technique when a caller needs both orderings simultaneously, and you will see it routinely in data-processing pipelines, reporting layers, and anywhere a dataset is displayed in multiple views at once. TimSort, the algorithm behind Arrays.sort since Java 7, is also Python’s built-in list sort, chosen independently by both teams for the same reason: O(n log n) worst-case with O(n) behavior on nearly-sorted data, which real-world data often is.


Practice

Level 1

Sort Player[] nflPlayers by team name using TeamComparator. Then print the result. Write both lines.

Show answer
Arrays.sort(nflPlayers, new TeamComparator());
System.out.println(Arrays.toString(nflPlayers));

Arrays.sort returns void; the result is used through the original nflPlayers reference.

Pattern from F19.Lab1.CSCD211Lab1.java case 4.


Level 2

A student writes:

int[] scores = {42, 7, 100, 3};
Arrays.sort(scores, (a, b) -> b - a);

Explain the compile error and provide two correct alternatives for descending sort of an int[].

Show answer

Compile error: Arrays.sort(int[], Comparator) does not exist. Java has no Comparator<int>.

Alternative 1: Sort ascending then reverse:

Arrays.sort(scores);
// reverse scores manually
for (int i = 0, j = scores.length - 1; i < j; i++, j--) {
    int tmp = scores[i]; scores[i] = scores[j]; scores[j] = tmp;
}

Alternative 2: Box to Integer[]:

Integer[] boxed = { 42, 7, 100, 3 };
Arrays.sort(boxed, Comparator.reverseOrder());

Level 3

You need to display players sorted by team, while preserving the original roster order for a different output. Write the code that sorts a copy of Player[] roster by team without modifying roster.

Show answer
Player[] byTeam = roster.clone();
Arrays.sort(byTeam, new TeamComparator());

// roster is unchanged; byTeam is sorted by team
System.out.println("Original roster: " + Arrays.toString(roster));
System.out.println("By team:         " + Arrays.toString(byTeam));

clone() produces a shallow copy: a new array of the same length containing the same Player references. Sorting byTeam reorders the references in that copy without touching roster.


Check Yourself

Close the notes and answer each one from memory, then reveal it. Pulling an idea back from memory is one of the strongest ways to make it stick.

Check your understanding

What does Arrays.sort(players, new TeamComparator()) return?

Tier 1 · BJP (Reges and Stepp), Ch 13

Which of the following calls will NOT compile because Arrays.sort has no matching overload?

Tier 1 · BJP (Reges and Stepp), Ch 13

Trace this code and predict what is printed. pC.team = “Bears”, pA.team = “Aces”, pB.team = “Bears”. Player[] players = { pC, pA, pB }; Arrays.sort(players, new TeamComparator()); System.out.println(Arrays.toString(players));

Tier 2 · BJP (Reges and Stepp), Ch 13

A student needs the original roster order preserved after sorting. Which code pattern is correct?

Tier 2 · BJP (Reges and Stepp), Ch 13

According to the Java 25 Arrays API, which condition causes Arrays.sort to throw IllegalArgumentException rather than NullPointerException?

Tier 3 · BJP (Reges and Stepp), Ch 13