第3章 ラムダ式を使ったプログラミング : 問題 10 : 関数合成
問題
第3章 ラムダ式を使ったプログラミング : 画像変換 - CUBは子供の白熊 において、transform
メソッドに渡すUnaryOperator<Color>
は以下のように指定した
Image finalImage = transform(image, Color::brighter);
そこで、画像変換を “グレースケールにしてから明るくする” と拡張する場合
UnaryOperator<Color> op = Color::brighter; Image finalImage = transform(image, op.compose(Color::grayscale));
というふうにできない
なぜか?
解答
Color::brighter
の型はUnaryOperator<Color>
、Color::grayscale
の型もUnaryOperator<Color>
である
しかしUnaryOperator<T>
のスーパーインターフェースのFunction<T,T>
の default メソッドcompose
の戻り値の型はFunction<Color, Color>
になる
残念ながら、Java は型チェックが厳しすぎて
Function<Color, Color>
≠UnaryOperator<Color>
である
上記のコードはコンパイルエラーだし
UnaryOperator<Color> op = Color::brighter; Image finalImage = transform(image, (UnaryOperator<Color>)op.compose(Color::grayscale));
とキャストすると、コンパイルは通るが実行時にClassCastException
が起こってしまう。
Function<T,T>
のcompose
メソッドは、戻り値の型がFunction<T,T>
であると宣言している。
Java は、いくら構造が似ていても宣言されていない派生関係は認めない(Nominal Subtyping)という立場をとっているのである。
望む結果を得るには、以下のようにする
Image finalImage = transform(image, c -> c.grayscale().brighter());
■ 実行結果