Summary
Add four new methods named clamp() into java.lang.Math and java.lang.StrictMath classes that allow clamping numerical values to fit the specified range.
Problem
Quite often it's necessary to clamp a numerical value to a given range, using the algorithm like this:
int clampedValue = value > max ? max : value < min ? min : value;
or probably
int clampedValue = Math.max(min, Math.min(max, value));
These "algorithms" are verbose and error-prone. E.g., many years ago Math.max and Math.min were mixed in Jenkins CI implementation. Static analyzers like SonarLint even implement a rule to catch such kind of mistake, but it cannot statically find a mistake if max and min values are not constant.
Having a library method for this algorithm will make the code more readable, and robust. Standard libraries of various languages tend to implement a function that encapsulates this algorithm. E.g., Kotlin coerseIn, C# Math.Clamp, Rust num::clamp.
Solution
It's proposed to add methods to java.lang.Math
and to java.lang.StrictMath
class to solve this particular problem. We need four overloads to cover int
, long
, float
, and double
types. The signatures could be:
public static int clamp(long value, int min, int max)
public static long clamp(long value, long min, long max)
public static double clamp(double value, double min, double max)
public static float clamp(float value, float min, float max)
Specification
In both java.lang.Math
and java.lang.StrictMath
add:
/**
* Clamps the value to fit between min and max. If the value is less
* than {@code min}, then {@code min} is returned. If the value is greater
* than {@code max}, then {@code max} is returned. Otherwise, the original
* value is returned.
* <p>
* While the original value of type long may not fit into the int type,
* the bounds have the int type, so the result always fits the int type.
* This allows to use method to safely cast long value to int with
* saturation.
*
* @param value value to clamp
* @param min minimal allowed value
* @param max maximal allowed value
* @return a clamped value that fits into {@code min..max} interval
* @throws IllegalArgumentException if {@code min > max}
*
* @since 21
*/
public static int clamp(long value, int min, int max) {...}
/**
* Clamps the value to fit between min and max. If the value is less
* than {@code min}, then {@code min} is returned. If the value is greater
* than {@code max}, then {@code max} is returned. Otherwise, the original
* value is returned.
*
* @param value value to clamp
* @param min minimal allowed value
* @param max maximal allowed value
* @return a clamped value that fits into {@code min..max} interval
* @throws IllegalArgumentException if {@code min > max}
*
* @since 21
*/
public static long clamp(long value, long min, long max) {...}
/**
* Clamps the value to fit between min and max. If the value is less
* than {@code min}, then {@code min} is returned. If the value is greater
* than {@code max}, then {@code max} is returned. Otherwise, the original
* value is returned. If value is NaN, the result is also NaN.
* <p>
* Unlike the numerical comparison operators, this method considers
* negative zero to be strictly smaller than positive zero.
* E.g., {@code clamp(-0.0, 0.0, 1.0)} returns 0.0.
*
* @param value value to clamp
* @param min minimal allowed value
* @param max maximal allowed value
* @return a clamped value that fits into {@code min..max} interval
* @throws IllegalArgumentException if either of {@code min} and {@code max}
* arguments is NaN, or {@code min > max}, or {@code min} is +0.0, and
* {@code max} is -0.0.
*
* @since 21
*/
public static double clamp(double value, double min, double max) {...}
/**
* Clamps the value to fit between min and max. If the value is less
* than {@code min}, then {@code min} is returned. If the value is greater
* than {@code max}, then {@code max} is returned. Otherwise, the original
* value is returned. If value is NaN, the result is also NaN.
* <p>
* Unlike the numerical comparison operators, this method considers
* negative zero to be strictly smaller than positive zero.
* E.g., {@code clamp(-0.0f, 0.0f, 1.0f)} returns 0.0f.
*
* @param value value to clamp
* @param min minimal allowed value
* @param max maximal allowed value
* @return a clamped value that fits into {@code min..max} interval
* @throws IllegalArgumentException if either of {@code min} and {@code max}
* arguments is NaN, or {@code min > max}, or {@code min} is +0.0f, and
* {@code max} is -0.0f.
*
* @since 21
*/
public static float clamp(float value, float min, float max) {...}
- csr of
-
JDK-8301226 Add clamp() methods to java.lang.Math and to StrictMath
-
- Resolved
-