Java 8 のソースを調べていたところ、コードのこの部分が非常に驚くべきものであることがわかりました。
// Defined in IntPipeline.java
@Override
public final OptionalInt reduce(IntBinaryOperator op) {
return evaluate(ReduceOps.makeInt(op));
}
@Override
public final OptionalInt max() {
return reduce(Math::max); // This is the gotcha line
}
// Defined in Math.java
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
Math::max
メソッド ポインタのようなものですか? 通常のメソッドはどのようにして に変換されるの
でしょうか?static
IntBinaryOperator
ベストアンサー1
reduce
通常、次のようにしてメソッドを呼び出しますMath.max(int, int)
。
reduce(new IntBinaryOperator() {
int applyAsInt(int left, int right) {
return Math.max(left, right);
}
});
を呼び出すだけでも多くの構文が必要になりますMath.max
。ここでラムダ式が役立ちます。Java 8 以降では、同じことをはるかに短い方法で実行できるようになりました。
reduce((int left, int right) -> Math.max(left, right));
これはどのように動作するのでしょうか? Java コンパイラは、 を 2 つ受け入れてint
1 つを返すメソッドを実装しようとしていることを「検出」しますint
。これは、インターフェースの唯一のメソッドの正式なパラメータIntBinaryOperator
(呼び出したいメソッドのパラメータreduce
) に相当します。そのため、コンパイラが残りの作業を行います。つまり、 を実装しようとしていると想定するだけですIntBinaryOperator
。
しかし、Math.max(int, int)
自体は の形式要件を満たしているためIntBinaryOperator
、直接使用できます。Java 7 には、メソッド自体を引数として渡すことを許可する構文がないため (メソッドの結果のみを渡すことができ、メソッド参照は渡すことができません)、メソッドを::
参照するための構文が Java 8 で導入されました。
reduce(Math::max);
これは実行時に JVM ではなくコンパイラによって解釈されることに注意してください。3 つのコード スニペットすべてに対して異なるバイトコードが生成されますが、意味的には同じであるため、最後の 2 つはIntBinaryOperator
上記の実装の短縮版 (おそらくより効率的なバージョン) と見なすことができます。
(参照ラムダ式の翻訳)