こんにちは、Sawa です。
前回のブログでは関数型インタフェースとは何かについて学びました。 まだ読んでいない方はこちらから読んでみてください 。
【Java】関数型インタフェースを理解しよう(Steram 理解への道1)
今回は java.util.function にある関数型インタフェースを使ってみようと思います。
今回紹介する関数型インタフェースの動作や使い方を学ぶことで Stream への理解が進みます。
さっそく使ってみましょう!
前提知識
- 関数型インタフェースの定義
- ジェネリクス(List が使えればとりあえず OK)
java.util.function って?
java.util.function は関数型インタフェースをまとめたパッケージです。
ぜひ公式のドキュメントを参照してみてください。
パッケージjava.util.function
よく使われるインタフェースは以下の4つです。
この4つのインタフェースを見て、なんか難しそうだなぁ と思うかもしれないですが、心配無用です。 ちゃんと学ぶとめちゃめちゃ簡単です! 目を背けずに一つ一つ丁寧に見ていきましょう!
Function<T,R>
Function<> 内の左の T が引数として渡す型、右の R が戻り値の型です。 そう、Function は一つの引数を受け取り、戻り値を返すインタフェースです。 そしてこの Function がもつただ一つの抽象メソッドは apply() です。 コードで見てみましょう。
import java.util.function.Function;
public class Main {
public static void main(String[] args){
Function<Integer,String> func = (Integer num) -> {return num.toString();};
System.out.println(func.apply(4)); // 4 を表示
}
}
このコードは apply() を Integer 型で受け取った数字を文字列にして返すように実装したものです。 Function<T,R> が Function<Integer,String> となっており、もちろん引数にとる型と戻り値の型は自分で設定できます。 こうみると結構簡単だと思います。 Function は引数を一つ取り、戻り値を返すものと覚えればいいだけです。 そして、apply() を実行すれば実装したメソッドを実行できます。
java.util.function の関数型インタフェースを学ぶ上での大事なことは引数と戻り値の有無です。
上のコードだけではあまり理解できなかった方向けに Functioon に似たインタフェースを自分で作ってみます。 それがこちらです。
public class Main implements Function<Integer,String>{
public static void main(String[] args){
Main main = new Main();
System.out.println(main.apply(4)); // 4 を表示
}
@Override
public String apply(Integer arg) {
return arg.toString();
}
}
interface Function<T,R>{
R apply(T arg);
}
今回 java.util.function パッケージをインポートしていないので Function は自分で定義したものです。 またT と R が出てきていますが、implements するときに自分好みの型に置き換えています。 Function である程度使い方がわかったら残りの関数型インタフェースも見てみましょう。
Supplier<T>
Function は引数を一つ取り、戻り値を返すインタフェースでしたが、Supplier は引数なしで戻り値を返すメソッドを持つインタフェースです。
T には戻り値の値を指定します。
そして、Supplier がもつただ一つの抽象メソッドは get() です。 例によってget () の中身をコードで書いていきます。
public class Main {
public static void main(String[] args){
Supplier<Integer> sup = () -> {return 10;};
System.out.println(sup.get()); // 10 を表示
}
}
はい、これだけです。 今回は戻り値に Integer 型を指定しました。 sup.get() はただ 10 を返すだけのメソッドです。 とてもシンプルですごく簡単だと思います。 また、引数はないので () の中身も空になっています。
このインタフェースは簡単だと思いますので次に進みましょう。
Consumer<T>
Supplier は引数なしで戻り値を返すインタフェースでしたが、Consumer は引数ありで戻り値なしのメソッドを持つインタフェースです。
T には引数の型を指定します。
そして、Consumer がもつただ一つの抽象メソッドは accept() です。 こちらも例によって accept の中身をコードで書いていきます。
import java.util.function.Consumer;
public class Main {
public static void main(String[] args){
Consumer<Integer> con = (Integer num) -> {System.out.println(num * 10);};
con.accept(3); // 30 を表示
}
}
Function や Supplier の使い方を理解できている方であればこちらもすごく簡単に理解できるかと思います。 今回も引数の型は Integer を指定し、引数で受け取った数字を10倍にして表示する実装にしました。 見ての通り戻り値はなく、処理した数字を表示しているだけです。 ここまできたら関数型インタフェースって簡単だなと感じてきたのではないでしょうか?
では今回最後のインタフェースを見ていきましょう!
Predicate<T>
Predicate はこれまでのものとは少し違うます。
これは一つの引数を取り、boolean を返します。つまり、すでに戻り値の型は決まっているのです。
T には引数の型を指定します。
Predicate がもつただ一つの抽象メソッドは test() です。 では、さっそくコードを見てみましょう。
import java.util.function.Predicate;
public class Main {
public static void main(String[] args){
Predicate<Integer> pre = (Integer num) -> {return num > 10;};
System.out.println(pre.test(3)); // false を表示
System.out.println(pre.test(11)); // true を表示
}
}
今回も引数に Integer 型を指定し、引数に渡した値が 10より大きいかどうかを評価するメソッドにしました。 正直これまでの3つの関数型インタフェースは使い所があまり思い浮かばなそうでしたが、Predicate は結構使う場面がありそうな感じがしますよね。
さいごに
みなさんいかがだったでしょうか?
関数型インタフェースの抽象メソッドの中身を実装できるようになることが今回のゴールです。
次はいよいよラムダ式について学んでいきます。
【Java】ラムダ式の書き方を理解しよう(Stream 理解への道3)