😎
【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では、int
、long
、double
型に対応する専用インタフェースも提供されています。
型 | 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