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