I've faced a strange(for me) behavior when I was trying to use function composition with two void methods. I've written a simple example to illustrate the problem :
public class Startup {
public static void main(String[] args) {
List<Foo> foos = new ArrayList<>();
// 1) Does not compile
foos.forEach(Startup::doSomething1.andThen(Startup::doSomething2));
Consumer<Foo> doSomething1 = Startup::doSomething1;
Consumer<Foo> doSomething2 = Startup::doSomething2;
// 2) Works as expected
foos.forEach(doSomething1.andThen(doSomething2));
}
public static void doSomething1(Foo foo) {
}
public static void doSomething2(Foo foo) {
}
public static class Foo {
}
}
When I try to compile the first solution it says "')' expected" before andThen call.
When I explicitly say this are Consumers the code is compiled and it works as expected.
Can anyone explain to my why this is happening and is there another way of doing function composition of void methods with Java 8?
Let's make this simpler:
private static boolean test(String input){
return input.equals("123");
}
Predicate<String> predicate = YourClass::test;
Function<String, Boolean> function = YourClass::test;
So a method reference is a poly expression (like generics for example), they depend on the context where they are used. So your Startup::doSomething
method reference could be any @FunctionalInterface
that would comply to the that method. It might look to you that it is a Consumer
in this case, but it's a different story for the compiler.
This has to do with the way Java inferes, converts and detects types in lambdas. As mentioned in a comment above, the conversion to Consumer<Foo>
has not taken place yet meaning that the compiler does not know that this is a Consumer
so that you can chain an andThen()
afterwards.
Explicitly casting this to a Consumer
and using parentheses properly will let you achieve the desired effect:
List<Foo> foos = new ArrayList<>();
foos.forEach(((Consumer<Foo>) Null::doSomething).andThen(Null::doSomething2));
I guess if you fiddle around with it, you can achieve the same behavior using type witnesses but I am not 100% sure whether they can achieve the desired result.
First time I noticed this was using chained comparators which may exhibit the same behavior. Doing an online search about that will show you some more intricate details regarding how this works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With