消除了接受不同功能接口的重载方法的歧义

时间:2018-06-20 14:30:52

标签: java lambda java-8

我在Utils类中具有以下可用方法:

protected <U> U withTx(Function<OrientGraph, U> fc) {
    // do something with the function
}

protected void withTx(Consumer<OrientGraph> consumer) {
    withTx(g -> {
        consumer.accept(g);
        return null;
    });
}

使用myClass的方法,我有:

withTx(g -> anotherMethod(g));

第二段代码有一个编译错误:

The method withTx(Function<OrientGraph, Object>) is ambiguous for the type myClass

我猜这来自编译器,编译器无法确定lambda是Consumer还是Function。有一种消除这种情况的高尚方法吗?

无论方法anotherMethod返回(voidObject,什么),我都不想使用此返回值。

一种解决方法是:

withTx(g -> { anotherMethod(g); });

但是我想知道是否还有更好的方法,因为这会触发SonarLint

2 个答案:

答案 0 :(得分:8)

摘自Joshua Bloch的“有效Java”

  

不提供带有多个重载的方法,这些重载需要不同的   如果可以创建,则功能接口位于相同的参数位置   客户中可能存在的歧义。

     

避免此问题的最简单方法是不编写重载   在同一个参数中采用不同的功能接口   位置。

另一种可能的解决方案是为这两种方法使用不同的名称:

<U> U withTxFunction(Function<OrientGraph, U> fc);

void withTxConsumer(Consumer<OrientGraph> consumer);

一个很好的例子,可以在Java API本身中找到,例如在IntStream界面中:

mapToDouble(IntToDoubleFunction mapper);

mapToLong(IntToLongFunction mapper);

更新

我想说明为什么编译器会抱怨?那是因为...

lambda g -> anotherMethod(g)可以同时分配给Function<T, R>Consumer<T>

Function<T, R> func  = g -> anotherMethod(g);

Consumer<T> consumer = g -> anotherMethod(g); // here you just ignore the return value

<T> T anotherMethod(T t) { ... }

因此,当您编写withTx(g -> anotherMethod(g))时,会出现“歧义方法调用” 错误,编译器无法找出应该使用哪种重载方法:

withTx(function) OR withTx(consumer) ... ?

答案 1 :(得分:2)

实际上,您已经有了解决问题的方法,但是在另一个地方,因为您这样写:

withTx(g -> {
    consumer.accept(g);
    return null; // this calls the `Function` variant of `withTx`
});

但是无论如何,您都会遇到此问题,因为函数anotherMethod()的返回类型为void,并且编译器不知道从Function<OrientGraph, Void>还是{{ 1}}。 Consumer<OrientGraph>本身应该表示一个接受某些东西却什么也不返回的函数。

Consumer明确调用withTx(g -> { anotherMethod(g); });变体。

如果要调用Consumer变体,请执行以下操作: Function