CodilityのLesson6のNumberOfDiscIntersectionsをJavaで解答していたときに、ラムダ式利用時に性能が劣化する現象を確認したので共有する。
注意:以下、上記問題に対する解答例がGitHubのリンク先に含まれます。
ラムダ式利用時
最初の解答では以下のようにラムダ式を利用した。
ラムダ式利用時のソースコード
Nが大きいときにパフォーマンスのスコアが基準を満たしていないことが確認される。
匿名クラス利用時
性能改善を試みて試行錯誤しているうちに、以下のようにラムダ式から匿名クラスを利用するように修正した。
匿名クラス利用への修正
ミリ秒単位ではあるが、パフォーマンスが改善していることが確認される。
結果と考察
ラムダ式を利用すると、匿名クラスを利用した時と比較してパフォーマンスが劣化する場合があることがわかった。これはすなわち性能がシビアに求められるケースでは、ラムダ式を利用してリファクタリングするときは性能のリグレッションテストも必要になる可能性を示唆する。
関連情報をインターネットで探してみると、例えばJava それぞれ書き方でどれほどパフォーマンスが違うのか?計測比較してみた。Streamとループとか - Qiitaには、ラムダ式により性能が改善する、または差異がない、と書かれている。しかしJava:ラムダは遅い? - 開発メモには、ラムダ式により性能が劣化する、と書かれている。
ラムダと invokedynamic の蜜月によれば、匿名クラスの実行時間増加要因がI/Oとjarの解凍であるのに対し、ラムダ式の実行時間増加要因がブートストラップメソッド呼び出しとバイトコードの生成であり、前者の和が後者の和より小さい(リンク先スライド38ページ)ためではないかと考えられる。
今回の場合だと、匿名クラスはクラスの生成が実行前になされて計測の対象外となったのに対し、ラムダのクラスはクラスの生成が実行時になされたため、その分だけ性能が劣化した、と考えられる。
...正直あまり自信はないので、もし何かしらご指摘あればご教授いただけると幸いです。