こんな感じになった。
import java.util.function.Function;
import java.util.function.BiFunction;
interface F1<T, R> extends Function<T, R> {
}
interface F2<T, U, R> extends BiFunction<T, U, R> {
default F1<U, R> apply(T p1) {
return p2 -> apply(p1, p2);
}
}
interface F3<T, U, V, R> {
R apply(T t, U u, V v);
default F2<U, V, R> apply(T p1) {
return (p2, p3) -> apply(p1, p2, p3);
}
}
public final class PartialTest {
public static void main(final String[] args) {
F3<Integer, String, Integer, Integer> f3 =
(n, s, i) -> String.format("%d%s", n, s).length() + i;
System.out.println(f3.apply(100, "test", 1)); // 8
F2<String, Integer, Integer> f2 = f3.apply(1000);
System.out.println(f2.apply("test", 2)); // 10
F1<Integer, Integer> f1 = f2.apply("abcde");
System.out.println(f1.apply(3)); // 12
System.out.println(
f3.apply(777).apply("ab").apply(12340));// 12345
}
}
- Java8 標準の関数インターフェイスとぜんぜん別系統にしても良かったが、ここでは extends させた。例えば、すでに Function/BiFunctionを使っているアプリケーションに追加するような場合、こうした方が既存コードとの相性が良いと思う。
- F1、F2、F3 って型名は、「単語は省略すべきじゃない」って原則に反するけど、意味は自明だしこだわらないことにした。そもそも、このレベルの抽象度の高さだとほとんど具体性とか問われないと思うし。FunctionalJava もこんな感じだった。
- apply() も、もっと抽象的で記号っぽいメソッド名でもよかったけど、ここは Function の既存メソッドに合わせた。
- F1 は Functionと同じだけど、F2、F3と合わせるために敢えて extends した。Function<T, R> が持っている R apply(T) をそのまま用いる。
- F2 は BiFunction を extends した。ただし、BiFunction<T, U, R> には、R apply(T, U) があるが、部分適用がないので default メソッドとして定義した。
- F3 は 適当な基底インターフェイスが無いので、全引数を与えて最終的な値を得るメソッドと、第一引数だけ部分適用するメソッドを持つクラスを作った。
同じ要領で F4以上でも書ける(「パラメータが多すぎる関数っていかがなものか」ってのは別にすれば)。
0 件のコメント:
コメントを投稿