プリミティブ特殊化型IntFunctionのメソッドはapplyかapplyAsIntか

# はじめに
Java SE 8 Goldを勉強していたときに、ややこしかったところなのでまとめ。
他のプリミティブ特殊型の関数型インタフェースについても触れている。
注）Gold受験者向けの内容
## 実は一言で解決する
この問題を解決するルールは、
**『戻り値の型が一つに決められた関数型インタフェースは、該当メソッド=基本のメソッド+As+戻り値の型となる』**
という一言に集約される。

java.util.function内の関数型インタフェースについて学習できる（私が勝手に作った）含蓄のある言葉なので、紐解いていこう。

# java.util.functionで用意されている基本の関数型インタフェースとメソッドの対応
まずは基本中の基本。ここを覚えておかないとGold取得はなかなか難しい。逆にここが分かれば、さっきの一文の半分は理解できたも同然である。

| 基本の関数型インタフェース | メソッド | 説明 |
|:-----------|:------------|:------------|
|Consumer\<T\>|void accept(T)|引数を受け取って処理を行い結果を返さない、<br>「消費者」|
|Function\<T,R\>|R apply(T t)|引数を受け取って、指定された型 (R)の結果を返す、<br>「処理」|
|Predicate\<T\>|boolean test(T t)|引数を受け取ってそれをboolean値で評価する、<br>「断定」|
|Supplier\<T\>|T get()|何も引数を受け取らずに結果だけを返す、<br>「供給者」|

### ここから分かってくる前提の話
さて、先ほどのルールを見返してみると「戻り値の型が一つに決められた〜〜」どうのこうの書いてある。
上の表をよく見てもらいたい。
``そもそも戻り値を返さない``
``戻り値の型を決めなくていい``
関数型インタフェースがあることに気づくだろう。
前者は``Consumer<T>``、後者は``Predicate<T>``であり、この二つはどうなるのか。

java.util.functionのJava SE APIドキュメントを見るとIntFunctionのようなプリミティブ特殊化型のIntConsumerやIntPredicateといった関数型インタフェースは存在している。では、applyAsIntのようにacceptAsIntやtestAsIntといったメソッドも存在しているのか？

答えはNoである。

**今回問題になるのは、Function\<T,R\>とSupplier\<T\>の関連のメソッドである**ことをまずは押さえて頂きたい。（Goldの問題では、acceptAsIntやtestAsIntなんて選択肢にすら出てこない）

# タイトルの問題を解いてみる
ここで本題に戻ろう。
Functionインタフェースのプリミティブ特殊化型であるIntFunctionのメソッドはただのapplyなのかapplyAsIntなのか・・・
ルールを読むと明白であるが、ポイントは``戻り値の型が決まっているかどうかである.``
これは関数型インタフェースの定義をジェネリクスまで見れば分かる。
Function関連のプリミティブ特殊化型には基本3パターンあるので、ここで確認してみよう。

```java
IntFunction<R>
ToIntFunction<T>
DoubleToIntFunction
```
上記のジェネリクスの意味と、引数・戻り値の型の関係をざっくりまとめると
``<R>:戻りの型を任意に決められる(引数はint型)``
``<T>:引数の型を任意に決められる（戻り値はint型）``
``ジェネリクスなし:引数も戻り値も型が決まっている（引数はdouble型、戻り値はint型）``
となる。

つまり、タイトルのIntFunctionのメソッドは戻り値の型を任意で決めることができるので、ただの``apply``
ToIntFunctionとDoubleToIntFunctionは戻り値の型がint型で決まっているので``applyAsInt``となるのだ。

もちろん、他のDoubleFunction（該当メソッドはapply）やToDoubleFunction(該当メソッドはapplyAsDouble)等々も、同じルールに従っている。

# IntSupplierのメソッドは？
次はIntSupplierのメソッドについて考えてみよう。
IntFunctionのメソッドがただのapplyだったことを考えると、
IntSupplierのメソッドもただのgetだと思うかもしれない。
**騙されてはいけない**

Supplierが何者であったかをよく思い出さなければならない。
Supplier\<T\>とは``何も引数を受け取らずに結果だけを返す、「供給者」``であった。
つまり、Supplier関連の関数型インタフェースには引数は存在しないのだから、プリミティブ特殊化型のIntSupplierでint型だと決めている部分は戻り値でしかありえないのである。

結果として``IntSupplierの該当メソッドはgetAsInt``ということになる。
**逆にいうと該当メソッドがgetとなるのは、Supplier系においてはSupplier\<T\>しか存在しない。**
~~(個人的にはSupplier\<T\>のジェネリクスはRにしたくなる）~~

# 応用問題
①BiFunction、②BinaryOperator、③IntBinaryOperator、④IntUnaryOperator、⑤ToDoubleBiFunction、それぞれの該当メソッドは何か？

まず①〜⑤はFuctionの特殊化型である。よって「〜該当メソッド=基本のメソッド+As+戻り値の型」の基本のメソッドの部分は``apply``となる。

**①BiFunction**
定義をジェネリクスまで書くと、``BiFunction<T,U,R>``
簡単にいうとFunction\<T,R\>の引数が二つに増えたバージョン。
戻り値は決まっていないので該当メソッドは``apply``（但し、引数は二つ存在する）

**②BinaryOperator**
定義をジェネリクスまで書くと``BinaryOperator<T>``
簡単にいうとBiFunctionの二つの引数、戻り値の型が全て同じ場合の関数型インタフェース。
BiFunction\<T,T,T\>と同義。
戻り値は決まっていないので該当メソッドは``apply``（但し、引数は二つ存在する）

**③IntBinaryOperator**
BinaryOperatorの二つの引数および戻り値がint型のバージョン。
戻り値がint型で決まっているので該当メソッドは ``applyAsInt``（二つの引数もint型）

**④IntUnaryOperator**
まず``UnaryOperator<T>``はFunctionの引数、戻り値の型が同じ場合の関数型インタフェース。
Function\<T,T\>と同義。
そのUnaryOperatorの引数および戻り値両方がint型のバージョン。
戻り値がint型で決まっているので該当メソッドは``applyAsInt``(引数もint型)

**⑤ToDoubleBiFunction**
定義をジェネリクスまで書くと``ToDoubleBiFunction<T,U>``
戻り値だけdouble型だと決まっているので該当メソッドは``applyAsDouble``（但し、引数は二つ存在する）

# 最後に
ここまで書いたが、実装するときはコンパイルエラーが出るので、こんなまどろっこしいこと考えなくてもいいはず。この記事がGoldの試験勉強、java.util.functionパッケージの理解につながれば幸いだ。

# 参考
[java.util.function以下の関数インターフェース使い方メモ](https://qiita.com/opengl-8080/items/22c4405a38127ed86a31)
[java.util.function (Java Platform SE 8 )](https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/package-summary.html)