23

これは、次の質問に関連しています:関数合成を行う方法は?

Functionとして宣言された変数にメソッド参照を割り当てることができるandThenことに気付きましたcompose。しかし、明らかに、それらを or で呼び出す前に、最初に宣言された (またはFunction呼び出し前に型キャストされた) 変数にそれらを割り当てる必要があります。andThencompose

これがどのように機能するかについて、誤解があるのではないかと思います。

だから私の質問:

  1. andThenメソッドを呼び出す前に、型キャストまたは変数への割り当てを行う必要があるのはなぜですか?
  2. この方法で実行する必要があるメソッド参照のタイプは正確には何ですか?

以下サンプルコード。

public class MyMethods{
    public static Integer triple(Integer a){return 3*a;}
    public static Integer quadruple(Integer a){return 4*a;}

    public int operate(int num, Function<Integer, Integer> f){
        return f.apply(num);
    }

    public static void main(String[] args){
        MyMethods methods = new MyMethods();
        int three = methods.operate(1, MyMethods::triple); // This is fine
        // Error below
        // int twelve = methods.operate(1, (MyMethods::triple).andThen(MyMethods::quadruple));
        // But this one is fine
        Function<Integer, Integer> triple = MyMethods::triple;
        Function<Integer, Integer> quadruple = MyMethods::quadruple;
        int twelve = methods.operate(1, triple.andThen(quadruple));
        // This one is also fine
        int twelve2 = methods.operate(1, ((Function<Integer, Integer>)MyMethods::triple).andThen(MyMethods::quadruple));
    }
}


エラーの詳細説明

Eclipse では、エラー メッセージで強調表示されます。

この式の対象の型は関数型インターフェイスでなければなりません

機能インターフェースに関するEclipseエラー

Java 8コンパイラでは、エラーは次のとおりです。

java8test.java:14: エラー: ここではメソッド参照が予期されていません
        int 12 = Methods.operate(1, (MyMethods::triple).andThen(MyMethods::quadruple));
                                         ^
1 エラー

(実際、Eclipse のエラーが Java 8 コンパイラーのエラーと異なるのはなぜですか?)

4

2 に答える 2

16

Brian Goetz (Java ラムダのプロジェクト リーダー) が言うように、「ラムダ式には組み込み型がありません」 (メソッド参照にも適用されます)。Functionこれが、メソッドが使用可能になる前に型にキャスト (または代入) する必要がある理由です。

Eclipse が JDK コンパイラ (javac) とは異なるエラー メッセージを表示する理由は、Eclipse が ecj と呼ばれる独自の Java コンパイラを使用しているためです。これは、javac とはまったく異なるプログラムです。これが、JDK を完全にインストールしなくても Eclipse を JRE で実行できる理由です。

于 2014-12-19T05:01:24.593 に答える
15

staticヘルパー メソッド (すべての関数がメソッド呼び出しレシーバーではなくパラメーターである場合) を作成すると、型キャストや一時変数なしで回避できます。

static <T,V,R> Function<V, R> chain(
    Function<? super V, ? extends T> f1, Function<? super T, R> f2) {

    return f2.compose(f1);
}

次に、次のように簡単に言うことができます。

int twelve = methods.operate(1, chain(MyMethods::triple, MyMethods::quadruple));

ただし、この方法でメソッド参照を連鎖させることは、単純なラムダ式と比較して、ソース コードが短くなることも、実行時に効率がよくなることもないことに注意してください。

int twelve = methods.operate(1, i -> quadruple(triple(i)));

最後のソリューションでは、型のキャスト、追加の変数、ヘルパー メソッドが必要ないことに注意してください。関数が必要な場所に適合する既存のメソッドがある場合、メソッド参照は優れたツールですが、複数のメソッド参照から関数を構成することはあまり役に立ちません (ほとんどの場合)。

于 2014-12-19T10:04:41.653 に答える