Javaでのラムダ式はinvokedynamicとMethodHandleを使って呼び出されますが、ラムダ式に書いた処理はコンパイラがメソッドに変換します。
僕はあーstaticメソッドになるんだよね、と感覚的にしか理解していなかったのですが、やってみるとそうでないものものあったので、まとめます。
単純にstaticメソッドに変換されるケース
public class Lambda { public static void main(String[] args) { Runnable r = () -> System.out.println("test"); Thread t = new Thread(r); t.start(); } }
ラムダ式で固定文字列を出力しているだけです。この場合、単純にstaticメソッドに変換されます。
$ javap -p -s -c -v Lambda
...
private static void lambda$main$0();
descriptor: ()V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=0, args_size=0
0: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #7 // String test
5: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 3: 0
ACC_SYNTHETICですので、これはコンパイラによって作成された、合成メソッドです。9年前触れていました。
引数ありのstaticメソッドに変換されるケース
public class Lambda2 { public static void main(String[] args) { String test = "test"; Runnable r = () -> System.out.println(test); Thread t = new Thread(r); t.start(); } }
ラムダ式でローカル変数を使うようにしました。この場合、変数はstaticメソッドの引数となるよう変換されます。
private static void lambda$main$0(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
7: return
LineNumberTable:
line 4: 0
インスタンスメソッドに変換されるケース
public class Lambda3 { public static void main(String[] args) { new Lambda3().test(); } void test() { Runnable r = () -> print(); Thread t = new Thread(r); t.start(); } void print() { System.out.println("test"); } }
ラムダ式でインスタンスメソッドを呼び出すようにしました。この場合、staticメソッドではなくインスタンスメソッドに変換されます。
private void lambda$test$0();
descriptor: ()V
flags: ACC_PRIVATE, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokevirtual #12 // Method print:()V
4: return
LineNumberTable:
line 7: 0
すべて当然といえばそうなのですが、何となくの理解はいけないですね。