BiFunction と 2 引数の関数
引数が 2 つになったとたん、Function では受けられない
Function<T, R> の apply は引数を 1 つしか取りません。ところが実際に渡したい処理は、姓と名をつなぐ、単価と個数から金額を出す、といった 2 引数のものが山ほどあります。
Function<String, String> f = (last, first) -> last + first; と書いてもコンパイルは通りません。ラムダの引数の数が、インタフェースが決めている数と合わないからです。引数を 2 つ受け取りたいなら、最初から 2 つ受け取る型を選びます。それが java.util.function.BiFunction<T, U, R> です。
型は「入力 2 つ」と「出力 1 つ」で 3 つ書く
BiFunction<T, U, R> は「T と U を受け取って R を返す」という意味です。<> の中は入力が 2 つ並んで、最後が戻り値です。動かす命令は Function と同じ apply で、こちらは引数を 2 つ渡します。
Java
import java.util.function.BiFunction;
public class Demo {
public static void main(String[] args) {
BiFunction<String, String, String> fullName = (last, first) -> last + " " + first;
BiFunction<String, Integer, String> repeat = (text, times) -> text.repeat(times);
System.out.println(fullName.apply("山田", "花子")); // 山田 花子
System.out.println(repeat.apply("ab", 3)); // ababab
}
}fullName は 3 つとも String、repeat は入力の 2 つ目だけ Integer です。入力の型は揃っていなくて構いません。ここで型を 2 つしか書かず BiFunction<String, String> としてしまうと「型パラメータが足りない」というエラーになります。戻り値の分を数え忘れるのが定番のつまずきです。
なお、入力 2 つと出力がすべて同じ型になるときは、BinaryOperator<T> という短い別名も使えます。書き味は同じで、型を 1 つ書くだけで済みます。
引数が 2 つ以上のラムダは、かっこを省けない
引数が 1 つのラムダは s -> s.trim() のようにかっこを省略できますが、2 つ以上では省略できません。
Java
BiFunction<String, String, String> ng = last, first -> last + first; // 文法エラー
BiFunction<String, String, String> ok = (last, first) -> last + first; // これが正しいJava
BiFunction<String, String, Boolean> sameLength = (a, b) -> a.length() == b.length();
System.out.println(sameLength.apply("java", "html")); // trueincompatible types や Lambda expression not expected here というエラーが出たときは、たいていインタフェースが決めている引数の数と、ラムダに書いた引数の数がずれています。まず両方の数を数え直すのが早道です。
標準ライブラリに用意されているのは 2 引数までです。
TriFunctionをimportしようとしても見つかりません。3 つ以上になったら、引数をひとまとめにしたレコードを作って 1 引数に畳むのが実務では読みやすくなります。
課題では BiFunction の変数を作り、apply に 2 つの引数を渡した結果を返します。計算を直接 return しても数字は合いますが、apply を経由させることが今回の目的です。
要件
- ファイル先頭で
import java.util.function.BiFunction;を書くこと - メソッド本体で
BiFunction<Integer, Integer, Integer>型の変数を(x, y) -> x + yのラムダで初期化すること sum.apply(a, b)のようにapplyを呼び出した戻り値をreturnすること (直接a + bを返さない)
入出力例
combine(3, 5) → 8
combine(0, 0) → 0
combine(-1, 1) → 0
combine(100, 250) → 350
combine(-7, -3) → -10