関数型インターフェース
CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 39/87。
関数型インターフェースとは、抽象メソッドをただ1つだけ持つインターフェースのことです。この単一メソッドという制約により、関数型インターフェースはラムダ式を使用して実装できるようになり、より簡潔なコーディングスタイルが可能になるという特別な性質を持っています。
Javaは、インターフェースが関数型であることを明示的に示すために @FunctionalInterface アノテーションを提供しています。このアノテーションは任意ですが、誤って2つ目の抽象メソッドを追加した場合にコンパイラがエラーを検出するのに役立ちます:
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}関数型インターフェースは、クラスを使用した従来の方法、またはラムダ式を使用したより簡潔な方法で実装できます。
// 従来の実装
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// ラムダ式(より簡潔です!)
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8関数型インターフェースは、デフォルトメソッドやstaticメソッドを持つことができます。これらは単一抽象メソッドのルールにはカウントされないためです。Javaのjava.util.functionパッケージには、Predicate、Function、Consumerなど、ストリームやコレクションを扱う際によく遭遇する多くの組み込み関数型インターフェースが用意されています。
チャレンジ
簡単関数型インターフェースとラムダ式を使用して、文字列変換システムを構築しましょう。単一の関数型インターフェースを活用して、文字列にさまざまな変換を適用できる柔軟なテキストプロセッサを作成します。
コードは以下の3つのファイルに分けて構成します:
StringTransformer.java: 任意の文字列変換操作を表す関数型インターフェースを定義します。関数型であることを保証するために、@FunctionalInterfaceアノテーションを付加してください。このインターフェースには、Stringを受け取りStringを返すtransformという名前の抽象メソッドを1つだけ宣言する必要があります。TextProcessor.java: 関数型インターフェースを使用してテキストを処理するクラスを作成します。このクラスはStringTransformerを保持するフィールドと、それを初期化するためのコンストラクタを持つ必要があります。また、指定されたテキストにトランスフォーマーを適用して結果を返すprocess(String text)というメソッドを含めてください。この設計により、コンストラクタを通じて任意の変換動作を注入できるようになります。Main.java: ラムダ式を使用して異なる変換を作成し、すべてを統合します。2つの入力(テキスト文字列と操作タイプ(upper、lower、またはreverse))を受け取ります。操作タイプに基づいて、適切なラムダ式を持つ
TextProcessorを作成します:upper: テキストを大文字に変換しますlower: テキストを小文字に変換しますreverse: テキストを反転させます(ヒント:StringBuilderを使用してください)
その後、入力テキストを指定して
process()を呼び出し、結果をResult: [transformed text]という形式で出力します。
変換対象のテキスト(String)と操作タイプ(String)の2つの入力を受け取ります。
渡すラムダ式によって、同じ TextProcessor クラスがまったく異なる操作を実行できることに注目してください。これが関数型インターフェースの強力な点です!
チートシート
関数型インターフェースは、抽象メソッドを1つだけ持つインターフェースです。ラムダ式を使用して簡潔なコードで実装できます。
インターフェースを関数型としてマークするには、@FunctionalInterfaceアノテーションを使用します(任意ですが推奨されます):
@FunctionalInterface
public interface Calculator {
int calculate(int a, int b);
}関数型インターフェースは、従来の方法またはラムダ式で実装できます:
// 従来の実装
Calculator adder = new Calculator() {
@Override
public int calculate(int a, int b) {
return a + b;
}
};
// ラムダ式
Calculator adder = (a, b) -> a + b;
System.out.println(adder.calculate(5, 3)); // 8関数型インターフェースは、単一抽象メソッドの規則に違反することなく、デフォルトメソッドや静的メソッドを持つことができます。
Javaのjava.util.functionパッケージには、Predicate、Function、Consumerなどの組み込み関数型インターフェースが用意されています。
自分で試してみよう
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String operation = scanner.nextLine();
TextProcessor processor;
// TODO: 操作タイプに基づいて、適切なラムダ式を使用してTextProcessorを作成します:
// - "upper": テキストを大文字に変換
// - "lower": テキストを小文字に変換
// - "reverse": テキストを反転(ヒント:StringBuilderを使用)
// TODO: 入力テキストを使用してprocess()を呼び出し、結果を出力します
// 出力形式: "Result: [transformed text]"
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造6インターフェースと抽象クラス
インターフェース入門インターフェースの実装複数インターフェースの実装インターフェースのデフォルトと静的メソッド抽象クラス vs インターフェース関数型インターフェースまとめ - 決済システム