Why Does a Java Method Reference with Return Type Match the Consumer Interface

Why does a Java method reference with return type match the Consumer interface?

consume(String) method matches Consumer<String> interface, because it consumes a String - the fact that it returns a value is irrelevant, as - in this case - it is simply ignored. (Because the Consumer interface does not expect any return value at all).

It must have been a design choice and basically a utility: imagine how many methods would have to be refactored or duplicated to match needs of functional interfaces like Consumer or even the very common Runnable. (Note that you can pass any method that consumes no parameters as a Runnable to an Executor, for example.)

Even methods like java.util.List#add(Object) return a value: boolean. Being unable to pass such method references just because that they return something (that is mostly irrelevant in many cases) would be rather annoying.

why BiConsumer Funcational Interface accepts methods having return type

BiConsumer<String, String> consumer= (s,t) -> {
String result = roles.put(s,t); // result is ignored
return;
}

Also called special void compatibility rule in the JLS.

How Java 8+ infers method reference as consumer?

The Java-8 compiler looks at the method declarations involved:

  • public void forEach(Consumer<? super T> in interface Iterable<T>
  • public void accept(T t) in interface Consumer<T>
  • public static String test(String) in your class Runner

From all these it concludes that Consumer<String> will fit.

Hence, it expands the method reference Runner::test
to an implementation of interface Consumer<String> which delegates
to the method test(String).

The line

Arrays.asList(testArgs).forEach(Runner::test);

is expanded to something equivalent to this:

Arrays.asList(testArgs).forEach(new Consumer<String>() {        
@Override
public void accept(String t) {
test(t);
}
});

Actually it does not exactly the above, but uses some JVM optimization
to avoid the anonymous class overhead.
But diving into these JVM details would lead too far here.

Method Reference - passing Function to method with Consumer argument

Two things here, lambda expressions are poly expressions - they are inferred by the compiler using their context (like generics for example).

When you declare consume(Holder::getHolded);, compiler (under the so-called special void compatibility rule) will infer it to Consumer<Holder>.

And this might not look obvious, but think of a simplified example. It is generally more than ok do call a method and discard it's return type, right? For example:

List<Integer> list = new ArrayList<>();
list.add(1);

Even if list.add(1) returns a boolean, we don't care about it.

Thus your example that works can be simplified to:

consume(x -> {
x.getHolded(); // ignore the result here
return;
});

So these are both possible and valid declarations:

Consumer<Holder> consumer = Holder::getHolded;
Function<Holder, String> function = Holder::getHolded;

But in this case we are explicitly telling what type is Holder::getHolded,, it's not the compiler inferring, thus consume(getHolded); fails, a Consumer != Function after all.

Why does this method returning a lambda depend on the return type of the interface method?

Your function type is Function<Person, Comparable>, which means fun.apply(p1) returns a Comparable. This is an interface defined in the Java standard library, which declares a method named compareTo which returns an int, so therefore your lambda returns an int.

This means if you define your functional interface as having a single abstract method returning an int, then your lambda conforms to the functional interface because it does return int. But if you define that abstract method as returning a String, then the lambda does not conform to the functional interface, because it does not return a String.

In the latter case, it is a type error for your comparing method to return that lambda, since the signature of comparing says it should return an instance implementing your functional interface, but the lambda does not conform to that functional interface due to the lambda having the wrong return type.

Why does the following casting with method reference not produce a compilation error?

From the spec:

If the body of a lambda is a statement expression (that is, an
expression that would be allowed to stand alone as a statement), it is
compatible with a void-producing function type; any result is simply
discarded.

Same is true for method references.

It's more flexible that way. Suppose it was a compiler error to not use a return value when you called a method normally - that would be incredibly annoying. You'd end up having to use fake variables you didn't care about in some cases.

public class SomeClass
{
public static int someFunction(int a) {
return a;
}

public static void main(String[] args) {
someFunction(3); // "error" - ignoring return type
int unused = someFunction(3); // "success"
}
}

If you want a the full formal definition of what is acceptable, see 15.13.2. Type of a Method Reference.

Java consumer with return

Your Consumer<Resource> block = resource -> resource.op1().op2(); is equivalent to:

Consumer<Resource> block = new Consumer<Resource>() {
@Override
public void accept(Resource resource) {
resource.op1().op2(); // there is no return statement
}
};

Why does functional interface with void return-type method accept any return-type method?

Although interface J declares it has a void function, Test::foo returns an Object.

It's inaccurate to say that Test::foo returns something. In different contexts, it could mean different things.

Supplier<Object>  a = Test::foo;
J b = Test::foo;
Runnable c = Test::foo;

It's more accurate to say that Test::foo can represent a target type the functional method of which returns either void or Object.

It's an example of expression statement (jls-14.8).

If the target type's function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).

...

An expression statement is executed by evaluating the expression; if the expression has a value, the value is discarded.



Related Topics



Leave a reply



Submit