Solution: Max by Natural Order

Start with the version that uses each element’s own natural order. It is indexOfMin with two changes: the comparison flips from “smaller” to “larger,” and we return the element itself rather than its index.

Solution

Because max calls compareTo, the type parameter needs the bound <T extends Comparable<T>>. The method declares its own T, with that bound, before the return type.

public static <T extends Comparable<T>> T max(DynamicArray<T> a) {
  T best = a.get(0);
  for (int i = 1; i < a.size(); i++) {
    if (a.get(i).compareTo(best) > 0) {
      best = a.get(i);
    }
  }
  return best;
}

We seed best with the first element, then iterate over the rest. Whenever we find a larger element, it becomes the new best. An empty array has no maximum, so get(0) throws. max assumes at least one element.

Now the second half of the question: why not write T max() as a method on DynamicArray?

The first reason is that it would not compile. DynamicArray<T> declares T with no bound, so inside the class, T is not guaranteed to have a compareTo. An instance max() would try to call compareTo on that T, and the compiler would reject it.

The next thought is to fix that by bounding the class: class DynamicArray<T extends Comparable<T>>. Then an instance max() compiles. But the bound applies to every use of the class, not just to max. You could no longer write DynamicArray<Color> unless Color implemented Comparable, which would mean deciding on a natural order for colors before you are allowed to put colors in a list. The reason T is unbounded is that a container does not need its elements to be ordered. If we bound the class to satisfy one method, we give that up.

So we leave the class unbounded and put the bound on the method. A static method declares its own T, separate from the array’s, and it can put whatever bound its body needs on that T. max requires Comparable, and no other code has to satisfy that bound. This is the same reasoning we used for swap and indexOfMin: add a bound only where the body needs it. That gives us a second reason to keep max in MoreArrayUtils, besides the design reason we already had.