为什么不是Math.max(双a,双b)可变参数?

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)

是否有任何理由不这样实施?

das*_*ght 5

java.lang.Math在JDK 1.0已经推出,可变参数功能引入了Java 5中的语言很久以前.

另外,效率是一个问题:如果你大多数时候需要两个元素,那么将它们"内联"传递它们要快得多,而不需要创建一个中间数组来保存它们.这也避免了在实现中设置循环的成本.


kir*_*uku 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 的可变参数形式:

  1. 它是面向对象的
  2. 它是多态的。这意味着它可以用于每种类型的集合(ListSetStreamIterator
  3. 富有表现力且易于理解
  4. 它允许即时并行化。只需更改.stream().parallelStream()