Javaではラムダ式という、メソッド内で特定の処理を行うような関数の実体を生成することが出来る書き方が用意されています。
簡単な関数であれば簡潔に書けるため、単純な処理を何度かメソッド内で使いまわしたい場合、ラムダ式を使うことで簡潔にコードを書くことが出来、コードが見やすくなるなどのメリットがある一方でデバッグ時にエラー個所を特定しにくくなるなどのデメリットもあります。
ラムダ式を使ったコードを見るとちょっと変な書き方をしているなと思われるかもしれませんが、この書き方を知っておくと役立つ機会があるかもしれないので、紹介しておきます。
ラムダ式を使うメリットとデメリット
ラムダ式を使うメリットには以下のものがあります。
- コードを短く簡潔に記述出来る
- コードの可読性が上がる
他にもメリットはありますが、抑えておきたいメリットはこの二つです。
簡素な処理をメソッドとして定義して、メソッドを参照するのが普通の方法ですが、そのメソッドが特定クラスの1つのメソッドでしか使われていない場合はわざわざメソッドにする必要がなく、ラムダ式を使うことで完結してしまいます。
また、ラムダ式を使うことで、コードの可読性も上がります。
簡単な処理であると書き方を省略できるので、シンプルで見やすいソースになります
一方で、ラムダ式を使うことで生まれるメリットや注意点は次のようなものがあります。
- デバッグがやりにくくなる
- 複雑な処理に対しては不適切
- Javaに慣れていない人には理解できないコードになる
- ラムダ式の外側の変数を使う場合は実質的にfinalな変数である必要があり、thisを使う場合も、ラムダ式の外側と内側では挙動が異なる
ラムダ式を使うと、スタックトレースが読みにくくなる可能性があります。
特に例外が発生した時、どこで例外が起きたのかを追うのが難しくなります。
また、ラムダ式は簡単な処理を書くのに適したものであり、複雑な処理を書くのには向いていません。
理由としては先述の例外の追跡の問題もありますが、複雑な処理を書くと単純に読みにくくなります。
どこまでが通常の処理で、どこまでがラムダ式なのか?
ラムダ式内に数十行から数百行の処理が書かれていると、分からなくなります。
ラムダ式の記載は自分の頭の中でどんな処理を行っているかが簡単にわかる処理にとどめておくべきものです。
ラムダ式は一般的なJavaのソースの書き方ではありません。
自分が現場で開発するソースで見たことがないだけかもしれませんが、そこそこの規模のコードであれば、誰にでも分かるようにラムダ式を使わないケースもあるようです。
ラムダ式はJavaについて知識がある人にとっては読みやすいコードになる一方で、Javaに対して知識が浅い人にとっては混乱を招く書き方です。
「これはどんな処理を行っているんですか?」
という質問が飛んで来るに間違いありません。
なので、読みやすくなるからという理由でラムダ式を多用するのは避けておいた方がいいでしょう。
ラムダ式内では、ラムダ式の外側の変数を使うことも出来ますが、この場合の変数は実質的にfinalなものではなければならないのも少し不便かもしれません。
finalであるということは値が変更できないということです。
外側の変数をラムダ式で扱う場合は値が代入される変数が使えないので、ここを意識しておかないとラムダ式を書く時に、「外側の変数を参照できない」と頭を抱えて半日ハマることになります。
ラムダ式の中でthisを使ってもラムダ式内部の変数を参照することが出来ません。
ラムダ式は独自のthisを持たないためです。
なので、外側のthisを参照するため、この挙動には注意が必要でしょう。
むしろ、ラムダ式の中ではthisを使わないよう、コーディングの際にルール付けをした方が、混乱を招くコードを記述せずに済むことでしょう。
実際にラムダ式を使った例
では、実際にラムダ式を使った処理を見てみましょう。
ラムダ式を使うと、以下のようにコードが書けるようになります。
//10を底とする1,000,000の対数を求める
long num = 1000000;
//ラムダ式の定義
LongToDoubleFunction f = (long n) -> {
return Math.log10(num);
};
//実際に定義したラムダ式に値を入れて処理を行う
double result = f.applyAsDouble(num);
//コンソールに出力を行う
System.out.println("通常のラムダ式の実行結果:" + result);
このコードでは対数を求める処理をラムダ式にして、ラムダ式を同一メソッド内で呼び出して計算を行ってみました。
ラムダ式を定義しているのは5~7行目で、処理を定義してfという名前を付けています。
そして、fと名前を付けたラムダ式に値を渡して計算を行い、最終結果をコンソールに出力してみます。
10を底とするのであれば、log101000000 =6となるはずなので、この処理の実行結果を見てみましょう。

ラムダ式が返す値の型がDoubleで、返す値を受け取る変数もDouble型なので小数点が表示されていますが、正しく計算がされていることが確認できました。
ラムダ式の表記の省略
ラムダ式の利点として、型の表記の省略や、括弧の省略、処理を囲む中括弧の省略などがあります。
例えば、上記のラムダ式の定義である
LongToDoubleFunction f = (long n) -> {
return Math.log10(num);
};
ですが、以下のように省略して書くことが出来ます。
//以下のように色々と省略できる
//1.型の省略
LongToDoubleFunction f1 = (n) -> {
return Math.log10(num);
};
//2.括弧の省略(引数が一つの場合のみ有効)
LongToDoubleFunction f2 = n -> {
return Math.log10(num);
};
//3.中括弧とreturnの省略(返す値が単一の場合のみ有効)
LongToDoubleFunction f3 = n -> Math.log10(num);
このように書き方を省略しても返ってくる値は同じで、必要に応じて書き方を省略できることは、ラムダ式を使う場合に自分の書きたい方法で柔軟に使えるという利点があります。
まとめ
今回はJavaのラムダ式についてお話ししました。
要点は以下の通りです。
- ラムダ式はメソッドの内部で関数の実体を作成するものである
- ラムダ式を使う利点としてコードを簡潔にし、可読性を上げることが挙げられる
- ラムダ式には複雑な処理の記述に向かない、デバッグの追跡が難しくなるなどデメリットもある
- そのようなデメリットを持っていても、ラムダ式はJavaの書き方として覚えておいた方がいい
ラムダ式は使いこなせば便利なものですが、Javaの初心者にとってはとっつきにくい書き方であり、コードを保守すする人のレベルに合わせて使うべきか、使わないべきか判断する必要があります。
また、ラムダ式に定義するのは簡潔な処理にした方が良く、ラムダ式内で別のメソッドを呼び出していたり、ライブラリのメソッドを呼び出すなどを行うと、逆に分かりづらいコードになってしまう可能性があります。
ですので、ラムダ式は使い方を選ぶ書き方と言っても良く、メリットとデメリットをしっかり理解して、使うかどうか判断する必要があります。
ラムダ式で書ける処理はラムダ式を使わなくても書ける処理でもあるので・・・。
今回の記事はここまでとなります。
また次の記事でお会いしましょう。