Functionインタフェースに定義されている関数の合成を試してみた
Java8のFunctionインターフェースに提供されている関数の合成を試してみた。提供されている関数はcompose
とandThen
の2つである。
関数の合成の処理はとても簡単だ。Java8のFunction
インターフェースの実装を見ると、処理はたった2行で実装されている。nullチェックが1行で、ラムダ式で書かれた本体が1行である。
以下は、Java8のソースコードからの引用である。
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }
この関数の合成を試してみよう。
まずはFunction
インタフェースを使ったシンプルな関数(f1
とf2
)を2つ定義して動かしてみる。
public class Main { public static void main(String[] args) { Function<Integer, Integer> f1 = x -> { System.out.print("f1 -> "); return 1 + x; }; Function<Integer, Integer> f2 = x -> { System.out.print("f2 -> "); return 2 * x; }; System.out.println("[f1]"); System.out.println(f1.apply(0)); System.out.println("[f2]"); System.out.println(f2.apply(0)); } }
実行結果は以下のようになる。
[f1] f1 -> 1 [f2] f2 -> 0
続けて、compose
とandThen
を使って関数を合成してみる。
public class Main { public static void main(String[] args) { // (以下は上のコードの続き) Function<Integer, Integer> f3 = f1.compose(f2); System.out.println("[f3: f1.compose(f2)]"); System.out.println(f3.apply(0)); Function<Integer, Integer> f4 = f1.andThen(f2); System.out.println("[f4: f1.andThen(f2)]"); System.out.println(f4.apply(0)); Function<Integer, Integer> f5 = f1.andThen(f2).compose(f1); System.out.println("[f5: f1.andThen(f2).compose(f1)]"); System.out.println(f5.apply(0)); } }
実行すると、次のように関数が合成されることが分かる。
[f3: f1.compose(f2)] f2 -> f1 -> 1 [f4: f1.andThen(f2)] f1 -> f2 -> 2 [f5: f1.andThen(f2).compose(f1)] f1 -> f1 -> f2 -> 4
ところで、このcompose
とandThen
による関数合成は、Function
インターフェースに従っていないと合成できない。つまり、任意のFunctionalInterface
同士を合成するための仕組みではない。
このため、FunctionalInterface
を自作する際には、Function
インターフェースを実装してcompose
とandThen
による関数合成を可能にするかどうかを意識しておく必要がある。
[近棟 稔]