Лямбда-захват против не-захват - PullRequest
0 голосов
/ 29 января 2019

Не могли бы вы объяснить, почему первая лямбда захватывает, а вторая нет.

   Runnable createLambdaWithCapture() {
      return System.out::println;
   }    
   Runnable createLambdaWithApparentCapture() {
        return () -> System.out.println();
   }

Ответы [ 2 ]

0 голосов
/ 30 января 2019

В первом методе System.out вычисляется немедленно в операторе возврата.

Эквивалентная лямбда будет выглядеть так, как если бы вы вывели System.out в переменную, которая затем фактически становится окончательным закрытием:

Runnable createLambdaWithCapture() {
    PrintWriter foo = System.out;
    return () -> foo.println(); // foo is captured and effectively final
}

Во втором методе System.out (который является статическим полем) не является окончательным и может быть изменен позднее во время выполнения.Он не вызывается до Runnable::run.

System.out = aPrintStream;
Runnable runnable1 = createLambdaWithCapture();
Runnable runnable2 = createLambdaWithApparentCapture();
System.out = anotherPrintStream;
runnable1.run(); // prints to aPrintStream
runnable2.run(); // prints to anotherPrintStream
0 голосов
/ 29 января 2019

Первый фрагмент записывается, потому что он оценивает System.out, когда выполняется оператор return и захватывает соответствующую ссылку на объект, который будет использоваться в его реализации Runnable#run.

Второй фрагмент генерирует экземпляр Runnable, который не захватывает, потому что System.out оценивается только после вызова метода run этого экземпляра.Он мог измениться со времени выполнения оператора return.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...