😎

【Java Gold】関数型インタフェースについて

に公開

はじめに

関数型インターフェースについて、試験のために整理しました。

関数型インタフェースとは?

抽象メソッドが1つだけ定義されたインタフェースのこと。

この性質によって、ラムダ式メソッド参照を使って簡潔に実装できます。

@FunctionalInterface
public interface MyFunc {
    int apply(int x);
}

MyFunc f = x -> x * 2;
System.out.println(f.apply(3)); // 出力: 6

@FunctionalInterface アノテーション

  • @FunctionalInterfaceは、関数型インタフェースとして明示するためのアノテーションです。
  • これを付けることで、抽象メソッドが2つ以上定義された場合にコンパイルエラーとなり、安全性が高まります。
@FunctionalInterface
interface Converter<T, R> {
    R convert(T t);
    // void error(); // ← エラーになる
}

標準の関数型インタフェース一覧(java.util.functionパッケージ)

以下は代表的な関数型インタフェースの一覧です。

インタフェース名 引数 戻り値 メソッド名 説明
Runnable なし void run() 引数も戻り値もない処理(スレッドなど)
Callable<V> なし V call() 戻り値あり。例外もスロー可。非同期処理向け
Supplier<T> なし T get() 値を生成・供給する(遅延評価など)
Consumer<T> T void accept(T t) 値を受け取って処理する
BiConsumer<T, U> T, U void accept(T, U) 2つの引数を受け取って処理
Function<T, R> T R apply(T t) 入力を出力に変換する処理
BiFunction<T, U, R> T, U R apply(T, U) 2つの入力を1つの出力に変換
UnaryOperator<T> T T apply(T t) 入力と出力の型が同じFunction
BinaryOperator<T> T, T T apply(T, T) 同じ型の2値を同じ型で返す
Predicate<T> T boolean test(T t) 条件判定(真偽値)
BiPredicate<T, U> T, U boolean test(T, U) 2値に対する条件判定

CallableとRunnableの違い

特徴 Runnable Callable<V>
戻り値 なし (void) 任意の型 (V)
例外の扱い チェック例外はスローできない チェック例外をスロー可能
使用方法 Threadでそのまま利用可能 ExecutorService.submit()などで利用
主な用途 戻り値不要な非同期処理 戻り値のあるタスク処理

Callableの使用例

Callable<Integer> task = () -> {
    Thread.sleep(1000);
    return 42;
};

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(task);
System.out.println(future.get()); // 出力: 42(1秒後)
executor.shutdown();

プリミティブ型に特化した関数型インタフェース

Javaでは、intlongdouble型に対応する専用インタフェースも提供されています。

Supplier Consumer Predicate Function
int IntSupplier IntConsumer IntPredicate IntFunction<R>
long LongSupplier LongConsumer LongPredicate LongFunction<R>
double DoubleSupplier DoubleConsumer DoublePredicate DoubleFunction<R>

使用例

Function<String, Integer> strLength = s -> s.length();
System.out.println(strLength.apply("Java")); // 出力: 4

Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // 出力: true

Consumer<String> printer = s -> System.out.println(s);
printer.accept("Hello"); // 出力: Hello

関数型インタフェースのメリット

項目 説明
簡潔に記述できる ラムダ式やメソッド参照でコードが短くなる
再利用性が高い Stream APIなどと組み合わせて柔軟に使用可能
テストが容易 処理をオブジェクトとして渡せるためテストしやすい

注意点

  • defaultメソッドやstaticメソッドは複数あっても問題ありません。
  • 抽象メソッドが1つだけであることが関数型インタフェースの条件です。

自作の関数型インタフェース例

@FunctionalInterface
interface Calculator {
    int calc(int a, int b);
}

Calculator add = (a, b) -> a + b;
System.out.println(add.calc(3, 5)); // 出力: 8

おわりに

誤記や改善点があればコメントなどでご指摘ください。

Discussion