// InternalVsExternalIteration.java import java.util.*; interface Pet { void speak(); } class Rat implements Pet { public void speak() { System.out.println("Squeak!"); } } class Frog implements Pet { public void speak() { System.out.println("Ribbit!"); } } public class InternalVsExternalIteration { public static void main(String[] args) { List<Pet> pets = Arrays.asList(new Rat(), new Frog()); for(Pet p : pets) // External iteration p.speak(); pets.forEach(Pet::speak); // Internal iteration } }
for
loop, and this loop exactly indicates how it is done. Such code is redundant and repeatedly reproduced in programs. However, with the forEach
loop, we order the program to call speak (here - using a link to a method that is more concise than lambda) for each element, but we don’t have to describe how the cycle works. The iteration is handled internally, at the level of the forEach
loop.make_fun()
creates and returns a function called func_to_return
, which is then used in the rest of the program: # Closures.py def make_fun(): # : n = 0 def func_to_return(arg): nonlocal n # 'nonlocal' n += arg : # 'n' print(n, arg, end=": ") arg += 1 n += arg return n return func_to_return x = make_fun() y = make_fun() for i in range(5): print(x(i)) print("=" * 10) for i in range(10, 15): print(y(i)) """ : 0 0: 1 1 1: 3 3 2: 6 6 3: 10 10 4: 15 ========== 0 10: 11 11 11: 23 23 12: 36 36 13: 50 50 14: 65 """
func_to_return
works with two fields that are not in its scope: n
and arg
(depending on the specific case, arg
can be a copy or refer to anything outside the scope). A nonlocal declaration is mandatory because of the Python device itself: if you are just starting to work with a variable, then this variable is assumed to be local. Here, the compiler (yes, there is a compiler in Python and yes, it does some — admittedly very limited — a check of static types) sees that n += arg
uses n, which was not initialized in the scope of func_to_return
, so a message is generated by mistake. But if we say that n
is nonlocal
, Python will guess that we use n
, defined outside the scope of the function, and which has been initialized, so that everything is in order.func_to_return
, what will happen to n
outside the scope of func_to_return
? As a rule, one would expect n to go out of scope and become unavailable, but if this happens, func_to_return
will not work. To support the dynamic creation of functions, func_to_return
should “close” around n and ensure that it “survives” until the function returns. Hence the term "closure".make_fun()
, we call it twice and save the result of the function in x and y. The fact that x and y give completely different results demonstrates that with each call to make_fun()
, a completely independent function func_to_return
with its own closed storage for n
. // AreLambdasClosures.java import java.util.function.*; public class AreLambdasClosures { public Function<Integer, Integer> make_fun() { // : int n = 0; return arg -> { System.out.print(n + " " + arg + ": "); arg += 1; // n += arg; // return n + arg; }; } public void try_it() { Function<Integer, Integer> x = make_fun(), y = make_fun(); for(int i = 0; i < 5; i++) System.out.println(x.apply(i)); for(int i = 10; i < 15; i++) System.out.println(y.apply(i)); } public static void main(String[] args) { new AreLambdasClosures().try_it(); } } /* Output: 0 0: 1 0 1: 2 0 2: 3 0 3: 4 0 4: 5 0 10: 11 0 11: 12 0 12: 13 0 13: 14 0 14: 15 */
// AreLambdasClosures2.java import java.util.function.*; class myInt { int i = 0; } public class AreLambdasClosures2 { public Consumer<Integer> make_fun2() { myInt n = new myInt(); return arg -> ni += arg; } }
final
keyword in the definition of n
. Of course, if we apply such a move with any competition, then there will be a problem with a variable shared state.Source: https://habr.com/ru/post/281026/
All Articles