LoginSignup
14
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-09-05

はじめに

Java SE 8 Goldを勉強していたときに、ややこしかったところなのでまとめ。
他のプリミティブ特殊型の関数型インタフェースについても触れている。
注)Gold受験者向けの内容

実は一言で解決する

この問題を解決するルールは、
『戻り値の型が一つに決められた関数型インタフェースは、該当メソッド=基本のメソッド+As+戻り値の型となる』
という一言に集約される。

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

java.util.functionで用意されている基本の関数型インタフェースとメソッドの対応

まずは基本中の基本。ここを覚えておかないとGold取得はなかなか難しい。逆にここが分かれば、さっきの一文の半分は理解できたも同然である。

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

ここから分かってくる前提の話

さて、先ほどのルールを見返してみると「戻り値の型が一つに決められた〜〜」どうのこうの書いてある。
上の表をよく見てもらいたい。
そもそも戻り値を返さない
戻り値の型を決めなくていい
関数型インタフェースがあることに気づくだろう。
前者は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パターンあるので、ここで確認してみよう。

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以下の関数インターフェース使い方メモ
java.util.function (Java Platform SE 8 )

14
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
4