Function インターフェース
変換のしかたが違うだけで、同じメソッドを 2 本書いている
社員名の一覧を受け取って、片方は全部大文字にして返す。もう片方は文字数に変換して返す。やりたい変換は違いますが、1 件ずつ取り出して結果を詰め直す部分はまったく同じです。このままだと、変換のパターンが 1 つ増えるたびにメソッドが 1 本ずつ増えていきます。
違うのは「1 つ受け取って、1 つ返す」中身だけです。その中身だけを外から渡せれば、詰め直す処理は 1 本で済みます。そのときに使う受け皿が java.util.function.Function<T, R> です。
変換の中身だけを変数に入れる
Function<T, R> は「T を 1 つ受け取って R を 1 つ返す」という意味の型です。<> の中は左が入力、右が出力の順に書きます。実際に動かす命令は apply の 1 つだけです。
Java
import java.util.function.Function;
public class Demo {
public static void main(String[] args) {
Function<String, String> upper = s -> s.toUpperCase();
Function<String, Integer> lengthOf = s -> s.length();
System.out.println(upper.apply("java")); // JAVA
System.out.println(lengthOf.apply("java")); // 4
}
}upper と lengthOf は中身がまったく違うのに、どちらも Function という同じ形の変数に入っています。だから「Function<String, String> を引数に取るメソッド」を 1 本用意しておけば、どの変換を使うかは呼ぶ側が選べます。関数を値として持ち回す、というのはこういうことです。
2 段の変換を、1 つにまとめる
「前後の空白を落としてから大文字にする」のように、変換が 2 段になることがあります。毎回 2 回 apply を呼んでもよいのですが、andThen を使うと 2 つの Function から新しい Function を 1 つ作れます。
Java
Function<String, String> trim = s -> s.trim();
Function<String, String> upper = s -> s.toUpperCase();
Function<String, String> clean = trim.andThen(upper);
System.out.println(clean.apply(" java ")); // JAVAa.andThen(b) は「先に a、その結果を b へ」という意味で、書いた順にそのまま流れます。元の trim と upper は書き換わらず、合成された新しい Function が返ってくるだけです。
整数を入れると Integer が返ってくる
Function<int, int> とは書けません。ジェネリクスはプリミティブ型を受け取れないので、整数を扱うときはラッパー型の Integer を書きます。
Java
Function<Integer, String> label = n -> n + " 件";
System.out.println(label.apply(12)); // 12 件そのため apply が返すのは int ではなく Integer です。戻り値の型が int のメソッドでそのまま return しても、アンボクシングが自動で Integer から int に直してくれるので、キャストを書く必要はありません。
速度が問題になる場面向けに、ボクシングを避ける
IntFunctionやIntUnaryOperatorといった整数専用の型も用意されています。名前だけ頭の隅に置いて、必要になったときに調べれば十分です。
課題では、整数を受け取って整数を返す Function を変数として 1 つ作り、apply に通した結果を返します。計算式を直接 return しても答えの数字は合いますが、それでは Function を経由したことになりません。必ず変数に入れてから apply を呼んでください。
要件
- ファイル先頭で
import java.util.function.Function;を書くこと - メソッド内で
Function<Integer, Integer> doubler = x -> x * 2;のようにラムダ式でFunctionを作ること doubler.apply(n)を呼び出し、その戻り値をintとしてreturnすること
入出力例
applyDouble(5) → 10
applyDouble(0) → 0
applyDouble(-3) → -6
applyDouble(100) → 200