6

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));
    }
}

このように実装されていない理由はありますか?

4

6 に答える 6

3

他の人はなぜ可変個ではないのかをすでに答えていますがMath.max、可変個の関数が導入されたときにそのようなメソッドが作成されない理由には答えていません。

私もそれを知らないので(開いているバグレポートがあります)、推測することしかできません:

に実装されていないのは事実ですMathが、調べてみるCollectionsと以下のような方法がありました。

public static <T extends Object & Comparable<? super T>> T max(
    Collection<? extends T> coll) {
  ...
}

型シグネチャは見栄えが悪いですが (共分散と反分散を処理するのに十分な柔軟性が必要です)、簡単に使用できますCollections.max(Arrays.asList(-13, 12, 1337, 9));

さらに良いことに、このメソッドは double だけでなく、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

今後のリリースでは、プロジェクト Lambdaでコレクション ライブラリが作り直され、よりオブジェクト指向になりました。上記の例では、最大要素を決定するための簡単で読みやすい方法を提供するためにラムダが使用されています。以下も機能します。

import static java.util.Comparators.naturalOrder;

Arrays.asList(-13, 12, 1337, 9)
  .stream()
  .max(naturalOrder())
  .ifPresent(System.out::println); // 1337

代わりにmax、高次関数を使用することもできますreduce:

Arrays.asList(-13, 12, 1337, 9)
  .stream()
  .reduce((a,b) -> a > b ? a : b)
  .ifPresent(System.out::println); // 1337

別の詳細は、の使用ですOptional。上記の例のように高階関数の構成により、エラーハンドリングを簡略化するための型です。

ラムダ提案には、Math.max の可変長形式を実装する必要がなくなるいくつかの利点があります。

  1. オブジェクト指向です
  2. ポリモーフィックです。Listこれは、すべてのタイプのコレクション ( 、Set、など)Streamで使用できることを意味します。Iterator
  3. 表現力豊かで分かりやすい
  4. オンザフライの並列化が可能です。に変更.stream()するだけ.parallelStream()
于 2013-02-23T16:04:15.857 に答える
2

Java 8 では、ストリームを使用した数値操作が実装されており、非常に柔軟です。例:

DoubleStream.of( -13, 12, 1337, 9 ).max().getAsDouble()

自作ほど単純ではありませんが、それでも簡単で、高速で、より柔軟です。

たとえば、マルチコアを利用するには、1 つの関数呼び出しだけが必要です。

stream.parallel().max().getAsDouble()

この場合、max を見つけるのは double でも非常に高速であるため、まったく意味がありません。ミリ秒の違いを確認するには、数百万の double が必要です。ただし、他の処理がある場合は、それらをすばやく高速化できます。

または、システムクラスだけを使用して、最小、平均、合計などをすべて一度に見つけることもできます。

DoubleSummaryStatistics stat = DoubleStream.of( -13, 12, 1337, 9 ).summaryStatistics();
System.out.println( stat.getMin() );
System.out.println( stat.getAverage() );
System.out.println( stat.getMax() );
System.out.println( stat.getCount() );
System.out.println( stat.getSum() );
于 2014-08-29T06:17:04.597 に答える
2

可変引数関数が Java に存在するよりも長く存在し ( Java 5で導入)、更新する必要があまりなかったため、先ほど示したように、自分で行うのは簡単です。

また、配列 (double[]) が舞台裏で引数から作成されるため、varargs メソッドに関連する隠れたパフォーマンスの低下があります。

于 2013-02-23T11:44:52.083 に答える
1

Math.max は JDK 1.0 以降、変数 # of argument 構文が導入されるずっと前から存在しています。これは、あなたが提案した方法でメソッドを更新できなかったと言っているわけではありません。ライブラリ メソッドの定義または実装が変更されることがありますが、これはまれです。ほとんどの場合、既存のメソッドを変更するのではなく、新しいメソッドがクラスに追加されます。

Max の新しい実装は、実際にはメソッドのオーバーロードのケースです。これは、既存のメソッドと新しい var args メソッドが同じクラスに並んで存在する可能性があるためです。したがって、それは確かに既存のメソッドを置き換えることができますが、Math クラスへの単なる追加である可能性もあります。だから追加すればいいと思う。既存のメソッドをそのままにしておくことができるという事実により、新しい実装によって発生する可能性のあるパフォーマンスに関する懸念が取り除かれます。

とにかく、Java n と Java n+1 の間で変更できるものの文化は変化しています。たとえば、ファイル アクセス クラスとjava.sql.Connectionは Java 6 から Java 7 に変更されました。これは、Java 7 で が実装されるようになったためAutoCloseableです。Java 9 では実際に、プロジェクト Jigsawの邪魔になるいくつかのメソッドをクラスから削除しようとしています。

Math.max が更新されない正当な理由は考えられません。今まで誰も提案しなかったのかもしれません。これを読んでいますか、マーク・ラインホルド

于 2013-02-23T12:09:42.373 に答える