2017-01-12 17 views
0

の入力引数が同じ型の2つの引数を生成するbuildBiFxnWithSameTypeArgsというメソッドを記述したいとします。 (buildBiFxnWithSameTypeArgsが呼び出されたときに)いつも知られていません。つまり、buildBiFxnWithSameTypeArgsによって返された関数が呼び出されるたびに、コンパイラが提供する引数の型が一致している必要があります。最終的な効果は、本質的には、メソッド定義の2つの引数の型に同じジェネリック型のパラメータを使用することに相当するラムダでなければなりません。汎用型パラメータで制約されたパラメータ型のラムダ関数を返す

私の最初の試みは、次のようになります。

public interface ConstrainedBiFunction<I, O> extends BiFunction<I, I, O> {} 

public static ConstrainedBiFunction<?, String> buildBiFxnWithSameTypeArgs() { 
    return (inputOne, inputTwo) -> String.valueOf(inputOne) + String.valueOf(inputTwo); 
} 

public void test() { 
    buildBiFxnWithSameTypeArgs().apply(Integer.valueOf(1), Integer.valueOf(2)); 
} 

ワイルドカード型パラメータ?がこの方法で使用することはできません、しかし、表示されます。コンパイルが次のエラーでapplyステップで失敗:

apply (capture<?>, capture<?> in BiFunction cannot be applied to (java.lang.Integer, java.lang.Integer) 

は、それは、そのパラメータの型推論されているラムダ関数を返すことが可能であり、その後、このように互いに対して制約?

EDIT:非常に良い質問に対する謝罪。私はここで最も簡単な質問をするために本質を捉えようとしていたより複雑な問題を抱えていましたが、問題をあまりにも単純化したようです。私はもちろん、すべてのクラスがObjectから継承していることを認識していますので、この問題を過度に単純化して解釈すると、@shmoselと@JB Nizetが提案する解決策が働きます。私は元の問題を蒸留してより良い仕事をしたら、新しい質問を投稿します。

+0

どのようにConstrainedBiFunction が' '.apply(Integer.valueOf(1)、Integer.valueOf(2))に関し、'思いを行うことができますか? – Savior

+2

すべてのクラスは最終的にObjectから継承されるため、たとえばバナナやトラックなどを渡しても、型を明示的に指定しない限り、コンパイラはConstrainedBuFunction として推論します。 –

答えて

1

ワイルドカードとは、「特定の、しかし不明なタイプの」という意味です。 引数のうち、タイプが?のパラメータを満たす引数を渡すことはできません。タイプが間違っている可能性があります。 ConstrainedBiFunction<Object, String>に戻り値の型を変更し、すべてのクラスが暗黙的Object拡張するので、任意の入力タイプを受け入れることができるようになります:これはまだPECS使用して、入力タイプに制限のある方法のために用いることができることを

public static ConstrainedBiFunction<Object, String> buildBiFxnWithSameTypeArgs() { 
    return (inputOne, inputTwo) -> String.valueOf(inputOne) + String.valueOf(inputTwo); 
} 

注意原理。例えば:正しく入力タイプとしてObjectを使用すると、PECSルール以下のすべてのAPIのために十分でなければならないことを指摘し

// input parameter must be of type Integer or any supertype, 
// so that we can safely pass in an Integer 
String combine(ConstrainedBiFunction<? super Integer, String> function) { 
    return function.apply(1, 2); 
} 

void test() { 
    ConstrainedBiFunction<Object, String> concat = buildBiFxnWithSameTypeArgs(); 
    ConstrainedBiFunction<Integer, String> sum = (a, b) -> String.valueOf(a + b); 
    System.out.println(combine(concat)); // "12" 
    System.out.println(combine(sum)); // "3" 
} 
0

shmosel’s answerが、あなたの元の試みを固定することが可能です。 buildBiFxnWithSameTypeArgs().apply(1, 1);として使用する場合、コンパイラはとにかくTためObjectを推測すること

public interface ConstrainedBiFunction<I, O> extends BiFunction<I, I, O> {} 

public static <T> ConstrainedBiFunction<T, String> buildBiFxnWithSameTypeArgs() { 
    return (inputOne, inputTwo) -> String.valueOf(inputOne) + String.valueOf(inputTwo); 
} 

public void test() { 
    ConstrainedBiFunction<Integer, String> f1 = buildBiFxnWithSameTypeArgs(); 
    String s1 = f1.apply(1, 1); 
    ConstrainedBiFunction<String, String> f2 = buildBiFxnWithSameTypeArgs(); 
    String s2 = f2.apply("hello ", "world"); 
} 

注:代わりに、ワイルドカードの

は、あなたは、呼び出し元がタイプを選択することを可能にするタイプのパラメータを追加する必要があります。これはIntegerの引数を渡すことを可能にしますが、もちろん両方の引数に同じ型を持たせるという考え方、つまりbuildBiFxnWithSameTypeArgs().apply(1.5, "foo");も同様の型を同じ型に割り当てることができるので、Objectに代入することができます。


PECSを介して解決できない問題を扱うこのような構成の実際の例がいくつかあります。

など。 Function.identity()は、同じ入出力タイプを持つ任意の型付き関数を戻します。この関数をtoMap collectorに渡すと、ストリーム要素と同じキーまたは値の型を持つマップを取得できます。

もっと複雑な例はComparator.naturalOrder()です。ここでは、型パラメータには、比較する要素が確かにComparableであることを保証する境界があります。型はComparable<?>を実装するのではなく、型自体を参照する型であるため、型パラメータなしではnaturalOrder()は機能しません。

だから、Comparator.naturalOrder().compare(42, "foo")はできません。 `;しかし、あなたは

Comparator<Integer> c1 = Comparator.naturalOrder(); 
c1.compare(10, 42); 
Comparator<String> c2 = Comparator.naturalOrder(); 
c2.compare("foo", "bar"); 
関連する問題