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


## はじめに

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


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

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

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

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

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


## `@FunctionalInterface` アノテーション

* `@FunctionalInterface`は、関数型インタフェースとして明示するためのアノテーションです。
* これを付けることで、抽象メソッドが2つ以上定義された場合にコンパイルエラーとなり、安全性が高まります。

```java
@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の使用例

```java
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>` |


## 使用例

```java
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つだけ**であることが関数型インタフェースの条件です。


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

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

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

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