When I try to compile this code
import java.util.Optional;
public class GenericTest {
public static void main(String[] args) {
Optional.empty().map(o -> getStringClass(o)).orElse(String.class);
}
static Class<?> getStringClass(Object arg) {
return String.class;
}
}
javac will fail with the following error:
GenericTest.java:6: error: method orElse in class Optional cannot be applied to given types; Optional.empty().map(o -> getStringClass(o)).orElse(String.class); ^ required: Class<CAP#1> found: Class<String> reason: argument mismatch; Class<String> cannot be converted to Class<CAP#1> where T is a type-variable: T extends Object declared in class Optional where CAP#1 is a fresh type-variable: CAP#1 extends Object from capture of ? 1 error
But if I use a method reference instead, javac will compile the code just fine:
import java.util.Optional;
public class GenericTest {
public static void main(String[] args) {
Optional.empty().map(GenericTest::getStringClass).orElse(String.class);
}
static Class<?> getStringClass(Object arg) {
return String.class;
}
}
Why does it make a difference if I use a method reference or a lambda expression?
According to my understanding, both the method reference and the lambda have the type Function<Object,Class<?>>
, so I don't see the difference here.
The eclipse java compiler (ecj) won't compile both versions by the way.
The method references can only be used to replace a single method of the lambda expression. A code is more clear and short if one uses a lambda expression rather than using an anonymous class and one can use method reference rather than using a single function lambda expression to achieve the same.
You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it's often clearer to refer to the existing method by name.
Method reference is used to refer method of functional interface. It is compact and easy form of lambda expression. Each time when you are using lambda expression to just referring a method, you can replace your lambda expression with method reference.
If you are using a lambda expression as an anonymous function but not doing anything with the argument passed, you can replace lambda expression with method reference. In the first two cases, the method reference is equivalent to lambda expression that supplies the parameters of the method e.g. System.
Method chaining strikes again. You can read here of why the designers of this feature found it complicated to implement (it has to do with the fact that lambda's/method references are poly expressions - their types are context dependent). Such a feature would require some extra burden on the compiler - and while your example would be a fairly trivial example to solve, javac
has to care about a lot more than triviality; thus this is not yet implemented, even in java-12.
The easiest solution IMO, since this has to do with method chaining (and in your case this is possible), is not to chain:
Optional<Class<?>> first = Optional.empty().map(o -> getStringClass(o));
Class<?> second = first.orElse(String.class);
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