1. ホーム

[解決済み】Java 8ストリームの.min()と.max():なぜこれがコンパイルされるのでしょうか?

2022-04-10 09:02:44

質問

注:この質問は、以前のSOの質問であったデッドリンクに由来するものですが、ここでは...

このコードを見てください ( 注:このコードが動作しないことは承知しています。 Integer::compare を使用する必要があります。 ):

final ArrayList <Integer> list 
    = IntStream.rangeClosed(1, 20).boxed().collect(Collectors.toList());

System.out.println(list.stream().max(Integer::max).get());
System.out.println(list.stream().min(Integer::min).get());

のjavadocによると .min() .max() であるべきであり,両者の引数は Comparator . しかし、ここでは、メソッドの参照先が Integer クラスがあります。

では、なぜこれが全くコンパイルされないのでしょうか?

どうすれば解決するの?

ここで何が起こっているのか、説明しましょう。

まず Stream.max() のインスタンスを受け取ります。 Comparator のように、ストリーム内のアイテムを互いに比較して最小値や最大値を見つけることができます。

そこで問題は、当然ながら、なぜ Integer::max を受け入れるか? 結局のところ、それは比較対象ではないのです。

その答えは、Java 8の新しいラムダ機能の動作にあります。 これは、非公式に単一抽象メソッドインターフェース(SAMインターフェース)と呼ばれる概念に依存しています。 この考え方は、1つの抽象メソッドを持つインターフェースは、そのインターフェースの1つのメソッドに一致するメソッドシグネチャを持つラムダ(またはメソッド参照)によって自動的に実装することができるというものです。 つまり Comparator インタフェース(簡易版)です。

public Comparator<T> {
    T compare(T o1, T o2);
}

もし、あるメソッドが Comparator<Integer> ということは、本質的にこのシグネチャを探していることになります。

int xxx(Integer o1, Integer o2);

私は "xxx" を使っています。 メソッド名はマッチングに使用されないため .

したがって、両方の Integer.min(int a, int b)Integer.max(int a, int b) は十分に近いので、オートボックスによって、これが Comparator<Integer> をメソッドコンテキストに追加します。