我遇到了以下问题:一个方法应该采用一个带有2个参数的双函数 - 一个是Collection<T>
类型,另一个是T
;实际的函数实际上可能是Collection::remove
或Collection::add
,也可能是更复杂的操作;实际函数用于十几个集合,函数中有几种类型的值和集合。
最初没有通用性 - 只有Collection<String>
s和元素String
s因此宣布论证为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编译器,因此可能因为某些错误而无法正常工作。
答案 0 :(得分:2)
您无法使用BiFunction
T
泛型来处理这两种情况(String
和Integer
)。
此代码无法编译:
<T> void visitElement(Element e,
BiFunction<Collection<T>, T, Boolean> elementOp) {
...
elementOp.apply(idCodes, e.getIdCode());
elementOp.apply(weights, e.getWeight());
}
因为BiFunction
是一个通用类,您使用Collection<T>
和T
作为函数参数对其进行参数化。
因此,您只能在通过时传递Collection<T>
和T
个对象/变量
第一个电话中为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
相反,它可以接受任何类声明的任何变量作为参数
要保留的是ElementOp
不是通用类
T
确实只是一个方法范围泛型,它推断了传递参数类型的类型。
要满足您的要求:使用相同的方法(Collection.add()
或Collection.remove()
)多次调用,但使用不同类型的参数(String
或Integer
),您不要我想使用通用BiFunction<T,Collection<T>, Boolean>
您介绍的自定义功能界面更适合。
答案 1 :(得分:2)
你的第一次尝试没有用,因为你有这样的事情:
<T> void visitElement(Element e, BiFunction<Collection<T>, T, Boolean> elementOp) {
// some code
}
visitElement
知道的所有内容都是T
类型;它知道elementOp
的类型为BiFunction<Collection<T>, T, Boolean>
;一个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);