CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第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());

■ 実行結果 f:id:ClosedUnBounded:20150610195928p:plain