2017-09-16 12 views
3

私は以下の問題を抱えていました。メソッドは2つの引数を取る2関数をとるべきです - 1種類はCollection<T>、もう1つはTです。実際の関数は実際にはCollection::removeまたはCollection::addになるか、より複雑な操作になります。実際の関数は1ダース以上のコレクションに使用され、関数にはいくつかの型の値とコレクションがあります。これは、メソッド定義でプレーンBiFunctionを使用することは可能ですか?

には、最初は汎用性がなかった - ちょうどCollection<String> sがあったと要素がBiFunction<Collection<String>, String, Boolean>がちょうどよく働いてString sがそう引数を宣言した:

List<String> idCodes; 
void visitElement(Element e, 
        BiFunction<Collection<String>, String, Boolean> elementOp) { 
    elementOp.apply(idCodes, e.getIdCode()); 
} 

をしかし、私はあまりにもコレクションの他のタイプを追加し、発見しました

List<String> idCodes; 
List<Integer> weights; 

void visitElement(Element e, 
        BiFunction<...> elementOp) { 
    elementOp.apply(idCodes, e.getIdCode()); 
    elementOp.apply(weights, e.getWeight()); 
} 

をしかし失敗しました - 私はちょうどかかわらず、私が使用しているもの一つの場所または別のコンパイルエラーを取得することができなかった:私はもはや一般的にBiFunctionを使用する方法を見つけることができませんでした型パラメータの場合はdが失敗します。

私の試みの一つは、Collection::addを渡すときには、実際にCollection<String>Stringに関数を適用するとき

<T> void visitElement(Element e, 
         BiFunction<Collection<T>, T, Boolean> elementOp) 

がない失敗しました。またはCollection<Integer>およびintである。

は、それから私は別のインターフェイスを作った:

interface ElementOp { 
    <T> boolean apply(Collection<T> collection, T item); 
} 

そしてませんので、驚くこと、これは今、私が望んでいたとおりに動作します。したがって、私の質問は:

は、私は本当に

interface ElementOp { 
    <T> boolean apply(Collection<T> collection, T item); 
} 

void visitElement(Element e, 
        ElementOp elementOp) { 
    elementOp.apply(idCodes, e.getIdCode()); 
    elementOp.apply(weights, e.getWeight()); 
} 

を使用しなければならないのか、この場合のためにBiFunctionを使用することが何とか可能でしょうか?

P.S.私はEclipse 4.3 Mars Javaコンパイラを使用していますので、そこにあるバグのために動作しないかもしれません。

答えて

2

T generic(StringInteger)を扱うジェネリックを使用できませんでした。 BiFunctionとして

<T> void visitElement(Element e, 
     BiFunction<Collection<T>, T, Boolean> elementOp) { 
    ... 
    elementOp.apply(idCodes, e.getIdCode()); 
    elementOp.apply(weights, e.getWeight()); 
} 

は一般的なクラスであり、あなたは、関数の引数としてCollection<T>Tでそれをパラメータ化:

このコードはコンパイルされませんでした。あなたが二番目に Collection<String>String拳通話中やCollection<Integer>Integerを渡しながら
だからのみCollection<T>Tオブジェクト/変数を渡すことができます。このカスタムインターフェイスで


は、物事が異なっている:

interface ElementOp { 
    <T> boolean apply(Collection<T> collection, T item); 
} 

これは動作します:

elementOp.apply(idCodes, e.getIdCode()); 
elementOp.apply(weights, e.getWeight()); 

BiFunctionに反して、それがパラメータとしてどのクラスで宣言された任意の変数を受け入れることができます。
保持するものは、ElementOpは汎用クラスではありません。
Tは、渡された引数の型の型を推測するメソッドスコープジェネリックのみです。同じ方法(Collection.add()またはCollection.remove())を呼び出す複数回、異なる種類(StringまたはInteger)の引数で、あなたは一般的なBiFunction<T,Collection<T>, Boolean>を使用したくない:あなたの条件に対処するために



あなたが導入したカスタム機能のインターフェイスは、はるかに優れています。

2

さて、あなたの最初の試みはうまくいかなかったので、あなたはこのようなものを持っている場合:

<T> void visitElement(Element e, BiFunction<Collection<T>, T, Boolean> elementOp) { 
    // some code   
} 

すべてT種類があるについてそのvisitElementが知っています。 elementOpBiFunction<Collection<T>, T, Boolean>であることがわかります。コンパイラによって推論されるTです。

もう一度interfaceを紹介する理由はありません。単純にメソッドを変更することができます。

void visitElement(T value, BiConsumer<Collection<T>, T> elementOp, Collection<T> elements) { 
     elementOp.accept(elements, value); 
} 

そして、それを使用します:また、あなたはとにかく結果を使用していないので、私はBiConsumerないBiFunctionを使用していたことがわかり

BiConsumer<Collection<String>, String> bi = Collection::remove; 

    Element e = ... 
    Collection<String> idCodes...; 
    visitElement(e.getIdCode(), bi, idCodes); 
関連する問題