Basically, the question boils down to the following: BiConsumer is a functional interface whose function is declared as follows:
void accept(T t, U u)
You gave a link to a method with the correct parameters, but the return type is incorrect:
public MutableContainer reduce(long param) { return new MutableContainer(param); }
[The T parameter is actually the this object when reduce is called, since reduce is an instance method, not a static method. Therefore, the parameters are correct.] The return type is MutableContainer , not void . So the question is, why does the compiler accept it?
Intuitively, I think this is because the method reference is more or less equivalent to an anonymous class, which looks like this:
new BiConsumer<MutableContainer,Long>() { @Override public void accept(MutableContainer t, Long u) { t.reduce(u); } }
Note that t.reduce(u) will return the result. However, the result is discarded. Since it is normal to call a method with a result and cancel the result, I think that, by and large, why it should use the method reference, where the method returns the result, for a functional interface whose method returns void .
Legally, I believe that the reason is in JLS 12.15.2.5 . This section is difficult, and I do not quite understand it, but somewhere in this section it says:
If e is the exact reference expression of the method ... R 2 is invalid.
where, if I read it correctly, R 2 is the result of a type of functional interface method. I think this is a suggestion that allows you to use a reference to a non-military method when a reference to the void method is expected.
( Edit: As Ismail noted in the comments, JLS 15.13.2 may be the right article here, he says that the reference to the method matches the type of the function, and one of the conditions for this is that the result of the type of the function is void .)
In any case, this should hopefully explain why it compiles. Of course, the compiler cannot always say when you are doing something that will lead to incorrect results.