ラムダは匿名クラスのシンタックスシュガーだとか言われますけど、オブジェクトの作られ方が違いますね。
というのを検証してみます。
(jdk1.8.0_112で動かしています)
ループの中でhogeにラムダを渡して、hogeでオブジェクトを表示します。
まず匿名クラスを使ったコード。
public class LambdaObj { public static void main(String[] args) { for (int i = 0; i < 2; ++i) { hoge(new Runnable() { @Override public void run() { } }); } } static void hoge(Runnable r) { System.out.println(r); } }
実行するとこう。
myproject.LambdaObj$1@15db9742 myproject.LambdaObj$1@6d06d69c
明確にnewしてるので、毎回違うオブジェクトが渡されています。
これをラムダにしてみます。
public class LambdaObj { public static void main(String[] args) { for (int i = 0; i < 2; ++i) { hoge(() -> {}); } } static void hoge(Runnable r) { System.out.println(r); } }
実行すると、こう。
myproject.LambdaObj$$Lambda$1/834600351@548c4f57 myproject.LambdaObj$$Lambda$1/834600351@548c4f57
オブジェクトが使いまわされていることがわかります。
ラムダと匿名クラスは違うということですね。
バイトコードとしては
private static void lambda$main$0() { //ラムダの中身 }
のようなメソッドが生成されて、invokeDynamicをよんでラムダオブジェクトを取ってくるようなコードが生成されます。このinvokeDynamicでいろいろやられているということですね。
めでたしめでたし。
ではなくて、もうちょっと調べてみます。
ラムダの中で、外側のローカル変数であるargsを使ってみます。
public class LambdaObj { public static void main(String[] args) { for (int i = 0; i < 2; ++i) { hoge(() -> { String[] a = args; }); } } static void hoge(Runnable r) { System.out.println(r); } }
そうすると、こう。
myproject.LambdaObj$$Lambda$1/834600351@1fb3ebeb myproject.LambdaObj$$Lambda$1/834600351@548c4f57
この場合は匿名クラスに展開されるのかなーと思ったけど
private static void lambda$main$0(String[]) { //ラムダの中身 }
のようなメソッドが定義されますね。
外側のローカル変数を使わない場合は簡易なオブジェクトを使っていて、外側のローカル変数を使う場合は引き渡すローカル変数のコピーをもったオブジェクトを渡さないといけないので毎回オブジェクトを生成してる、とかですかね。