Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

メソッド参照をRunnable型の変数に代入する

こんなことができるのを知りませんでした。

public class MethodReferenceSample {

    private void method1() { }

    public static void main(String[] args) {

        Runnable method1 = new MethodReferenceSample()::method1;

    }
}

メソッド参照の値をRunnable型の変数に代入できるんですね。

jls-15.13.2にも記載がありました。

These compatibility rules provide a convenient facility for converting from one functional interface to another:

Task t = () -> System.out.println("hi");

Runnable r = t::invoke;

https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13.2

これはstaticメソッドにも適用できますし、戻り値があるメソッドにも適用できます(戻り値は捨てることになりますが)。

public class MethodReferenceSample {

    private void method1() { }

    private static void method2() { }

    private String method3() { return "test"; }

    public static void main(String[] args) {
        Runnable method1 = new MethodReferenceSample()::method1;
        Runnable method2 = MethodReferenceSample::method2;
        Runnable method3 = new MethodReferenceSample()::method3;
    }
}

コンパイルエラーとなるパターン

Runnableに代入する以上、引数のあるメソッドの参照はダメです。

public class MethodReferenceSample {

    private void method1(String s) { }

    public static void main(String[] args) {
        Runnable method1 = new MethodReferenceSample()::method1;
    }
}

$ javac MethodReferenceSample.java
MethodReferenceSample.java:6: エラー: 不適合な型: メソッド参照が無効です
        Runnable method1 = new MethodReferenceSample()::method1;
                           ^
    クラス MethodReferenceSampleのメソッド method1は指定された型に適用できません
      期待値: String
      検出値: 引数がありません
      理由: 実引数リストと仮引数リストの長さが異なります
エラー1