Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disambiguate overloaded methods that accept different functional interfaces [duplicate]

I have the following available methods in a Utils class:

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;
    });
}

And in a method of myClass I have:

withTx(g -> anotherMethod(g));

The second piece of code has a compilation error:

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

I guess this comes from the compiler, which is not able to determine if the lambda is a Consumer or a Function. Is there a noble way to disambiguate this situation?

Whatever the method anotherMethod returns (void, Object, anything), I don't want to use this return value.

One solution is to do:

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

But I wanted to know if there was something better, because this triggers SonarLint.

like image 620
matthiasbe Avatar asked Jun 20 '18 14:06

matthiasbe


People also ask

Can functional interface have overloaded methods?

Two overloaded methods require two method bodies (implementations). A functional interface must be an interface that can be fully implemented with a single method body, which can then be implemented using Lambda syntax or Method Reference syntax. "which one you are trying to reference from the lambda".

Can two overloaded methods have different return types?

The compiler does not consider the return type while differentiating the overloaded method. But you cannot declare two methods with the same signature and different return types. It will throw a compile-time error. If both methods have the same parameter types, but different return types, then it is not possible.

How do compiler differentiate overloaded methods from duplicate methods?

48. How do compiler differentiate overloaded methods from duplicate methods? Compiler uses method signature to check whether the method is overloaded or duplicated. Duplicate methods will have same method signatures i.e. same name, same number of arguments and same types of arguments.

Can overloaded methods have different data types?

No, you cannot overload a method based on different return type but same argument type and number in java. same name.


1 Answers

From the "Effective Java" by Joshua Bloch:

Do not provide a method with multiple overloadings that take different functional interfaces in the same argument position if it could create a possible ambiguity in the client.

The easiest way to avoid this problem is not to write overloadings that take different functional interfaces in the same argument position.

One more possible solution could be to use a different names for these two methods:

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

void withTxConsumer(Consumer<OrientGraph> consumer);

A good example of this approach one can find in the Java API itself, for example in the  IntStream interface:

mapToDouble(IntToDoubleFunction mapper);

mapToLong(IntToLongFunction mapper);

Update:

I'd like to add a clarification of why does the compiler complain? That is because...

The lambda g -> anotherMethod(g) can be assigned to both Function<T, R> and 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) { ... }

So, when you write withTx(g -> anotherMethod(g)), you get the "Ambiguous method call" error, the compiler fails to find out which of the overloaded method should be used:

withTx(function) OR withTx(consumer) ... ?
like image 90
Oleksandr Pyrohov Avatar answered Oct 18 '22 19:10

Oleksandr Pyrohov