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:
<T> T max(T... inputs)
.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.
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.
Stream.of(inputs).max(Comparator.naturalOrder())
, which accepts an arbitrary Comparator
and returns an Optional
, which is empty if the collection is empty. NullPointerException
is thrown if null
is the maximum element.Collections.max(Arrays.asList(inputs))
, which does correct type-safety things (to enforce that you either pass a Comparator
, or have naturally Comparable
elements), but returns an element or throws NoSuchElementException
. null
will be returned if the input contains null and the provided comparator reports that the maximum element is null
.Since you ask about libraries, I'll mention Guava's offerings here:
Ordering
, which was Guava's "fluent Comparator
" type, has max
methods accepting an Iterable
, Iterator
, or two arguments. Ordering
isn't exactly deprecated, but is mostly obsolete at this point.Comparators
has a max
method accepting either two Comparable
arguments, or two arguments and a Comparator
.