// functional/Closure1.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
import java.util.function.*;
public class Closure1 {
int i;
IntSupplier makeFun(int x) {
return () -> x + i++;
}
}
// functional/SharedStorage.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
import java.util.function.*;
public class SharedStorage {
public static void main(String[] args) {
Closure1 c1 = new Closure1(); // [1]
IntSupplier f1 = c1.makeFun(0);
IntSupplier f2 = c1.makeFun(0);
IntSupplier f3 = c1.makeFun(0);
System.out.println(f1.getAsInt());
System.out.println(f2.getAsInt());
System.out.println(f3.getAsInt());
}
}
/* Output:
0
1
2
*/
// functional/Closure2.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
import java.util.function.*;
public class Closure2 {
IntSupplier makeFun(int x) { // effective final
int i = 0; // effective final
return () -> x + i;
}
}
change SharedStorage'[1] Closure1 to Closure2, the output is:
/* Closure2 Output:
0
0
0
*/
// functional/Closure3.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// {WillNotCompile}
import java.util.function.*;
public class Closure3 {
IntSupplier makeFun(int x) {
int i = 0;
// Neither x++ nor i++ will work:
return () -> x++ + i++;
}
}
show Closure3 compile error, use javac command and the output error:
functional/Closure3.java:13: error: local variables referenced from a lambda expression must be final or effectively final
return () -> x++ + i++;
^
functional/Closure3.java:13: error: local variables referenced from a lambda expression must be final or effectively final
return () -> x++ + i++;
^
2 errors
// functional/Closure4.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
import java.util.function.*;
public class Closure4 {
IntSupplier makeFun(final int x) { // x is final
final int i = 0; // i is also final
return () -> x + i;
}
}
// functional/Closure5.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// {WillNotCompile}
import java.util.function.*;
public class Closure5 {
IntSupplier makeFun(int x) {
int i = 0;
i++;
x++;
return () -> x + i;
}
}
/* compile error
functional/Closure5.java:14: error: local variables referenced from a lambda expression must be final or effectively final
return () -> x + i;
^
functional/Closure5.java:14: error: local variables referenced from a lambda expression must be final or effectively final
return () -> x + i;
^
2 errors
*/
To fix Closure5.java issue by assigning x and i to final variables before using them in the closure:
// functional/Closure6.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
import java.util.function.*;
public class Closure6 {
IntSupplier makeFun(int x) {
int i = 0;
i++;
x++;
final int iFinal = i;
final int xFinal = x;
return () -> xFinal + iFinal;
}
}
// functional/Closure7.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// {WillNotCompile}
import java.util.function.*;
public class Closure7 {
IntSupplier makeFun(int x) {
Integer i = 0; // using references
i = i + 1;
return () -> x + i;
}
}
/* compile error:
functional/Closure7.java:13: error: local variables referenced from a lambda expression must be final or effectively final
return () -> x + i;
^
1 error
*/
// functional/Closure8.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
import java.util.*;
import java.util.function.*;
public class Closure8 {
Supplier<List<Integer>> makeFun() {
final List<Integer> ai = new ArrayList<>(); // remove final also work
ai.add(1);
return () -> ai;
}
public static void main(String[] args) {
Closure8 c7 = new Closure8();
List<Integer> l1 = c7.makeFun().get(), l2 = c7.makeFun().get();
System.out.println(l1);
System.out.println(l2);
l1.add(42);
l2.add(96);
System.out.println(l1);
System.out.println(l2);
}
}
/* Output:
[1]
[1]
[1, 42]
[1, 96]
*/
This time it works: we modify the contents of the List without producing a compile-time error. When you look at the output from this example, it does seem pretty safe, because each time makeFun() is called, a brand new ArrayList is created and returned—which means it is not shared, so each generated closure has its own separate ArrayList and they can’t interfere with each other.
references:
1. On Java 8 - Bruce Eckel
2. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/functional/Closure1.java
3. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/functional/Closure2.java
4. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/functional/Closure3.java
5. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/functional/Closure4.java
6. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/functional/Closure5.java
7. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/functional/Closure6.java
8. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/functional/Closure7.java
9. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/functional/Closure8.java
10. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/functional/SharedStorage.java