Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does it matter if I use a method reference or a lambda here?

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.

like image 705
Johannes Kuhn Avatar asked May 25 '19 11:05

Johannes Kuhn


People also ask

Why method reference is better than lambda?

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.

What is lambda and method reference used for?

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.

Why do we use method reference?

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.

Can we replace 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.


1 Answers

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);
like image 196
Eugene Avatar answered Sep 21 '22 11:09

Eugene