白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

ラムダを引数にとるメソッドのオーバーロードってどうなるの?

こんにちは。

そんなに雨が好きなわけでもないですが、
こう暑さを実感すると、雨が降っていても涼しい方が幸せな気がします。
水不足ですしね。

さて、タイトルの通りです。
関数インタフェースのラッパーをつくろうかと思ったら、参照があいまいとか怒られてしまったので、
ラムダの型推論がどこまで効くのか確認してみようかと思います。

検証条件は

Java:1.8.0
IDENetBeans IDE 8.1

です。

では、早速こんな感じでクラスを作ります。

public class Test {
    
    public static void main(String[] args) {
        
        Test test = new Test();
        
        // ここに書くよ!        
    }
    
    /**
     * Supplier () -> T 
     */
    <T> void method(Supplier<T> s) {
    }
    
    /**
     * Consumer (T) -> void 
     */
    <T> void method(Consumer<T> c) {
    }
    
    /**
     * Predicate (T) -> boolean
     */
    <T> void method(Predicate<T> p) {
    }
    
    /**
     * Function (T) -> R
     */
    <T, R> void method(Function<T, R> f) {
    }
    
    /**
     * UnaryOperator (T) -> T
     */
    <T> void method(UnaryOperator<T> uo) {
    }
    
    /**
     * BinaryOperator (T, T) -> T
     */
    <T> void method(BinaryOperator<T> bo) {
    }
}


まず1つめ。
引数なしで戻り値を返すSupplierです。

test.method(() -> "a");

これはちゃんと判断できるようです。
OK。


2つめ。
引数を受けて戻り値を返さないConsumerです。

test.method(e -> System.out.println(e));

eの型がなんだかわからないですが、Object#toStringがかかるから大丈夫でしょう。
・・・と思ったらさっそくエラーになってしまいました。

「methodの参照はあいまいです
Testのメソッド method(Predicate)とTestのメソッド method(UnaryOperator)の両方が一致します」

いや、一致しないよ。戻り値ないからUnaryOperatorは無理だよと言いたいところです。
NG。


3つめ。
引数を受けて戻り値にbooleanを返すPredicateです。

test.method(e -> "a".equals(e));

これもエラーです。

「methodの参照はあいまいです
Testのメソッド method(Predicate)とTestのメソッド method(UnaryOperator)の両方が一致します」

あーなるほど、TがBooleanだったらAutoUnBoxingでbooleanで戻せますもんね。
ってことでこうしてみます。

test.<String>method(s -> "a".equals(s));

が、

「methodの参照はあいまいです
Testのメソッド method(Predicate)とTestのメソッド method(UnaryOperator)の両方が一致します」

そういうことじゃないんですね。
せめて今度はFunctionとの区別がつかないよとかならわかりますけども。
NG。


4つめ。
引数と戻り値の型が違うFunctionです。

test.<String, Integer>method(s -> Integer.parseInt(s));

バインドが効いたようでエラーになりません。
OK。


5つめ。
引数と戻り値の型が同じUnaryOperatorです。

test.<String>method(s -> s);

これは案の定エラーになります。Predicateと一緒ですね。

「methodの参照はあいまいです
Testのメソッド method(Predicate)とTestのメソッド method(UnaryOperator)の両方が一致します。」
NG。


最後。
2つ引数を受けて戻り値を返すBinaryOperatorです。(引数1、引数2、戻り値の型はすべて同じ)

test.<String>method((s1, s2) -> s1 + s2);

二つ引数を取るのはこの型だけなので大丈夫です。
OK。


つまり、

①ラムダの引数の数や型は推論に利用される
②ラムダの戻り値の型(voidも含め)は推論に利用されない

ということでいいんでしょうか。
ちょっともやもやしますね。