Tobias Liefke
Tobias Liefke

Reputation: 9022

Min / max function of two Comparables

I need to find the smaller of two Comparable values:

Comparable<C> a = ...;
Comparable<C> b = ...;
Comparable<C> min = a.compareTo(b) <= 0 ? a : b;

This is similar to Math.min(a, b), but for Comparable.

I know that the ternary operator is already quite short, but I can't inline the expressions for a and b and I think that min(a, b) and max(a, b) is easier to understand.

I know that there are several functions that operate on Stream and Collection values, like:

Stream.of(a, b).min(Comparator.naturalOrder())

This would help to inline the expressions, but I still find it difficult to read and a bit too much overhead for such a small task.

For the moment I'm using my own utility function, but I'm interested to know if there's an existing function for this purpose. How can one find the minimum of two Comparable values in a readable and library-independent manner without too much performance overhead?

Upvotes: 39

Views: 14545

Answers (6)

Daniel Beer
Daniel Beer

Reputation: 1849

Using BinaryOperator (java.util.function)

Comparable<C> min = minBy(naturalOrder()).apply(a, b);

You have to use some static imports to make it this short:

import static java.util.Comparator.naturalOrder;
import static java.util.function.BinaryOperator.minBy;

You can also re-use the BinaryOperator to apply it to other pairs of objects.

Such pattern is especially usefull in Streams like in this example:

stream.collect(toMap(keyMapper, valueMapper, minBy(naturalOrder())))

This is one way of resolving key conflicts in a map by using the smallest value for each key.

Upvotes: 2

Tobias Liefke
Tobias Liefke

Reputation: 9022

I have created my own helper class, which extends Comparable by min, max, isLessThan, isLessOrEqualTo, isGreaterThan and isGreaterOrEqualTo:

public interface Ordered<T> extends Comparable<T> {

  static <T extends Comparable<? super T>> T min(T a, T b) {
    return a.compareTo(b) <= 0 ? a : b;
  }

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

  default boolean isLessThan(T other) {
    return compareTo(other) < 0;
  }

  default boolean isLessOrEqualTo(T other) {
    return compareTo(other) <= 0;
  }

  default boolean isGreaterThan(T other) {
    return compareTo(other) > 0;
  }

  default boolean isGreaterOrEqualTo(T other) {
    return compareTo(other) >= 0;
  }

}

The min and max methods I use for any Comparable:

String first = "a";
String second = "b";
System.out.println(Ordered.min(first, second)); // Prints "a"

For my own implementations of Comparable I extend Ordered and use that one for readable comparisons. Very helpful for enums:

public enum Board implements Ordered<Board> {
  NONE,
  BREAKFAST,
  HALF_BOARD,
  FULL_BOARD,
  ALL_INCLUSIVE
}

Usage:

Board requestedBoard = ...;
Board availableBoard = ...;
if (requestedBoard.isLessOrEqualTo(availableBoard)) {
  ...
}

Upvotes: 8

herman
herman

Reputation: 12305

Using Stream

Comparable<C> min = Stream.of(a, b).min(Comparable::compareTo).get();

Note that you will usually not call get() and assign, but use ifPresent(min -> ...) instead. But in this case you can trust the value to be present since the stream is not empty.

Upvotes: 1

M. Justin
M. Justin

Reputation: 21239

The Google Guava library has the Comparators.min and Comparators.max methods as of version 30.0:

Comparable<C> min = Comparators.min(a, b);

Upvotes: 6

diginoise
diginoise

Reputation: 7620

3rd party solutions

Collections has max(collection) and min(collection) methods, which kind of do what you want.

Bringing whole new library just to inline one simple op might be an overkill, unless you have Apache Commons or Guava in the mix.

Hand crafted

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

public <T extends Comparable<T>> T min(T a, T b) { 
    return a.compareTo(b) < 0 ? a : b; 
}

Upvotes: 8

azro
azro

Reputation: 54168

  1. From java.util.Collections: Collections.max() and Collections.min()

    Comparable<C> a = ...;
    Comparable<C> b = ...;
    Comparable<C> min = Collections.min(Arrays.asList(a,b));
    

  1. From org.apache.commons.lang3.ObjectUtils : ObjectUtils.max() and ObjectUtils.min()

    Comparable<C> a = ...;
    Comparable<C> b = ...;
    Comparable<C> min = ObjectUtils.min(a, b);
    

Apache Commons has less overhead and is able to handle null values, but it is a third party library.

Upvotes: 35

Related Questions