カスタム関数型インターフェース
@FunctionalInterface で独自に定義します。
「カスタム関数型インターフェース」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
インターフェースが関数型になる条件
関数型インターフェースには、抽象メソッド(SAM)がちょうど1つあります。このメソッド1つをラムダが実装します。
- defaultメソッドとstaticメソッドは、この数に含まれません。
interface Greeter {
String greet(String name);
}
public class Main {
public static void main(String[] args) {
Greeter g = name -> "Hello, " + name;
System.out.println(g.greet("Ada"));
}
}@FunctionalInterfaceアノテーション
@FunctionalInterfaceは、抽象メソッドを1つだけにする規則をコンパイラーに適用させます。誤って2つ目の抽象メソッドを追加すると、コンパイルに失敗します。
@FunctionalInterface
interface Calculator {
int compute(int a, int b);
}
public class Main {
public static void main(String[] args) {
Calculator add = (a, b) -> a + b;
System.out.println(add.compute(3, 4));
}
}アノテーションが役立つ理由
このアノテーションは意図を記録し、契約を保護します。アノテーションがなくてもインターフェースは関数型として機能しますが、チームメンバーが別の抽象メソッドを追加して壊してしまう可能性があります。
@FunctionalInterface
interface Transformer {
String apply(String input);
}
public class Main {
public static void main(String[] args) {
Transformer reverse = s -> new StringBuilder(s).reverse().toString();
System.out.println(reverse.apply("abc"));
}
}ジェネリクスを使ったカスタムインターフェース
組み込みのインターフェースと同じように、インターフェースをジェネリックにすることもできます。
@FunctionalInterface
interface Converter<S, T> {
T convert(S source);
}
public class Main {
public static void main(String[] args) {
Converter<String, Integer> toInt = Integer::parseInt;
System.out.println(toInt.convert("123") + 1);
}
}defaultメソッドは使用可能
関数型インターフェースにはdefaultメソッドを定義できます。これにより、抽象メソッドを1つだけにする規則を壊さずに動作を追加できます。
@FunctionalInterface
interface Operation {
int apply(int x);
default Operation then(Operation next) {
return x -> next.apply(this.apply(x));
}
}
public class Main {
public static void main(String[] args) {
Operation inc = x -> x + 1;
Operation dbl = x -> x * 2;
System.out.println(inc.then(dbl).apply(5));
}
}staticメソッドも使用可能
staticメソッドは、Function.identity()と同じようにファクトリとして機能します。
@FunctionalInterface
interface Mapper {
int map(int x);
static Mapper identity() {
return x -> x;
}
}
public class Main {
public static void main(String[] args) {
System.out.println(Mapper.identity().map(99));
}
}チェック例外の送出
抽象メソッドがチェック例外を宣言している場合、ラムダからその例外を送出できます。組み込みのFunctionではこれができないため、独自のインターフェースを定義する理由の1つになります。
@FunctionalInterface
interface RiskyParser {
int parse(String s) throws NumberFormatException;
}
public class Main {
public static void main(String[] args) {
RiskyParser p = Integer::parseInt;
System.out.println(p.parse("77"));
}
}カスタムインターフェースをメソッドに渡す
独自のインターフェースをパラメーター型として使うことで、呼び出し側がラムダで動作を提供できるようになります。
@FunctionalInterface
interface IntCombiner {
int combine(int a, int b);
}
public class Main {
static int reduce(int[] arr, IntCombiner c) {
int acc = arr[0];
for (int i = 1; i < arr.length; i++) acc = c.combine(acc, arr[i]);
return acc;
}
public static void main(String[] args) {
int[] data = {1, 2, 3, 4};
System.out.println(reduce(data, (a, b) -> a + b));
}
}3引数のインターフェース
JDKに用意されているのは、1引数および2引数のインターフェースだけです。3つ以上の引数を扱う場合は、独自のインターフェースを定義してください。
@FunctionalInterface
interface TriFunction<A, B, C, R> {
R apply(A a, B b, C c);
}
public class Main {
public static void main(String[] args) {
TriFunction<Integer, Integer, Integer, Integer> sum3 = (a, b, c) -> a + b + c;
System.out.println(sum3.apply(1, 2, 3));
}
}メソッド参照はカスタムインターフェースに適合する
SAMとシグネチャが一致するメソッドは、メソッド参照として渡せます。
@FunctionalInterface
interface StringTest {
boolean check(String s);
}
public class Main {
public static void main(String[] args) {
StringTest blank = String::isBlank;
System.out.println(blank.check(" "));
}
}匿名クラスとラムダ
ラムダは、関数型インターフェースを実装する匿名クラスを簡潔に置き換えるものです。どちらも同じ動作を実現します。
@FunctionalInterface
interface Action {
void run();
}
public class Main {
public static void main(String[] args) {
Action old = new Action() {
public void run() { System.out.println("anonymous"); }
};
Action neo = () -> System.out.println("lambda");
old.run();
neo.run();
}
}理解度チェック
@FunctionalInterfaceは何を保証しますか。
まとめ
独自の関数型インターフェースを定義しました。
- 関数型インターフェースには抽象メソッド(SAM)がちょうど1つあります。
@FunctionalInterfaceはコンパイル時にこの規則を適用します。- defaultメソッドとstaticメソッド、ジェネリクス、チェック例外はすべて使用できます。
- カスタムインターフェースは、3引数の関数やチェック例外を扱うラムダなど、JDKでカバーされていない用途を補います。
よくある質問
「カスタム関数型インターフェース」レッスンは無料ですか?
はい。「カスタム関数型インターフェース」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「カスタム関数型インターフェース」で何を学びますか?
@FunctionalInterface で独自に定義します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「カスタム関数型インターフェース」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Function と BiFunction
- Supplier と Consumer
- Predicate と合成
- カスタム関数型インターフェース