今日のjavaおっかけ(20170929):ラムダ〜streamAPIのざっくり

基本

Runnableインタフェースをラムダの書き方で実装した場合。

            Runnable runnable1 = () ->{
                System.out.println("lambda!");
            };
            runnable1.run();
  • 結果
lambda!

Runnableはご存知の通りrunメソッドしかない。 戻り値と引数もない。

なので、上記のように、runメソッドの処理を特にrunというメソッドを宣言せずに実装できた。

関数型インタフェース 「引数とか戻り値ある場合はどうなる?」

関数型インタフェースという仕組みを使う。

この後のstreamAPIも絡むので、よく使われるであろう3つについてかく。

Function<T,R>

https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/Function.html

T は引数の型。R は戻り値の型を指定する。

Function<Integer, String> asterisker = (i) -> { return "*" + i; };
String result = asterisker.apply(10);
System.out.println(result);
  • 結果
*10

上記は10という数字を引数で渡して、アスタリスクの文字列を先頭に足して文字列を返す処理。

引数2つ渡したい!なんて場合は、BiFunctionなんてのもある。

https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/BiFunction.html

BiFunction<Integer, Integer, String> asterisker = (i, i2) -> { return "*" + (i * i2); };
String result = asterisker.apply(10, 2);
System.out.println(result);
  • 結果
*20

Consumer

https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/Consumer.html

T は引数の型。Functionの戻り値がない版?

Consumer<String> buyer = (goods) -> {
  System.out.println(goods + "を購入しました");
};
buyer.accept("おにぎり");
  • 結果
おにぎりを購入しました

Predicate

https://docs.oracle.com/javase/jp/8/docs/api/java/util/function/Predicate.html

T は引数の型。testメソッドは評価した結果をbooleanで返してくれる。

Predicate<String> buyer = (goods) -> {
  return goods.equals("おにぎり");
};
boolean result = buyer.test("おにぎり");
System.out.println(result);
  • 結果
true

Comparator として使う

関数型インタフェース、そもそもどういう使い方するの?ってところ。。

int[] numbers = {-1, 2, 0, -3, 8};
List<Integer> numbersList = new ArrayList<>();
for(int n : numbers){
  numbersList.add(n);
}

前提

まず数字が入ったリストを適当に用意した。この数字の順番をソートしたい。

Collections#sort の第二引数では、ソートする方法をComparatorで定義することができる。

本題

下記は、Comparatorをラムダで、小さい値→大きい値にソートするように書いた例。

Collections.sort(numbersList, (a, b) -> { return a - b; });

for(Integer n : numbersList) {
  System.out.print(n + ",");
}
  • 結果
-3,-1,0,2,8,

streamAPI

まず、リストなどの大元であるCollectionsstreamというメソッドがjava8から追加された。

Stream<E>を戻り値で返してくれる。

https://docs.oracle.com/javase/jp/8/docs/api/java/util/stream/Stream.html

先ほどと同じように、数値型のリストに適当な値を入れておきました。

int[] numbers = {-1, 2, 0, -3, 8};
List<Integer> numbersList = new ArrayList<>();
for(int n : numbers){
  numbersList.add(n);
}

forEarch

numbersList.stream().forEach((i) -> {
    System.out.print(i + ",");
});
  • 結果
-1,2,0,-3,8,

リストの中身が変数i に入ってくるので、それをsysoutしているだけのプログラム。

forEarchConsumerを受け取るので、 今回の数値の場合だと、Constumer<Integer>を受け取っていることになる。

filter

numbersList.stream().filter((i) -> {
    return i > 0;
}).forEach((i) -> {
    System.out.print(i + ",");
});
  • 結果
2,8,

意味の通り、フィルタリングしてくれる。

filterPredicateを受け取るので、 Predicateの中で評価してbooleanの値を返しtrueのものだけ抜粋する。

map

numbersList.stream()
  .filter((i) -> { return i > 0;})
  .map((i) -> {
    return "*" + i + "*"; })
  .forEach((s) -> {
    System.out.print(s + ","); });
  • 結果
*2*,*8*,

mapFunctionを受け取るので、 Functionの中で受け取った数値を文字列として返している。