javacollectionscomparator

A pithy way to obtain the largest amongst a set of comparables


Context: Modern java (the latest version; JDK23 at time of writing this question)

Given 2 objects that are comparable (implement Comparable<T>, where T is a type they all share), how does one obtain the largest of the two?

Had this question been about integers, the answer is reasonably simple:

int largest = Math.max(a, b);

It's slightly annoying (but, perhaps from the perspective of varargs introducing a newly heap-allocated array, sensible due to performance concerns) that this only works for precisely 2 integers.

But there is no max for <T>. It could exist; it would be easy:

public static <T implements Comparable<? super T>> T max(T a, T b) {
  return a.compareTo(b) < 0 ? b : a;
}

But, java.lang.Math does not contain this method; only max methods from primitives.

Complications:

In that vein, I was expecting this method to exist in java.util.Comparator:

public default T max(T... inputs) {
  if (inputs.length == 0) throw new IllegalArgumentException("inputs is empty"); // [1]
  T out = inputs[0];
  for (int i = 1; i < inputs.length; i++) {
    T t = inputs[i];
    if (out.compareTo(t) < 0) out = t;
  }
  return out;
}

However, none of the classes one might expect this on (java.util.Comparator, java.util.Comparators, java.util.Comparable) appears to have such a method.

Checking some of my code projects, I have quite a few methods scattered about such as:

public LocalDate latest(LocalDate a, LocalDate b) {
   return a.isBefore(b) ? b : a;
}

which could all be replaced with such a method; LocalDate implements Comparable, so if a max method had existed I could just have called max(date1, date2) instead.

Does it exist somewhere in the java.* core libraries? Are there plans afoot in future JDK releases to have such a method?

Not asking for particular libraries, simply an inventory of sorts: Any popular libraries that do include it, in terms as generic as the snippets in this question? 2


[1] A designer might initially think returning an Optional<T> is better here; this would be the wrong design. Callers would, virtually always, pass explicit arguments, thus guaranteeing that Optional.none literally cannot happen. For the same reason it's bad API design to make a method that declares throwing a checked exception that the docs say can never occur in commonly use cases, having an API that returns an optional that can never be NONE is similarly annoying. The exception is thus the correct solution here.

[2] null handling is up for debate here. If one ascribes to the SQL view of null (which is that null represents unknown values), then an implementation that e.g. returns b if a is null would be incorrect (how do you know, between a known value and an unknown value, that the known value is the one that was larger?): An NPE is correct. But, if one ascribes to the view that null means 'missing' then NPE is wrong and returning the maximum from amongst the non-null values is right. The question is complex enough as is; let's say that any reasonable null handling is acceptable.


Solution

  • There are two very straightforward approaches already easily assembled from the Java standard library, and it's not obvious that more are necessary. All of these have alternate min versions.

    Since you ask about libraries, I'll mention Guava's offerings here: