Javaの関数型インターフェースについて。
|
|
関数型インターフェースは、ラムダ式やメソッド参照の代入先になれるインターフェースのこと。
関数型インターフェースの条件は、大雑把に言って、定義されている抽象メソッドが1つだけあるインターフェース。
staticメソッドやデフォルトメソッドは含まれていても構わない(関数型インターフェースの条件としては無視される)。
また、Objectクラスにあるpublicメソッドがインターフェース内に抽象メソッドとして定義されている場合、そのメソッドも無視される。
(この条件を満たすインターフェースを、JDK1.8で「関数型インターフェース」と呼ぶようになった)
// このsubmitメソッドの引数はCallable<Integer>であり、 // Callableインターフェースはcallメソッドだけしか定義されていないので、関数型インターフェースとして扱える。 // したがって、ラムダ式を渡すことが出来る。 ExecutorService pool = Executors.newSingleThreadExecutor(); try { Future<Integer> future = pool.submit(() -> { System.out.println("hoge"); return 123; }); int result = future.get(); } finally { pool.shutdownNow(); }
// Collections.sortメソッドの第2引数はComparatorインターフェースであり、 // Comparatorには抽象メソッドはcompareしか定義されていないので、関数型インターフェースとして扱える。 // したがって、ラムダ式を渡すことが出来る。 List<Integer> list = Arrays.asList(1, 3, 2); Collections.sort(list, (o1, o2) -> Integer.compare(o1, o2));
// List#forEachメソッドの引数はConsumerインターフェースであり、 // Consumerインターフェースには抽象メソッドはacceptしか定義されていないので、関数型インターフェースとして扱える。 // したがって、メソッド参照を渡すことが出来る。 List<Integer> list = Arrays.asList(1, 3, 2); list.forEach(System.out::println);
関数型インターフェースの条件を満たしたインターフェースであれば、自動的に関数型インターフェースとして使用できる。
しかし、インターフェースを関数型インターフェースとして定義したい場合は、java.lang.FunctionalInterfaceアノテーションを付けるのが良い。
FunctionalInterfaceアノテーションを付けていると、関数型インターフェースの条件を満たしていない場合にコンパイルエラーになってくれる。
(また、このアノテーションが付いていれば、関数型インターフェースを目的としていることが分かりやすい)
@FunctionalInterface public interface FuncInterfaceExample { public int example(int n); }
ラムダ式やメソッド参照を受け取れるようにしたいメソッドは、関数型インターフェースの条件を満たすようなインターフェースを受け取るように作ればよい。
戻り型 自メソッド名(関数型インターフェース 引数, …) { 〜 }
自分が欲しい目的に応じて、インターフェースを作成する。
しかし、個別にインターフェースを作らなくても汎用的に使える関数型インターフェースが用意されている。
場合によってはそれを使うのが良いだろう。
参考: irxgroundさんのJava8 ラムダ式用のクラス
引数と戻り型 | 関数型インターフェース | 備考 | |||
---|---|---|---|---|---|
() |
T |
java.util.function |
Supplier |
T get() |
Supplier(get)系。 (引数なしで)値を返す。 基本的には固定値を返すことに使う。 (いわゆる「遅延評価」用) |
() |
boolean |
java.util.function |
BooleanSupplier |
boolean getAsBoolean() |
|
() |
int |
java.util.function |
IntSupplier |
int getAsInt() |
|
() |
long |
java.util.function |
LongSupplier |
long getAsLong() |
|
() |
double |
java.util.function |
DoubleSupplier |
double getAsDouble() |
|
() |
void |
java.lang |
Runnable |
void run() |
|
(T) |
void |
java.util.function |
Consumer |
void accept(T t) |
Consumer(accept)系。 処理を行う(値を返さない)。 |
(int) |
void |
java.util.function |
IntConsumer |
void accept(int value) |
|
(long) |
void |
java.util.function |
LongConsumer |
void accept(long value) |
|
(double) |
void |
java.util.function |
DoubleConsumer |
void accept(double value) |
|
(T, U) |
void |
java.util.function |
BiConsumer |
void accept(T t, U u) |
|
(T, int) |
void |
java.util.function |
ObjIntConsumer |
void accept(T t, int value) |
|
(T, long) |
void |
java.util.function |
ObjLongConsumer |
void accept(T t, long value) |
|
(T, double) |
void |
java.util.function |
ObjDoubleConsumer |
void accept(T t, double value) |
|
(T) |
boolean |
java.util.function |
Predicate |
boolean test(T t) |
Predicate(test)系。 条件判定する(booleanを返す)。 |
(int) |
boolean |
java.util.function |
IntPredicate |
boolean test(int value) |
|
(long) |
boolean |
java.util.function |
LongPredicate |
boolean test(long value) |
|
(double) |
boolean |
java.util.function |
DoublePredicate |
boolean test(double value) |
|
(T, U) |
boolean |
java.util.function |
BiPredicate |
boolean test(T t, U u) |
|
(T) |
R |
java.util.function |
Function |
R apply(T t) |
Function(apply)系。 引数を受け取り、任意のクラスを返す。 |
(int) |
R |
java.util.function |
IntFunction |
R apply(int value) |
|
(long) |
R |
java.util.function |
LongFunction |
R apply(long value) |
|
(double) |
R |
java.util.function |
DoubleFunction |
R apply(double value) |
|
(T, U) |
R |
java.util.function |
BiFunction |
R apply(T t, U u) |
|
(T) |
int |
java.util.function |
ToIntFunction |
int applyAsInt(T value) |
ToIntFunction(apply)系。 引数を受け取り、intを返す。 |
(long) |
int |
java.util.function |
LongToIntFunction |
int applyAsInt(long value) |
|
(double) |
int |
java.util.function |
DoubleToIntFunction |
int applyAsInt(double value) |
|
(T, U) |
int |
java.util.function |
ToIntBiFunction |
int applyAsInt(T t, U u) |
|
(T) |
long |
java.util.function |
ToLongFunction |
long applyAsLong(T value) |
ToLongFunction(apply)系。 引数を受け取り、longを返す。 |
(int) |
long |
java.util.function |
IntToLongFunction |
long applyAsLong(int value) |
|
(double) |
long |
java.util.function |
DoubleToLongFunction |
long applyAsLong(double value) |
|
(T, U) |
long |
java.util.function |
ToLongBiFunction |
long applyAsLong(T t, U u) |
|
(T) |
double |
java.util.function |
ToDoubleFunction |
double applyAsDouble(T value) |
ToDoubleFunction(apply)系。 引数を受け取り、doubleを返す。 |
(int) |
double |
java.util.function |
IntToDoubleFunction |
double applyAsDouble(int value) |
|
(long) |
double |
java.util.function |
LongToDoubleFunction |
double applyAsDouble(long value) |
|
(T, U) |
double |
java.util.function |
ToDoubleBiFunction |
double applyAsDouble(T t, U u) |
|
(T) |
T |
java.util.function |
UnaryOperator |
T apply(T t) |
UnaryOperator(apply)系。 引数と同一の型を返す。 |
(int) |
int |
java.util.function |
IntUnaryOperator |
int applyAsInt(int operand) |
|
(long) |
long |
java.util.function |
LongUnaryOperator |
long applyAsLong(long operand) |
|
(double) |
double |
java.util.function |
DoubleUnaryOperator |
double applyAsDouble(double operand) |
|
(T, T) |
T |
java.util.function |
BinaryOperator |
T apply(T t, T u) |
BinaryOperator(apply)系。 引数(2つ)と同一の型を返す。 |
(int, int) |
int |
java.util.function |
IntBinaryOperator |
int applyAsInt(int left, int right) |
|
(long, long) |
long |
java.util.function |
LongBinaryOperator |
long applyAsLong(long left, long right) |
|
(double, double) |
double |
java.util.function |
DoubleBinaryOperator |
double applyAsDouble(double left, double right) |
Supplierは値を返す(供給する)為の関数型インターフェース。[2014-04-04]
引数なしで何らかの値を返す。返す値は呼ばれるごとに毎回異なっていても構わない(固定であることは要求されていない)。
@FunctionalInterface public interface Supplier<T> { // () -> T public T get(); }
プリミティブ型を扱うSupplierも用意されている。[/2014-04-13]
インターフェース名 | 関数としての型 | 説明 |
---|---|---|
Supplier<T> | () -> T |
Tを返す。 |
BooleanSupplier | () -> boolean |
booleanを返す。 |
IntSupplier | () -> int |
intを返す。 |
LongSupplier | () -> long |
longを返す。 |
DoubleSupplier | () -> double |
doubleを返す。 |
メソッド(例) | 実行結果(例) | 説明 | 同様のメソッドを持つ インターフェース |
|
---|---|---|---|---|
Supplier<String> s = () -> "abc"; |
abc |
ラムダ式を渡すようにしておくと、 getメソッドが呼ばれたときだけそのラムダ式が呼ばれる。 Loggerでは出力対象ログレベルによっては呼ばれないこともあるので、 重たい処理を行った結果を返す場合に有用。 実際に呼ばれるまで処理が行われないことになるので、 「遅延評価」と呼ばれる。 |
Supplier |
get |
List<String> list = Arrays.asList("a", "b"); |
情報: list=[a, b] |
Consumerは、引数を受け取り、それを使って処理を行う為の関数型インターフェース。[2014-04-04]
値を返さないので、基本的に副作用を起こす目的で使用する。
@FunctionalInterface public interface Consumer<T> { // (T) -> void public void accept(T t); 〜 }
プリミティブ型を扱うConsumerや引数を2つ受け取るConsumerも用意されている。[/2014-04-13]
インターフェース名 | 関数としての型 | 説明 |
---|---|---|
Runnable | () -> void |
|
Consumer | (T) -> void |
Tを受け取って処理する関数 |
IntConsumer | (int) -> void |
intを受け取って処理する関数 |
LongConsumer | (long) -> void |
longを受け取って処理する関数 |
DoubleConsumer | (double) -> void |
doubleを受け取って処理する関数 |
BiConsumer<T, U> | (T, U) -> void |
T,Uを受け取って処理する関数 |
ObjIntConsumer<T> | (T, int) -> void |
T,intを受け取って処理する関数 |
ObjLongConsumer<T> | (T, long) -> void |
T,longを受け取って処理する関数 |
ObjDoubleConsumer<T> | (T, double) -> void |
T,doubleを受け取って処理する関数 |
メソッド(例) | 実行結果(例) | 説明 | 同様のメソッドを持つ インターフェース |
|
---|---|---|---|---|
Consumer<String> c = s
-> System.out.println(s); |
abc |
printlnは値をコンソールに出力する(という副作用を起こしている)。 | Consumer |
accept |
Consumer<String> c1 = s
->
System.out.println("c1=" + s); |
c1=abc |
andThenメソッドで2つのConsumerをつなぐ。 つないだConsumerのacceptが順番に呼ばれる。 |
Consumer |
andThen |
Predicateは判定を行う為の関数型インターフェース。[2014-04-04]
引数を受け取り、判定を行い、真偽値(判定結果)を返す。
@FunctionalInterface public interface Predicate<T> { // (T) -> boolean public boolean test(T t); 〜 }
プリミティブ型を扱うPredicateや引数を2つ受け取るPredicateも用意されている。[/2014-04-13]
インターフェース名 | 関数としての型 | 説明 |
---|---|---|
Predicate<T> | (T) -> boolean |
Tを受け取って判定する関数 |
IntPredicate | (int) -> boolean |
intを受け取って判定する関数 |
LongPredicate | (long) -> boolean |
longを受け取って判定する関数 |
DoublePredicate | (double) -> boolean |
doubleを受け取って判定する関数 |
BiPredicate<T, U> | (T, U) -> boolean |
T,Uを受け取って判定する関数 |
メソッド(例) | 実行結果(例) | 説明 | 同様のメソッドを持つ インターフェース |
|
---|---|---|---|---|
Predicate<String> p = s
-> s.isEmpty(); |
false |
Predicate |
test |
|
Predicate<String> isEmpty = s
-> s.isEmpty(); |
true |
negateを使うと、条件判定を反転(否定)した関数を作れる。 | Predicate |
negate |
Predicate<String> isEmpty = s
-> s.isEmpty(); |
true |
Java11でPredicateにnotメソッドが追加された。[2018-10-01] (JavaのStreamにはScalaのfilterNotのようなメソッドは無いので、 stream.filter(Predicate.not(ラムダ式)) のようにして使う) |
||
IntPredicate p3 = n -> (n % 3) == 0; |
false |
2つのPredicateをandメソッドでつなぐと、 双方を満たしたときにtrueを返す関数になる。 これは「 && 」と同等であり、最初の条件が満たされなかったらその時点でfalseになる。 |
Predicate |
and |
IntPredicate p3 = n -> (n % 3) == 0; |
true |
2つのPredicateをorメソッドでつなぐと、 どちらかを満たしたときtrueを返す関数になる。 これは「 || 」と同等であり、最初の条件を満たしたらその時点でtrueになる。 |
Predicate |
or |
Predicate<String> p =
Predicate.isEqual("abc"); |
true |
isEqualメソッドを使うと、あるオブジェクトと等しいかどうかを返す関数を作れる。 isEqualの引数がnull以外だった場合は、オブジェクトのequalsメソッドで比較される。 isEqualの引数がnullだった場合は、testメソッドはnullかどうかを判定する。 |
||
Predicate<String> p =
Predicate.isEqual(null); |
false |
Functionは、値を変換する為の関数型インターフェース。[2014-04-04]
引数を受け取り、変換(演算)して別の値を返す。
@FunctionalInterface public interface Function<T, R> { // (T) -> R public R apply(T t); // TをRに変換する 〜 }
プリミティブ型を扱うFunctionや引数を2つ取るFunctionも用意されている。[/2014-04-13]
インターフェース名 | 関数としての型 | 説明 | 備考 |
---|---|---|---|
Function<T, R> | (T) -> R |
Tを受け取ってRを返す関数 | 引数の型と戻り型が同一の場合はUnaryOperatorを使う。 |
IntFunction<R> | (int) -> R |
intを受け取ってRを返す関数 | 戻り型もintの場合はIntUnaryOperatorを使う。 |
LongFunction<R> | (long) -> R |
longを受け取ってRを返す関数 | 戻り型もlongの場合はLongUnaryOperatorを使う。 |
DoubleFunction<R> | (double) -> R |
doubleを受け取ってRを返す関数 | 戻り型もdoubleの場合はDoubleUnaryOperatorを使う。 |
ToIntFunction<T> | (T) -> int |
引数を受け取ってintを返す関数 | |
ToLongFunction<T> | (T) -> long |
引数を受け取ってlongを返す関数 | |
ToDoubleFunction<T> | (T) -> double |
引数を受け取ってdoubleを返す関数 | |
(int) -> int |
intを受け取ってintを返す関数はIntUnaryOperator。 | ||
IntToLongFunction | (int) -> long |
intを受け取ってlongを返す関数 | |
IntToDoubleFunction | (int) -> double |
intを受け取ってdoubleを返す関数 | |
LongToIntFunction | (long) -> int |
longを受け取ってintを返す関数 | |
(long) -> long |
longを受け取ってlongを返す関数はLongUnaryOperator。 | ||
LongToDoubleFunction | (long) -> double |
longを受け取ってdoubleを返す関数 | |
DoubleToIntFunction | (double) -> int |
doubleを受け取ってintを返す関数 | |
DoubleToLongFunction | (double) -> long |
doubleを受け取ってlongを返す関数 | |
(double) -> double |
doubleを受け取ってdoubleを返す関数はDoubleUnaryOperator。 | ||
BiFunction<T, U, R> | (T, U) -> R |
引数を2つ受け取ってRを返す関数 | 全ての引数の型と戻り型が同一の場合はBinaryOperator。 |
ToIntBiFunction<T, U> | (T, U) -> int |
引数を2つ受け取ってintを返す関数 | 全ての引数の型と戻り型がintの場合はIntBinaryOperator。 |
ToLongBiFunction<T, U> | (T, U) -> long |
引数を2つ受け取ってlongを返す関数 | 全ての引数の型と戻り型がlongの場合はLongBinaryOperator。 |
ToDoubleBiFunction<T, U> | (T, U) -> double |
引数を2つ受け取ってdoubleを返す関数 | 全ての引数の型と戻り型がdoubleの場合はDoubleBinaryOperator。 |
メソッド(例) | 実行結果(例) | 説明 | 同様のメソッドを持つ インターフェース |
|
---|---|---|---|---|
Function<String, File> f = s
-> new File("/tmp",
s); |
/tmp/test.txt |
Function |
apply |
|
ToIntFunction<String> f = s
-> s.length(); |
3 |
ToIntFunction |
applyAsInt |
|
IntToLongFunction f = Integer::toUnsignedLong; |
4294967295 |
ToLongFunction |
applyAsLong |
|
IntToDoubleFunction f = n
-> Math.pow(2, n); |
8.0 |
ToDoubleFunction |
applyAsDouble |
|
Function<String, File> f1 = s
-> new File(s); |
[/tmp/test.txt] |
andThenメソッドでFunctionを渡すと、 1つ目のFunctionの結果を2つ目のFunctionに渡す。 |
Function |
andThen |
BiFunction<File, String, File> f1 = (f, s)
-> new File(f, s); |
||||
Function<String, File> f1 = s
-> new File(s); |
[/tmp/test.txt] |
composeメソッドで2つのFunctionをつなぐと、 先に2つ目のFunctionを処理し、 その結果を1つ目のFunctionに渡す。 |
Function |
compose |
Function<String, String> f = Function.identity(); |
abc |
identityメソッドは、「同じ値を返す関数」を返す。 「 s -> s 」と同じ。 |
Function |
identity |
UnaryOperatorは、単項演算子を表す関数型インターフェース。[2014-04-05]
引数を1つ受け取り、演算を行い、引数と同じ型の値を返す。
@FunctionalInterface public interface UnaryOperator<T> extends Function<T, T> { // (T) -> T // public T apply(T t); 〜 }
UnaryOperatorは特殊なFunctionである。
FunctionはT型を受け取ってR型(引数と異なる型)を返せるが、UnaryOperatorはT型を受け取ってT型を返すFunctionになっている。
プリミティブ型を扱うUnaryOperatorも用意されている。[/2014-04-13]
インターフェース名 | 関数としての型 | 説明 | 備考 |
---|---|---|---|
UnaryOperator<T> | (T) -> T |
Tを受け取ってTを返す関数 | Function<T, T>である。 |
IntUnaryOperator | (int) -> int |
intを受け取ってintを返す関数 | IntFunctionやToIntFunctionとは継承関係は無い。 |
LongUnaryOperator | (long) -> long |
longを受け取ってlongを返す関数 | LongFunctionやToLongFunctionとは継承関係は無い。 |
DoubleUnaryOperator | (double) -> double |
doubleを受け取ってdoubleを返す関数 | DoubleFunctionやToDoubleFunctionとは継承関係は無い。 |
メソッド(例) | 実行結果(例) | 説明 | 同様のメソッドを持つ インターフェース |
|
---|---|---|---|---|
UnaryOperator<String> op = s
-> s.toUpperCase(); |
ABC |
UnaryOperator |
apply |
|
DoubleUnaryOperator op = n
-> n * 1.08; |
540.0 |
|||
IntUnaryOperator op1 = n -> n * 10; |
21 |
andThenメソッドで2つのUnaryOperatorをつなぐと、 1つ目のUnaryOperatorの結果を2つ目のUnaryOperatorに渡す。 |
UnaryOperator |
andThen |
IntUnaryOperator op1 = n -> n * 10; |
30 |
composeメソッドで2つのUnaryOperatorをつなぐと、 2つ目のUnaryOperatorを先に処理し、 その結果を1つ目のUnaryOperatorに渡す。 |
UnaryOperator |
compose |
UnaryOperator<String> op = UnaryOperator.identity(); |
abc |
identityメソッドは、同じ値を返す関数。 「 s -> s 」と同じ。 |
UnaryOperator |
identity |
BinaryOperatorは、二項演算子を表す関数型インターフェース。[2014-04-05]
同じ型の2つの引数を受け取り、演算を行い、引数と同じ型の値を返す。
@FunctionalInterface public interface BinaryOperator<T> extends BiFunction<T,T,T> { // (T, T) -> T // public T apply(T left, T right); 〜 }
BinaryOperatorは特殊なBiFunctionである。
BiFunctionはT型,U型を受け取ってR型(引数と異なる型)を返せるが、BinaryOperatorはT型を2つ受け取ってT型を返すBiFunctionになっている。
プリミティブ型を扱うBinaryOperatorも用意されている。[/2014-04-13]
インターフェース名 | 関数としての型 | 説明 | 備考 |
---|---|---|---|
BinaryOperator<T> | (T, T) -> T |
Tを2つ受け取ってTを返す関数 | BiFunction<T, T, T>である。 |
IntBinaryOperator | (int, int) -> int |
intを2つ受け取ってintを返す関数 | ToIntBiFunctionとは継承関係は無い。 |
LongBinaryOperator | (long, long) -> long |
longを2つ受け取ってlongを返す関数 | ToLongBiFunctionとは継承関係は無い。 |
DoubleBinaryOperator | (double, double) -> double |
doubleを2つ受け取ってdoubleを返す関数 | ToDoubleBiFunctionとは継承関係は無い。 |
メソッド(例) | 実行結果(例) | 説明 | 同様のメソッドを持つ インターフェース |
|
---|---|---|---|---|
BinaryOperator<String> op = (s1, s2)
-> s1 + s2; |
abcdef |
BinaryOperator |
apply |
|
IntBinaryOperator op = Integer::sum; |
579 |
|||
LongBinaryOperator op = Long::max; |
456 |
|||
BinaryOperator<String> op =
BinaryOperator.minBy((s1, s2) -> s1.compareTo(s2)); |
abc |
与えられたComparatorを使用して、小さい方を返す。 | BinaryOperator |
minBy |
BinaryOperator<String> op =
BinaryOperator.maxBy((s1, s2) -> s1.compareTo(s2)); |
zzz |
与えられたComparatorを使用して、大きい方を返す。 | BinaryOperator |
maxBy |
JDK1.8でIntegerやLongクラスにsum(a, b)
やmax(a, b)
・min(a,
b)
というstaticメソッドが追加されたが、IntBinaryOperator等にメソッド参照として渡すことを想定しているのではないかと思う。
参考: opengl-8080さんのjava.util.function以下の関数インターフェース使い方メモ