Help us understand the problem. What is going on with this article?

ラムダ式のオーバーロード時はどう動くのか検証してみた

More than 3 years have passed since last update.

Javaラムダ式がオーバーロードで定義されるとき、どんな動きをするのか

Javaのラムダ式はいままでのJavaの文法と違いかなり省略した書き方ができる。型を省略した書き方でメソッドがオーバーロード時ちゃんと呼ばれるか検証してみた。

メソッドがひとつしかないとき

Main.java
public class Main {

    public static void main(String[] args) {
        Main main = new Main();
        main.methodA(e -> "{" + e + "}");
    }

    void methodA(UnaryOperator<String> op){
        System.out.println("UnaryOperator<String> が呼ばれました");
        System.out.println(op.apply("MethodA"));
    }

}

実行結果

UnaryOperator<String> が呼ばれました
{MethodA}


ひとつしかないし、正しく呼ばれるのも当たり前かな


メソッドが複数定義されている場合(違う関数型インターフェースを使用した場合)

Main.java
public class Main {

    public static void main(String[] args) {
        Main main = new Main();
        main.methodA(e -> "{" + e + "}");
        main.methodA(e -> System.out.println(e));
    }

    void methodA(UnaryOperator<String> op){
        System.out.println("UnaryOperator<String> が呼ばれました");
        System.out.println(op.apply("MethodA"));
    }

    void methodA(Consumer<String> con){
        System.out.println("Consumer<String> が呼ばれました");
        con.accept("MethodA");
    }   
}

実行結果

UnaryOperator<String> が呼ばれました
{MethodA}
Consumer<String> が呼ばれました
MethodA

ラムダ式の何を引数にとって何の型を返すのかというのを自動的に判断してちゃんと選ばれたメソッドが呼ばれるようだ。


あえてUnaryOperatorとFunctionで同じ動きをさせてみる

UnaryOperatorは入力Tを入力して同じ型のTを返す関数型インターフェースで、FunctionはTを入力して違う型Rを返す関数型インターフェースである。あえてFunctionで同じ型を返すように定義すれば理論上どちらのメソッドでも適用可能である。その場合を検証してみた。

Main.java
public class Main {

    public static void main(String[] args) {
        Main main = new Main();
        main.methodA(e -> "{" + e + "}");
    }

    void methodA(UnaryOperator<String> op){
        System.out.println("UnaryOperator<String> が呼ばれました");
        System.out.println(op.apply("MethodA"));
    }

    void methodA(Function<String, String> func){
        System.out.println("Function<String, String> が呼ばれました");
        System.out.println(func.apply("MethodA"));
    }
}

実行結果

UnaryOperator<String> が呼ばれました
{MethodA}

両方でも解釈できそうなのでエラーになるかなと思ったものだけど、UnaryOperatorが呼ばれました。e -> "{" + e + "}"というラムダ式がUnaryOperatorに近いからそっちの方が呼ばれたのかな?

ちなみにに、あえて逆の方を呼び出したい時はキャストすればいいらしい

Main.java
public class Main {

    public static void main(String[] args) {
        Main main = new Main();
        main.methodA((Function<String, String>)e -> "{" + e + "}");
    }

    void methodA(UnaryOperator<String> op){
        System.out.println("UnaryOperator<String> が呼ばれました");
        System.out.println(op.apply("MethodA"));
    }

    void methodA(Function<String, String> func){
        System.out.println("Function<String, String> が呼ばれました");
        System.out.println(func.apply("MethodA"));
    }
}

実行結果

Function<String, String> が呼ばれました
{MethodA}

同じ入力、戻り値の関数型インターフェースを自力で定義してオーバーロードしちゃう

Main.java
public class Main {

    @FunctionalInterface
    interface myInterface<T>{
        T apply(T t);
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.methodA(e -> "{" + e + "}");
    }

    void methodA(UnaryOperator<String> op){
        System.out.println("UnaryOperator<String> が呼ばれました");
        System.out.println(op.apply("MethodA"));
    }

    void methodA(myInterface<String> my){
        System.out.println("myInterface<String> が呼ばれました");
        System.out.println(my.apply("MethodA"));
    }
}

流石にこれはコンパイルエラーになりました。入力の型と戻り値の型が完全に一致しているので判断できないっぽい。
なお、こうなってしまった場合先ほどのようにキャストすればOK

        main.methodA((UnaryOperator<String>)e -> "{" + e + "}");
//もしくは
        main.methodA((myInterface<String>)e -> "{" + e + "}");



そもそもキャストしなければならないラムダ式なんてラムダ式のメリットが薄くなっているので、こんな設計にしないようにすべきです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした