是否可以在方法定义中使用普通的 BiFunction

Is this possible to do using plain BiFunction in method definition

我遇到了以下问题:一个方法应该接受一个双函数,它有两个参数——一个是 Collection<T> 类型,另一个是 T 类型;实际函数实际上可能是 Collection::removeCollection::add,或更复杂的操作;实际函数用于十几个集合,函数中有几种类型的值和集合。

最初没有通用性——只有 Collection<String>,元素是 String,所以将参数声明为 BiFunction<Collection<String>, String, Boolean> 效果很好:

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

但是后来我也添加了其他类型的集合,发现我再也找不到如何通用地使用 BiFunction:

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

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

但失败了——我可能只是在一个地方或另一个地方遇到编译错误,无论我使用什么类型参数都会失败。

我的一个尝试是

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

不会在传入 Collection::add 时失败,而是在实际将函数应用于 Collection<String>String 时失败;或 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 编译器,所以这可能只是因为那里有一些错误而无法工作。

您不能将 BiFunctionT 泛型一起使用来处理这两种情况(StringInteger)。

此代码无法编译:

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

因为 BiFunction 是一个泛型 class 并且您使用 Collection<T>T 作为函数参数对其进行了参数化。
所以你只能传Collection<T>Tobjects/variables而你传 第一次调用 Collection<String>String,第二次调用 Collection<Integer>Integer

有了这个自定义界面,情况就不同了:

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

这行得通:

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

BiFunction相反,它可以接受用任何class.
声明的任何变量作为参数 要保留的是 ElementOp 不是通用的 class.
T 实际上只是一个方法范围泛型,它推断所传递参数的类型。


为了满足您的要求:多次调用相同的方法(Collection.add()Collection.remove())但使用不同类型的参数(StringInteger),您不想使用通用的 BiFunction<T,Collection<T>, Boolean>.
您介绍的自定义功能界面更适合。

嗯,你的第一次尝试没有成功,因为当你遇到这样的事情时:

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

visitElement 知道的只有 T 类型;它知道 elementOpBiFunction<Collection<T>, T, Boolean> 类型; a T 将由编译器推断。

我看不出有什么理由在这里介绍另一个 interface,因为您可以简单地稍微改变一下方法。另请注意,我使用的是 BiConsumer 而不是 BiFunction,因为无论如何您都没有使用结果:

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

并使用它:

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

    Element e = ...
    Collection<String> idCodes...;
    visitElement(e.getIdCode(), bi, idCodes);