Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda capturing vs non capturing

Can you please explain why the first lambda is capturing and the second not.

   Runnable createLambdaWithCapture() {
      return System.out::println;
   }    
   Runnable createLambdaWithApparentCapture() {
        return () -> System.out.println();
   }
like image 926
Steven Avatar asked Jan 29 '19 20:01

Steven


People also ask

What is capturing lambda?

Captures default to const value. By default, variables are captured by const value . This means when the lambda is created, the lambda captures a constant copy of the outer scope variable, which means that the lambda is not allowed to modify them.

What are the advantages of lambda expression over anonymous methods?

Fewer Lines of Code − One of the most benefits of a lambda expression is to reduce the amount of code. We know that lambda expressions can be used only with a functional interface. For instance, Runnable is a functional interface, so we can easily apply lambda expressions.

Can we use lambda without functional interface?

You do not have to create a functional interface in order to create lambda function.

Are lambdas more efficient?

Generally speaking, lambdas and streams provide a more concise and (once everyone is up to speed) more readable way of expressing this kind of algorithm.


2 Answers

The first snippet is capturing because it evaluates System.out when the return statement is executed and captures the corresponding object reference to be used within its Runnable#run implementation.

The second snippet generates a Runnable instance that is not capturing because System.out is only evaluated once that instance's run method is invoked. It could have changed since the time the return statement was executed.

like image 170
Savior Avatar answered Nov 02 '22 23:11

Savior


In the first method, System.out is evaluated immediately in the return statement.

The equivalent lambda would be as if you factored System.out out to a variable which then becomes an effectively final closure:

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

In the second method, System.out (which is a static field) is not final and could be changed later at runtime. It is not invoked until Runnable::run is invoked.

System.out = aPrintStream;
Runnable runnable1 = createLambdaWithCapture();
Runnable runnable2 = createLambdaWithApparentCapture();
System.out = anotherPrintStream;
runnable1.run(); // prints to aPrintStream
runnable2.run(); // prints to anotherPrintStream
like image 30
Novaterata Avatar answered Nov 02 '22 23:11

Novaterata