Clamp Function in Java – Java 中的钳位函数

最后修改: 2023年 9月 1日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

A clamp function restricts a value to within a range. It ensures a given value doesn’t fall outside specific lower and upper boundaries.

钳位函数将数值限制在一定范围内。它确保给定值不会超出特定的下限和上限。

In this tutorial, we’ll explore with examples how to implement the clamp function in Java.

在本教程中,我们将通过示例探讨如何在 Java 中实现钳位函数。

2. Clamp Function Before Java 21

2.Java 前的夹钳功能 21

Prior to Java 21, Java didn’t have an inbuilt function to clamp a value. We need to write our clamp function ourselves.

在 Java 21 之前,Java 没有内置的箝位函数。我们需要自己编写钳位函数。

A clamp function specifies a range of values. Values below the minimum are set to the minimum. Values above the maximum are set to the maximum. Also, values within the range return themselves.

钳位函数指定一个数值范围。低于最小值的值将设置为最小值。高于最大值的值将设置为最大值。此外,范围内的值会返回自身。

2.1. Using Method Overloading

2.1.使用方法重载

We can use method overloading to implement the clamp function for different data types.

我们可以使用方法 overloading 为不同的数据类型实现钳位函数

Let’s create a Clamp class and add a clamp() method that returns an integer:

让我们创建一个 Clamp 类,并添加一个返回整数的 clamp() 方法:

class Clamp {  
    int clamp(int value, int min, int max) {
        return Math.max(min, Math.min(max, value));
    }   
}

Here, we create a clamp() method that accepts the value, lower, and upper boundary as arguments. Furthermore, we use the Math class to set the minimum and the maximum values. Finally, we return the value if it’s in the set range and return the minimum or the maximum if the value isn’t in the range.

在这里,我们创建了一个 clamp() 方法,该方法接受值、下边界和上边界作为参数。此外,我们使用 Math 类来设置最小值和最大值。最后,如果值在设置范围内,我们将返回该值;如果值不在范围内,我们将返回最小值或最大值。

Let’s write a unit test for the clamp() method:

让我们为 clamp() 方法编写一个单元测试:

@Test
void givenValueOutsideRange_whenClamp_thenReturnLowerValue() {
    Clamp clampValue = new Clamp();
    assertEquals(15, clampValue.clamp(10, 15, 35));
}

Here, we create an instance of Clamp and invoke clamp() on it. The value is set to 10,  the minimum value is set to 15, and the maximum to 35. Since the value isn’t within range, the method returns the minimum.

在这里,我们创建了一个 Clamp 的实例,并对其调用 clamp() 。值设置为 10,最小值设置为 15,,最大值设置为 35。由于值不在范围内,该方法返回最小值。

Here’s a test for value within the range:

下面是对范围内数值的测试:

assertEquals(20, clampValue.clamp(20, 15, 35));

Since the input value falls within the range, the clamp() method returns this value.

由于输入值在该范围内,clamp() 方法会返回该值。

Finally, let’s see a test for a value above the maximum value:

最后,让我们来看看测试值是否高于最大值:

assertEquals(35, clampValue.clamp(50, 15, 35));

Here, the input value exceeds the maximum boundary. Hence, the clamp() method returns the maximum value.

在这里,输入值超过了最大边界。因此,clamp() 方法会返回最大值。

Furthermore, let’s implement a clamp function for double data type by overloading the clamp() method:

此外,让我们通过重载 clamp() 方法来实现 double 数据类型的钳位函数:

double clamp(double value, double min, double max) {
    return Math.max(min, Math.min(max, value));
}

Here, we overload the clamp() with double data type. Additionally, the method returns a double.

在这里,我们使用 double 数据类型重载 clamp() 方法。此外,该方法还返回一个 double.

2.2. Using Generics

2.2.使用泛型

Furthermore, we can use generics to make the clamp() method more flexible and work with different data types:

此外,我们可以使用 enerics 使 clamp() 方法更加灵活,并能处理不同的数据类型

static <T extends Comparable<T>> T clamp(T value, T min, T max) {
    if (value.compareTo(min) < 0) {
        return min;
    } else if (value.compareTo(max) > 0) {
        return max;
    } else {
        return value;
    }
}

The method above takes three arguments of generic type T. T also implements a Comparable interface. However, this method could be expensive. If the minimum and the maximum are primitive types, Java will automatically box them into equivalent objects because primitive types cannot implement Comparable.

上述方法接收 generic 类型 T 的三个参数。T 还实现了一个 Comparable 接口。然而,这种方法可能会很昂贵。如果最小值和最大值都是基元类型,Java 将自动将它们框选为等价对象,因为基元类型无法实现 可比较

Let’s write a unit test for the generic method:

让我们为通用方法编写一个单元测试:

@Test
void givenFloatValueWithinRange_whenClamp_thenReturnValue() {
    Clamp clampValue = new Clamp();
    assertEquals(16.2f, clampValue.clamp(16.2f, 15f, 35.3f));
}

The method accepts a float type, but while computing the value, it boxes float to Float and later unboxes the return value from Float to float. Therefore, we have two box operations and one unbox operation.

该方法接受 float 类型,但在计算值时,它将 float 框选为 Float ,随后又将返回值从 Float 取消框选为 float 。因此,我们有两个装箱操作和一个解箱操作。

Method overloading is recommended to avoid boxing/unboxing operations.

建议使用方法重载来避免装箱/开箱操作

3. Clamp Function After Java 21

3.Java 后的夹钳功能 21

Java 21, which is still in the experimental stage, introduces the clamp() method in the Math class. This method makes it easy to clamp a value without writing our own method.

仍处于试验阶段的 Java 21 在 Math 类中引入了 clamp() 方法。使用该方法,我们无需编写自己的方法,即可轻松箝位一个值。

Here’s an example that uses the clamp() in Java 21:

下面是一个使用 Java 21 中的 clamp() 的示例:

@Test
void givenValueWithinRange_whenClamp_thenReturnValue() {
    assertEquals(20, Math.clamp(20, 17, 98));
}

In the code above, we invoke the clamp() method and set the minimum and maximum values. The code returns the value because it’s within the minimum and maximum.

在上面的代码中,我们调用了 clamp() 方法,并设置了最小值和最大值。代码会返回该值,因为它在最小值和最大值范围内。

Notably, the clamp() method supports different data types. Therefore, there’s no need for explicit implementation for different data types.

值得注意的是,clamp() 方法支持不同的数据类型。因此,不需要为不同的数据类型进行显式实现。

4. Conclusion

4.结论

In this article, we learned three different methods to implement the clamp function in Java. We saw how to write a clamp() method before Java 21 introduced the clamp() method in the standard library.

在本文中,我们学习了在 Java 中实现钳位函数的三种不同方法。在 Java 21 在标准库中引入 clamp() 方法之前,我们了解了如何编写 clamp() 方法。

As always, the source code for the examples is available over on GitHub.

与往常一样,这些示例的源代码可在 GitHub 上获取。