2016-03-11 5 views
6

、例えば、このようなインターフェイス:Java8:クラスメソッド参照からインスタンスメソッド参照を取得する方法はありますか?私が持っている場合は

public interface FooBar<A, B> { 
    B foo(A a); 

    B bar(A a); 
} 

は、インスタンスメソッドの参照をFooBar::barのようなクラスレベルのメソッド参照を取得し、取得する方法はありますか?

ie。私は

FooBar myFooBarInstance; 
BiFunction<FooBar<A, B>, A, B> barFunction = FooBar::bar; 

を持っている場合、私は

Function<A, B> myBarFunction = myFooBarInstance::bar; 

答えて

7

関数プログラミングの世界では、あるいは単に「パラメータに値をバインドする」機能の少ない用語で説明します。そこそのための組み込みの方法はませんが、それはあなた自身を書くことは簡単です:

public static <T,U,R> Function<U,R> bind(BiFunction<T,U,R> f, T t) { 
    return u -> f.apply(t, u); 
} 

次に、あなたはあなたのケースでそれを使用することができます。

FooBar<X,Y> instance=…; 
BiFunction<FooBar<X,Y>,X,Y> barFunction=FooBar::bar; 
Function<X,Y> myBarFunction=bind(barFunction, instance); 

か、単に

// equivalent to myBarFunction=instance::bar 
Function<X,Y> myBarFunction=bind(FooBar::bar, instance); 

注意ユーティリティメソッドが、使用している機能インターフェイス(つまり、FunctionおよびBiFunction)とタイトで、メソッド参照ではないことを確認してください。どのようなBiFunctionでも動作します。メソッドリファレンス、ラムダ式、または通常のクラスとして実装されます。しかし、具体的にはFunctionインスタンスが必要な場合にのみ役に立ち、1つのパラメータを取る任意の機能インタフェースでは役に立ちません。 Function::applyを使用して別の単一引数関数型に変換できますが、bind(bifunc, value)::applyを使用すると、インスタンスが必要な場所でx -> bifunc.apply(value, u)以上の利点はありません。

BiFunctionFunctionに変換する必要がある場合は、最初の引数を非常に頻繁にバインドして、ユーティリティメソッドを使用すると便利です。それ以外の場合は、実際のターゲットタイプが存在するコンテキストでラムダ式を使用してください。もちろん、他のインターフェースにも同様のメソッドを書くことができますが、このインターフェースは、特定のインターフェースで必要な場合にのみ便利です。

より多くのパラメータを取る関数に関しては、Java APIはそのような機能インタフェースを提供しないので、適切なインタフェースを自分で定義する必要があります。インタフェースに直接バインディング機能を提供するオプションを提供します。defaultメソッド。あなたは

MyFunc4<U, W, X, Y, Z> func = …; 

のような機能を持っている場合

interface MyFunc3<A,B,C,R> { 
    R apply(A a, B b, C c); 
    default BiFunction<B,C,R> bind(A a) { 
     return (b, c) -> apply(a, b, c); 
    } 
} 
interface MyFunc4<A,B,C,D,R> { 
    R apply(A a, B b, C c, D d); 
    default MyFunc3<B,C,D,R> bind(A a) { 
     return (b, c, d) -> apply(a, b, c, d); 
    } 
} 

そして、あなたは

MyFunc3<W, X, Y, Z> f3 = func.bind(u); 

または

BiFunction<X, Y, Z> f2 = func.bind(u).bind(w); 
+1

いつものように華麗な説明、ホルガー。機能的なインターフェイスにインスタンスをバインドするためのデフォルトのメソッドを単に追加することは考慮されていませんでしたが、それは本当に便利なトリックです。 –

3

を定義した場合、私はそれについて考えたら、私はその答えの非常に簡単に実現取得したいものと一致しますFunction<A,B>インスタンスを取得する任意の簡単な方法があります。私はこれを行うことができます。

Function<A, B> instanceFunction = (a)->barFunction.apply(myFooBar, a); 

「一部機能アプリケーション」何をしたいとも呼ばれますが、より多くのカップルのパラメータを取るメソッドを持っている場合、それは本当に醜い取得しますが、それは動作します...

+0

これが機能するような何かを行うことができますが、それは非常に一般的ではありません。 .. 誰か理由がありますか?前もってメソッドのシグネチャを知っていることに依存していない優雅なやり方?私は反射で物を作ることができると知っていますが、より良い方法があることを知ってうれしいです。 –

+0

スタティックタイピングでは、コンパイル時に型を知る必要があります。バイトコードを生成したり、コードを生成したり、実行時にコンパイルすることなく、これを一般的に行う方法はありません。 Javaでは、より良い解決策は、最初にこれを行い、より具体的なコードを書く必要を避けることです。より動的な言語でこれを処理することはできますが、動的言語を使用することの欠点はすべてあります。 –

関連する問題