この部分のFunction
Function<IntBinaryOperator, Integer, Integer(戻り値の型)> f = //←この部分がわかりません。この次の行で定義する函数リテラルは、以下の関数の型を期待していることがわかります。
- (IntBinaryOperator,int,int) -> int
型パラメータに置き換えると、3引数をとり戻り値を返す、関数型インターフェイスのどれかに該当します。
- (T,U,V) -> W
- (T,U,U) -> V
- (T,U,U) -> U
Java標準の関数型インターフェイス
java.util.functionパッケージを調べます。Java標準の関数型インターフェイスで3引数のものはありません。
Function<T,R>は、(T) -> R (引数は1つだけ)
BiFunction<T,U,R>は、(T,U) -> R
BinaryOperator<T>は、(T,T) -> T
IntUnaryOperatorは、(int) -> int
IntBinaryOperatorは、(int,int) -> int
…
3引数の関数型インターフェイスを定義する
標準の関数型インターフェイスがない場合は、自分で3引数の関数型インターフェイスを定義します。
- 関数型インターフェイスのメソッドは1つだけ定義する
- ただし、Objectで定義されるメソッド(equals, toString など)や、staticメソッド、デフォルトメソッドは除外
- @FunctionalInterfaceアノテーションをつけてコンパイラにチェックさせる
3引数の関数型インターフェイスをどう使うかによって、型パラメータの指定が異なります。要件に応じて型パラメータを決めてください。
Java
1
2 @FunctionalInterface
3 interface TriFunction<T, U, V, W> { // (T,U,V) -> W
4 W apply(T f, U x, V y);
5 }
6 interface TriFunction2<T, U, V> extends TriFunction<T, U, U, V> {}
7 interface TriFunction3<T, U> extends TriFunction<T, U, U, U> {}
8 interface HigherOrderBiOperator<T> extends TriFunction<BiFunction<T,T,T>, T, T, T> {}
9
10 @FunctionalInterface
11 interface HigherOrderIntBinaryOperator { // (IntBinaryOperator, int, int) -> int
12 int apply(IntBinaryOperator f, int x, int y);
13 }
14
Java標準の関数型インターフェイスで済ませる
標準のFunctionを使って、関数を引数にとり合成関数を返すことができます。
Java
1Function<IntBinaryOperator, IntBinaryOperator> f3 = fun -> (x,y) -> fun.applyAsInt(x,y) + fun.applyAsInt(x,y);
2Function<IntBinaryOperator, BiFunction<Integer,Integer,Integer>> f4 = fun -> (x,y) -> fun.applyAsInt(x,y) + fun.applyAsInt(x,y);
関数は定義しただけなので、f3.applyAsInt(a,b)またはf4.apply(a,b)で呼び出して、結果を得ます。
カリー化(追記)
カリー化を追記します。左辺の関数の型が入れ子になります。
Java
1 Function<IntBinaryOperator,IntFunction<IntUnaryOperator>> f5 = fun -> x -> y -> fun.applyAsInt(x,y) + fun.applyAsInt(x,y);
2 System.out.println(f5.apply((x,y)-> x * y).apply(3).applyAsInt(2));
参考: Does Java support Currying?