ラムダ式を利用する
- (type args, …) -> { statements }
- type:引数の型
- args:引数の名前
- statements:処理本体
ラムダ式はJavaSE 8から導入された構文で、大雑把にいうならば、メソッドをシンプルに表すための構文です。
例えば、「無名クラスを定義する」項の無名クラスをラムダ式で書き換えた例です。
AnonymousSample.java
package com.example.mynavi.object; public class AnonymousSample { public static void main(String[] args) { IPrintable p = () -> { System.out.println("TEST"); }; p.print(); // 結果:TEST } }
ラムダ式で実装できるのは、関数型インターフェイスのメソッドです。この例であれば、IPrintableインターフェイスのprintメソッドをラムダ式で実装しているわけです。
関数型インターフェイス
関数型インターフェイスとは、メソッドを一つしかもたないインターフェイスのことです。@FunctionalInterfaceアノテーションを利用して、明示的に宣言することもできます。
@FunctionalInterface public interface IPrintable { void print(); }
@FunctionalInterfaceアノテーションを付与した場合、インターフェイスがメソッドを複数持つなど、関数型インターフェイスの要件を満たさない場合に、コンパイルエラーを返すことができます。
ラムダ式のさまざまな記法ラムダ式は特定の条件を満たす場合に、さまざまな省略記法を用いることができます。たとえば、以下のようなラムダ式があったとします。
SampleInterface hoge = (String str) -> { return str + str; };
これは、まず以下のように書き換えることができます。
SampleInterface hoge = (str) -> { return str + str; };
ラムダ式では引数の型をインターフェイスの定義から推論しますので、省略できます。これを型推論と言います。
そして、引数がひとつの場合には、引数を括るカッコも省略できます(引数が複数、またはゼロの場合には省略できません)。
SampleInterface hoge = str -> { return str + str; };
最後に、処理本文がreturnの1文だけの場合は、{…}とreturnを省略できます。
SampleInterface hoge = str -> str + str;
いかがですか。最初のラムダ式に比べると、ぐんとコードがシンプルになったことが確認できるでしょう。このように、ラムダ式では条件次第でさまざまな記法があるので、理屈も理解しながら、それぞれの記法に慣れていきましょう。
ラムダ式を利用したAPIラムダ式の登場以降、コレクションフレームワークを中心に引数としてラムダ式を受け取るメソッドが増えています。たとえば、replaceAllメソッドはリスト内の要素を指定されたルール(ラムダ式)に基づいて置き換えます。
replaceAllメソッド- public default void replaceAll(UnaryOperator<E> operator)
- E:要素の型
- operator:変換ルールを表すラムダ式
たとえば以下は、「あ」で始まる単語の先頭に「*」を付与する例です。
LambdaReplace.java
package com.example.mynavi.object; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class LambdaReplace { public static void main(String[] args) { List<String> list = new ArrayList<>( Arrays.asList("あかさか", "さくらぎちょう", "よよぎ", "あおもり") ); list.replaceAll(str -> { if(str.startsWith("あ")) { return "*" + str; } else { return str; } }); System.out.println(list); // 結果:[*あかさか, さくらぎちょう, よよぎ, *あおもり] } }
引数operatorは、
・引数として個々の要素(str)を受け取り、
・戻り値として変換結果を返す
ラムダ式です。引数operatorの型UnaryOperatorは、「引数1個と、同じ型の戻り値を持つ」関数型インターフェイスを表しているわけです。
Javaでは、このようによく利用するラムダ式(関数型インターフェイス)を標準で用意しており、ほとんどの場合、自前で関数型インターフェイスを用意しなくても済むようになっています。以下に、主な関数型インターフェイスをまとめます。
分類 | インターフェイス | メソッド |
---|---|---|
XxxxxConsumer | void accept(xxxxx v) | |
BiConsumer<T,U> | void accept(T t, U u) | |
値を返す | Supplier<T> | T get() |
Function<T,R> | R apply(T t) | |
BiFunction<T,U,R> | R apply(T t, U u) | |
真偽値を返す | Predicate<T> | boolean test(T t) |
BiPredicate<T,U> | boolean test(T t, U u) | |
演算結果を返す | UnaryOperator<T> | T apply(T t) |
BinaryOperator<T> | T apply(T t, T u) |
▲主な関数型インターフェイス