pro tip #2 – lambdas & method references

avatar icon blog author
Mikołaj Kąkol

TLDR;Lambda and method reference is not the same thing so lambda cannot be replaced with method reference without any thought on it.

IntelliJ to święte IDE, jednak im również zdarzają się błędy. Jakiś czas temu Android Studio informowało mnie, że lambdę można zastąpić referencją do metody. Spójrzmy na kod ze zgłoszenia błędu.

 

 public class LambdaVsMethodRef {

    public static final Runnable firstRunnable = () -> System.out.println("runner at time of lambda creation");
    public static final Runnable secondRunnable = () -> System.out.println("runner after lambda creation.");

    static Runnable lambda;
    static Runnable runner;

    public static void main(String[] args) {
        runner = firstRunnable;
        lambda = () -> runner.run(); // warning "Can be replaced with method reference"
        lambda.run(); // Prints: "runner at time of lambda creation"
        runner = secondRunnable;
        lambda.run(); // Prints: "runner after lambda creation."

        runner = firstRunnable;
        lambda = runner::run;
        lambda.run(); // Prints: "runner at time of lambda creation"
        runner = secondRunnable;
        lambda.run(); // Prints: "runner at time of lambda creation"
    }
}

 

W linii #11 IDE sugeruje nam, aby zastąpić lambdę referencją co jest błędne. Jak sugerują komentarze wynik uruchomienia kodu z zamienioną lambdą na referencje jest różny, czyli sugerowany refactoring kodu powoduje zmianę w semantyce, co z pewnością nie jest tym czego oczekujemy.

Tworząc lambdę () -> runner.run() mówimy, żeby za każdym uruchomieniem jej poszukać zmiennej runner oraz wykonać na niej run().
Natomiast przy method references jest podawana wprost metoda, którą mamy uruchomić. Czyli równie dobrze moglibyśmy napisać w linii #17 lambda = () -> System.out.println("runner at time of lambda creation"). W taki sposób kompilator widzi ten kod.