ホーム › オブジェクト指向設計(OOP) › OOP-03
OOP-03: 関数型インターフェース・ラムダ式との関係
Java 8 で導入されたラムダ式は「@FunctionalInterface(抽象メソッドが1つのインターフェース)」を 匿名クラスよりも簡潔に実装する仕組みです。 Strategy パターンをラムダで書き換える例を通じて、関数型インターフェースの本質を理解しましょう。
@FunctionalInterface とは何か
Java のインターフェースのうち、抽象メソッドがちょうど1つだけのものを「関数型インターフェース」と呼びます。@FunctionalInterface アノテーションをつけることで、 コンパイラがその制約(抽象メソッドは1つだけ)を確認してくれます。
ラムダ式が使える理由
ラムダ式は「インターフェースを実装した匿名クラスのインスタンス」の省略形です。 抽象メソッドが1つだけなので、ラムダ式のコード(-> の右辺)が 「その1つのメソッドの実装」として自動的に対応付けられます。
| 書き方 | 例 | 特徴 |
|---|---|---|
| 匿名クラス | new Validator() { @Override ... } | Java 7 以前からある書き方。冗長だが明示的 |
| ラムダ式 | value -> value != null | Java 8 以降。簡潔で読みやすい |
| メソッド参照 | System.out::println | 既存のメソッドをそのまま渡す。さらに簡潔 |
サンプルコード
Java 8 で導入されたラムダ式は、@FunctionalInterface(抽象メソッドが1つのインターフェース)を実装するときに匿名クラスの代わりに使えます。Comparator や Runnable など、既存の多くのインターフェースもラムダで実装できます。
よくあるミス・注意点
⚠️ @FunctionalInterface アノテーションは必須ではないが、つけることを推奨
@FunctionalInterface は必須ではありません。 アノテーションなしでも抽象メソッドが1つであればラムダで実装できます。 ただし、アノテーションをつけることで「このインターフェースは関数型として使うことを意図している」という意図が明確になり、 誤って抽象メソッドを2つ追加してしまったときにコンパイルエラーで気づけます。 自分で定義する関数型インターフェースには、積極的にアノテーションをつけましょう。
⚠️ ラムダ式の中で例外をスローするときの注意
ラムダ式の中で検査例外(IOException など)をスローしようとすると、 インターフェースのメソッド宣言に throws IOException がないとコンパイルエラーになります。 例外が発生しうる処理をラムダに渡す場合は、ラムダの中で try-catch して非検査例外(RuntimeException)に変換するか、throws IOException を宣言したカスタム関数型インターフェースを定義してください。
テストする観点
- 匿名クラスとラムダ式で実装した
Validatorが同じ引数に対して同じ結果を返すこと(同等性の確認) Validator.and()の合成結果が、各バリデーションを個別に呼び出した結果の AND と一致すること- メソッド参照(
System.out::println)が対応するラムダ式(s -> System.out.println(s))と同等に動作すること - PriceCalculator の各戦略(通常・10%引き・半額)が期待通りの価格を計算すること(境界値: 価格 0 のとき)
- Comparator.comparing() によるソートが正しい順序でリストを返すこと