Mar*_*oma 5 java variadic-functions
为什么Math.max的实现不具有可变函数?
它可以像这样实现:
public class Main {
public static double max(double... values) {
double max = Double.NEGATIVE_INFINITY;
for (double tmp : values) {
max = max < tmp ? tmp : max;
}
return max;
}
public static void main(String[] args) {
// This works fine:
System.out.println(max(-13, 12, 1337, 9));
// This doesn't work:
// System.out.println(Math.max(-13, 12, 1337));
}
}
Run Code Online (Sandbox Code Playgroud)
是否有任何理由不这样实施?
将java.lang.Math在JDK 1.0已经推出,可变参数功能引入了Java 5中的语言很久以前.
另外,效率是一个问题:如果你大多数时候需要两个元素,那么将它们"内联"传递它们要快得多,而不需要创建一个中间数组来保存它们.这也避免了在实现中设置循环的成本.
虽然其他人已经回答了为什么Math.max不是可变参数,但他们没有回答为什么在引入可变参数函数时不创建这样的方法。
我什至不知道(有一个开放的错误报告)所以我只能猜测:
确实,它没有在 中实现Math,但是如果我们研究一下,Collections有以下方法:
public static <T extends Object & Comparable<? super T>> T max(
Collection<? extends T> coll) {
...
}
Run Code Online (Sandbox Code Playgroud)
虽然类型签名看起来很丑(它需要足够灵活来处理协变和逆变),但它可以很容易地在Collections.max(Arrays.asList(-13, 12, 1337, 9));所有函数实现之后使用,只是在不同的地方。
更好的是:此方法不仅可以处理双精度数,还可以处理实现该Comparable接口的所有类型。
然而,您建议的解决方案和解决方案都不Collections是面向对象的,它们只是静态方法。幸运的是,有了JDK8,这将会改变:
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
int max(List<Integer> list) {
Optional<Integer> opt = list.stream().max((a,b) -> a-b);
return opt.orElse(Integer.MAX_VALUE);
}
max(Arrays.asList(-13, 12, 1337, 9)); // 1337
max(Arrays.asList()); // 2147483647
Run Code Online (Sandbox Code Playgroud)
对于即将发布的版本,集合库在Lambda 项目中进行了重新设计,使其更加面向对象。在上面的示例中,Lambda 用于提供一种简单易读的方式来确定最大元素。以下也可以工作:
import static java.util.Comparators.naturalOrder;
Arrays.asList(-13, 12, 1337, 9)
.stream()
.max(naturalOrder())
.ifPresent(System.out::println); // 1337
Run Code Online (Sandbox Code Playgroud)
max也可以使用高阶函数来代替reduce:
Arrays.asList(-13, 12, 1337, 9)
.stream()
.reduce((a,b) -> a > b ? a : b)
.ifPresent(System.out::println); // 1337
Run Code Online (Sandbox Code Playgroud)
另一个细节是使用Optional. 如上例所示,它是一种由于高阶函数的组合而简化错误处理的类型。
lambda 提案有几个优点,使得无需实现 Math.max 的可变参数形式:
List、Set、Stream等Iterator).stream()为.parallelStream()