Closures9:15 with Craig Dennis
A closure allows you to create a lexical scope for functions that will run later. Java handles things by making those values be *effectively* final.
So we know how go create higher order functions by passing a function as 0:00 an argument. 0:04 Another way to create one of these higher order functions is to return a function 0:05 from a method just like you would a value. 0:10 You can use this approach as a function factory of sorts. 0:12 This allows you to configure how the function works from the outside. 0:16 So our problem is we wanna take any date string, process it, and 0:20 return another date string. 0:24 But we want to create that function on the fly. 0:26 As we saw before we can use the date time formatters to help us out. 0:30 Let's do this. 0:33 Okay so let's make our method. 0:35 So let's see, it's going to return a function like we said, right? 0:37 So it's gonna be public static is gonna return a function that 0:41 takes a string of a formatted date. 0:46 And then it's gonna return a string, some other string, another format okay. 0:48 And let's say createDateStringConverter. 0:53 Okay, so that's pretty clear. 0:58 It'll create one of these. 1:02 So we know that it can take a formatter for the way in, so 1:03 we'll call that an inFormatter. 1:07 And then let's do one for out so we'll do a date, time, formatter out. 1:10 Let's out these on two separate lines, 1:13 make that a little bit cleaner. 1:17 Space wise, let's get some more space here. 1:22 Out(Formatter). 1:24 Okay, and we said what we'll do is we'll return a function. 1:27 Okay, so we'll return, and that function's gonna take a string, take a bait string. 1:32 And in the body here, what we'll do is we'll parse that. 1:39 So the function itself will return a LocalDateTime. 1:43 What we'll do is we'll parse that date string that came in 1:48 using our inFormatter, right? 1:52 So we know what the format is coming in. 1:55 And then finally, we'll format using our outFormatter. 1:58 Cool, and so this requires that cuz we're returning a function. 2:03 So that seems pretty cool, right? 2:08 I'm gonna go ahead let's use it. 2:09 I'm gonna take let's get rid of this, all this code here cuz we're gonna recreate 2:10 that pretty easily with our function now. 2:14 So let's get rid of that and let's make a new one of those. 2:17 So we're gonna get back a function that takes a string and returns a string. 2:21 And we'll call it converter. 2:29 And we'll say createDateStringConverter. 2:31 And on the input side, we know that that is .RFC, right, there it is. 2:33 And then for the output, 2:40 let's just do some other one will say basic ISO DateTime. 2:41 Cool. And instead of mapping to that, 2:48 we'll map to a converter. 2:51 And cool, it worked. 2:55 Let's go ahead. I'm just gonna change this just to make 2:56 sure it's not the default there. 2:58 Show off, awesome. 3:00 Now wait a second, let's go look at that method again. 3:03 So you'll notice that these formatters are coming in in the method scope, right? 3:08 And we're using them inside the lambda here which is 3:14 in the scope of this method until we return it. 3:19 Does that mean that these formatters or 3:23 some hell still in scope when we get up here? 3:25 Right this will just float away. 3:27 This one will be an existence on scope but when we use this converter it's there. 3:29 It surely must mean that right away in that scope. 3:34 So what this creates is known as a closure. 3:36 These variables, these inFormatter and outFormatter are captured and 3:40 they're available to the function itself for later when the code runs. 3:45 Remember, this code is lazy and it hasn't ran yet but 3:49 it will some time in the future when something calls the apply method. 3:52 So therefore, 3:56 it needs those variables to execute those variables are stored in lexical scope. 3:57 Here, actually, let's explore it a bit more. 4:03 In the creation of that method, I'm gonna just go ahead and 4:05 in the method body here, we'll make a new local variable in the method scope. 4:09 And it will go away when the method ends, just like normal, right? 4:14 So let's do the meaningOfLife, this is handy if this is something that 4:17 takes a long time to calculate, which it does. 4:22 And of course, the meaningOfLife is 42. 4:25 So to show this off, I'll use it in here, right. 4:27 So we'll just, we're returning a string here, 4:30 let's just return something at the front. 4:32 We'll do the meaning of life, And 4:35 we'll just add some information, a little dash there. 4:39 Okay, therefore, right, this is very clear, this would normally fall off, 4:45 we're gonna use it. 4:49 And then later we're gonna use it, and 4:50 look at that it's outside of the scope, right. 4:52 When this function's called here, that should be gone but 4:55 it's captured, it's pretty cool, right. 4:58 So the variable is in the scope of the function. 5:00 But what happens if that variable changes, what if I increment the meaningOfLife? 5:03 Well look at this, see what this says. 5:11 Variable used in lambda expression should be final, or effectively finally. 5:15 There's an intention action, let's see what it says. 5:20 It says copy meaningOfLife to effectively final temp variable. 5:22 It's all temporary indeed, let's do it. 5:28 Okay, so see what it did? 5:31 It made a new variable called finalMeaningOfLife and we used it here. 5:32 This sort of problem was around in Java 7 as well, and 5:37 you used to have to mark the variables themselves as final and 5:39 they wouldn't changed if you closed over them using an abstract class. 5:43 With Java 8 they made it a little bit more loose but 5:47 they checked that you don't change it. 5:49 So this version is okay and it's trying to protect us from 5:51 breaking the pure function principal of relying on side effects, right? 5:54 However, let's break some big time rules. 5:58 So let's undo that last little change there and 6:01 let's move the meaningOfLife inside the function body and then we'll increment it. 6:05 I just heard you yell. 6:12 Wait a second Craig, that's producing a side effect, 6:14 you just broke a pure function. 6:17 Well nice eyes, I shouldn't be modifying this value should I? 6:19 And it looks like the squiggle agrees. 6:23 So let's see what this intention action is. 6:25 So it says transform meaningOfLife into a final one element, what the, 6:28 let's just do it, let's see what happens. 6:33 Yuck, now we know. 6:35 We shouldn't do this because it makes the function impure, right? 6:38 No side effects but yuck, look at that. 6:40 I really wish intelligent didn't provide this solution, 6:42 this is very obviously a hack. 6:45 And there is most certainly a better way to work around those issue. 6:46 Let's remove the limit, I wanna show you something here. 6:50 Let's come up to this limit here, I'm gonna remove this so 6:52 that we can just take a look. 6:54 Let me go ahead and I'm gonna run this and we'll see that it appears to work. 6:55 So we counted all the way up to 1042, cuz there is 1000 job postings, 7:01 and it's going in order, all the way through. 7:06 You might even argue that that worked correctly. 7:09 But if we were trying to show how many times it ran, like if we 7:11 were really trying to keep track of this meaningOfLife as an increment and 7:15 we wanted to see has it gotten better? 7:17 Remember when we talked about being able to run these streams in parallel? 7:19 Parallelization is out of the scope of this course, 7:23 because I need more practice saying it. 7:26 But first, I'll give you a little taste. 7:28 So if I simply switch this call here to stream to be called parallelStream. 7:29 Parallelalized, what it will do now is it will spread its execution over a number of 7:37 cores available on your machine. 7:42 So now when I run this, check this out. 7:44 The numbers are all goofed up, right? 7:48 So they're not going in order. 7:51 And that's because each core is taking this functions and running them across. 7:52 See when I run this now? 7:57 The number is jumping all over the place. 7:58 Right, if we were doing something without side effects outside or 8:01 just trying to print an order, this could be disastrous. 8:04 So I'm gonna back that up. 8:08 I do not like this we're no, we're gonna keep that function pure. 8:09 The meaningOfLife is important. 8:13 Let's get the meaning of life over there. 8:18 Let's put that back. 8:23 So Java makes sure that the values we capture here are effectively final, 8:24 follow its lead and keep things pure. 8:30 The closures are so cool and they let you capture values that are effectively final. 8:33 Now, this is super handy in helping to create configured functions, 8:38 just like we did here. 8:41 Because our function is lazy, it needs to hold on to that lexical scope, so 8:42 can use it whenever it's called. 8:46 Speaking of lazy that is the last item in 8:48 our parking lot and you got this one, right? 8:53 Streams are lazy, they are waiting will be called upon and 8:56 the only one called upon then they do work, right? 8:59 You pass around powerful functions that are lazily awaiting you to execute them. 9:02 You though, you are not lazy. 9:06 You made it all the way here to the end of the course. 9:08 I am very impressed with your dedication. 9:11 Let's wrap things up right after this quick break. 9:13
You need to sign up for Treehouse in order to download course files.Sign up