普段はスクリプト系言語使いです。
珍しくJavaを触る機会があったので、
うっすらしか知らなかったJavaのラムダ式について、
Java11リリースのご時世ではありますが確認の意味でまとめます。
1.ラムダ式導入以前
なんかすごいゲームの開発チームに入ったとします。
ユーザーの名前に関する部分を担当することになりました。
将来的にキャラごとに主人公に対する敬称が変わるので、そのあたりのAPIの整備を任されました。
名前のフォーマットを担当するインターフェースを定義します。
interface NameFormatter {
public abstract String format(String familyName, String firstName);
}
実装クラスとメイン実行部はこんな感じ。
class ChanFormatter implements NameFormatter {
@Override
public String format(String familyName, String firstName){
return firstName + "ちゃん";
}
}
class Main {
public static void main(String[] args){
String familyName = "伊達";
String firstName = "政宗";
NameFormatter nf = new ChanFormatter();
String formatted = nf.format(familyName, firstName);
System.out.println("こんにちは!" + formatted + "。");
System.out.println("なんかすごいゲームを始めるよ!");
}
}
実行結果はコチラ
こんにちは!政宗ちゃん。
なんかすごいゲームを始めるよ!
馴れ馴れしいですね。
逆に、仰々しいキャラのために別のフォーマッタも用意しましょう。
class DonoFormatter implements NameFormatter {
@Override
public String format(String familyName, String firstName){
return familyName + "殿";
}
}
メイン実行部でnewするクラスを変更するだけで呼び方も簡単に変えられます。
String familyName = "伊達";
String firstName = "政宗";
- NameFormatter nf = new ChanFormatter();
+ NameFormatter nf = new DonoFormatter();
String formatted = nf.format(familyName, firstName);
System.out.println("こんにちは!" + formatted + "。");
こんにちは!伊達殿。
なんかすごいゲームを始めるよ!
1.1.無名クラス
さて、なんかすごいゲームの開発チームをクビになったとします。
こんなに小さなクラス群の整備に人員コストをかけられないからです。
開発チームではフォーマッタを無名クラスを用いて実装することにしました。
このくらいの規模のクラスに対してひとつひとつファイルを作るのではなく、
その場で定義して使い捨てるための機能が無名クラスです。
無名クラスを使うと、以下の2つのファイルのみで済みます。
// 再掲
// 前述のものと同じ
interface NameFormatter {
public abstract String format(String familyName, String firstName);
}
class Main {
public static void main(String[] args){
NameFormatter chan = new NameFormatter(){
@Override
public String format(String familyName, String firstName){
return firstName + "ちゃん";
}
};
NameFormatter dono = new NameFormatter(){
@Override
public String format(String familyName, String firstName){
return familyName + "殿";
}
};
String familyName = "伊達";
String firstName = "政宗";
String formatted = chan.format(familyName, firstName);
System.out.println("こんにちは!" + formatted + "。");
System.out.println("なんかすごいゲームを始めるよ!");
}
}
変数に対してフォーマット方法が紐付いている形です。
2.ラムダ式
さて、本題のラムダ式です。
今回のような状況の場合、
NameFormatter
クラスが実装すべきメソッドはformat
のみです。
したがって、オーバーライドの対象はformat
メソッドしかありえません。
public String format(String familyName, String firstName)
といちいちコピペするのも冗長な気がします。コンパイラによろしくやって欲しい。
そんな要望を叶えられる記法がラムダ式です。以下のように書けます。
class Main {
public static void main(String[] args){
NameFormatter chan = (String familyName, String firstName) -> {
return firstName + "ちゃん";
};
NameFormatter dono = (String familyName, String firstName) -> {
return familyName + "殿";
};
String familyName = "伊達";
String firstName = "政宗";
String formatted = chan.format(familyName, firstName);
System.out.println("こんにちは!" + formatted + "。");
System.out.println("なんかすごいゲームを始めるよ!");
}
}
スッキリ書けました。以上。
3.それだけ?
ラムダ式についてはそれだけです。
ラムダ式自体はただの無名クラスの省略記法で、そんなに大きなトピックではありません。
本丸はラムダ式ではなく以下2点です。
- 関数型インタフェース(パッケージ
java.util.function
) - Java Stream API
今回、NameFormatter
というオリジナルなインターフェースを用いましたが、
ラムダ式を使うことが想定されたインターフェースが多数提供されています。
そのひとつがjava.util.function.Function<T,R>
です。
また、Java Stream APIとしてmap
やfilter
など関数型によくあるメソッドも多数追加されました。
それらのメソッドは、引数にjava.util.function
のインターフェースを渡して使います。
4.結論
ラムダ式はこわくない。
5.感想
Stream APIをスラスラ使いこなせるようにしたいなあ