1. 概述
钳子函数限制一个值在特定范围内。它确保给定的值不会超出特定的下限和上限。
在这个教程中,我们将通过示例探讨如何在Java中实现钳子函数。
2. Java 21之前钳子函数的实现
在Java 21之前,Java并没有内置的钳子函数。我们需要自己编写这个函数。
钳子函数定义了一个值范围。低于最小值的值设置为最小值,超过最大值的值设置为最大值。同时,处于范围内的值则返回自身。
2.1. 使用方法重载
我们可以使用方法重载(method overloading)为不同数据类型实现钳子函数。
让我们创建一个Clamp
类,并添加一个返回整数的clamp()
方法:
class Clamp {
int clamp(int value, int min, int max) {
return Math.max(min, Math.min(max, value));
}
}
这里,我们创建了一个接受值、下限和上限作为参数的clamp()
方法。此外,我们使用Math
类来设置最小值和最大值。最后,如果值在设定范围内,就返回该值,否则返回最小值或最大值。
接下来,我们为clamp()
方法编写单元测试:
@Test
void givenValueOutsideRange_whenClamp_thenReturnLowerValue() {
Clamp clampValue = new Clamp();
assertEquals(15, clampValue.clamp(10, 15, 35));
}
这里,我们创建一个Clamp
实例并调用clamp()
方法。值设为10
,下限设为15
,上限设为35
。由于值不在范围内,方法返回最小值。
这里是值在范围内的测试:
assertEquals(20, clampValue.clamp(20, 15, 35));
因为输入值在范围内,clamp()
方法返回这个值。
最后,看一个值大于最大值的测试:
assertEquals(35, clampValue.clamp(50, 15, 35));
在这里,输入值超过了最大边界。因此,clamp()
方法返回最大值。
此外,我们还可以为double
数据类型重载clamp()
方法:
double clamp(double value, double min, double max) {
return Math.max(min, Math.min(max, value));
}
这里,我们为double
数据类型重载了clamp()
方法,它返回一个double
。
2.2. 使用泛型
此外,我们可以使用泛型(generics)使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;
}
}
上述方法接受三个泛型类型T
作为参数,T
实现了Comparable
接口。然而,这种方法可能会有些昂贵。如果最小值和最大值是基本类型,Java会自动将它们装箱成相应的对象,因为基本类型不能实现Comparable
接口。
现在,我们为泛型方法编写单元测试:
@Test
void givenFloatValueWithinRange_whenClamp_thenReturnValue() {
Clamp clampValue = new Clamp();
assertEquals(16.2f, clampValue.clamp(16.2f, 15f, 35.3f));
}
这个方法接受float
类型,但在计算值时,它将float
转换为Float
,然后将返回值从Float
反向转换为float
。因此,我们有两次装箱操作和一次解包操作。
推荐使用方法重载以避免装箱/拆箱操作。
3. Java 21之后的钳子函数
Java 21,目前仍处于实验阶段,将在Math
类中引入clamp()
方法。这使得在不编写自定义方法的情况下轻松钳制值变得简单。
以下是使用Java 21中clamp()
方法的一个例子:
@Test
void givenValueWithinRange_whenClamp_thenReturnValue() {
assertEquals(20, Math.clamp(20, 17, 98));
}
在上面的代码中,我们调用clamp()
方法并设置最小值和最大值。由于值在最小值和最大值之间,代码返回该值。
值得注意的是,clamp()
方法支持不同的数据类型,因此不需要为不同数据类型进行显式实现。
4. 总结
在这篇文章中,我们学习了三种在Java中实现钳子函数的方法。我们了解了在Java 21引入标准库中的clamp()
方法之前如何编写clamp()
方法。
如往常一样,所有示例的源代码可以在GitHub上找到。