在方法定义

时间:2017-09-16 11:01:04

标签: java generics java-8 functional-interface

我遇到了以下问题:一个方法应该采用一个带有2个参数的双函数 - 一个是Collection<T>类型,另一个是T;实际的函数实际上可能是Collection::removeCollection::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编译器,因此可能因为某些错误而无法正常工作。

2 个答案:

答案 0 :(得分:2)

您无法使用BiFunction T泛型来处理这两种情况(StringInteger)。

此代码无法编译:

<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())多次调用,但使用不同类型的参数(StringInteger),您不要我想使用通用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);