Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses 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.
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
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 date 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 are
3:23
somehow still in scope
when we get up here?
3:25
Right? This would just float away.
3:27
This one will be in existence on the 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 meaningOfLife, 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 principle
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 IntelliJ
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
these 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're waiting to be called upon and
8:56
only when 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 upYou need to sign up for Treehouse in order to set up Workspace
Sign up