Filtering9:36 with Craig Dennis
Sometimes you only want to keep certain elements from your stream, filtering helps do just that.
All right, we now have a list of Java jobs. 0:00 I'd like to figure out which of those jobs are here in Portland where I live. 0:03 I'm sure every single one of those jobs aren't here in town, so 0:07 I'll need to filter out the ones in Portland Oregon. 0:11 So let's take a quick second and solve the problem imperatively first, and 0:14 then we'll get declarative. 0:18 So this is a pretty common ceremony that we need to do, right. 0:20 So I'm gonna get rid of this line here. 0:23 So what we need to do is loop through these jobs, right. 0:26 So we say for (Job job : jobs), right, this jobs that was passed in. 0:30 And let's see, if the job, so 0:35 there is a thing here called getState() and I need to see Oregon, and 0:39 Oregon is OR not to be confused with or. 0:43 We wanna look at everything words in Portland, so 0:48 we wanna get where the job state is Oregon and the city 0:52 equals("Portland"), okay. 0:58 So, we're gonna open that if block and close that and 1:04 then we wanna print that out, right. 1:07 So, that's gonna print all of the jobs that are in Portland, Oregon. 1:11 Let's run that. 1:13 Okay, so we've got like, five jobs that were posted here in the last day. 1:15 Now, note, 1:19 this is the results of the 2String method that's in the job class here. 1:20 If we go take a look at Job, there's a 2String method here. 1:24 So that's what's going on. 1:28 That's what this mess here is. 1:29 So now, let's refactor this into a method of itself. 1:33 So we can keep it around for reference, so I'm gonna come up and 1:37 choose Refactor this and I am going to choose Method. 1:40 And we will make this a private method, and 1:46 we're gonna name it Print Portland Jobs. 1:51 Imperatively, I'm gonna say, okay. 1:56 And it'll take a list of jobs. 1:59 So now, we can come back and take a look at what we had before. 2:02 So, now, let's do this declaratively, right? 2:04 So there's several ways to create streams from our data but 2:09 most collections offer a new stream method. 2:12 Let's call it. 2:15 So we have jobs, right? 2:15 So jobs is a collection, it's a list. 2:16 We're gonna say stream. 2:18 Okay so what did we want to do? 2:21 Yeah, we want to filter the jobs that are in Portland, Oregon. 2:23 So now, quite intuitively we just say that we want to filter the stream. 2:27 So we say .filter. 2:31 As you can see, it takes a predicate, which was the function shape that we saw 2:34 that takes an item, and then returns a boolean a true or false. 2:38 So the way that the filter method works is if the predicate returns true, 2:43 it will keep the item. 2:47 So the item in this case is going to be a job. 2:49 So why don't we name our parameter job? 2:53 And remember, it's gonna figure out the type, right? 2:57 It's gonna know that it is off type job, just by the way it's working. 3:00 Pretty cool, right? 3:03 Because it's only one parameter, I don't need the parenthesis In the body of 3:04 the lambda will be to get the state and see if it equals Oregon, right. 3:09 So we're gonna say job.getState().equals("OR"). 3:14 Now, remember this equals method returns a true or 3:20 false and automatically The return statement is assumed. 3:23 So it's gonna return true or false. 3:28 It's gonna return whatever this is. 3:30 So let's introduce some manners early, here on. 3:32 Now, filter is an intermediate method. 3:35 Now, remember that each call to these intermediate methods 3:38 is going to return a stream, so that you can chain them together. 3:41 And these get pretty long pretty quick. 3:44 So typically, each of these are written on a line all their own. 3:47 Now, it's a little strange looking at first but 3:52 I promise you if you see them all written out in one line you will go rude. 3:54 And fix it, just like this. 4:00 They pile up pretty quick. 4:03 Now, speaking of which, let's add another filter here. 4:05 So we need to get the city, right? 4:12 So we'll do job We're gonna do job.getCity, 4:13 we'll say equals Portland. 4:18 So, now we have two intermediate operations, 4:23 now we need to add a terminal operation. 4:27 So, very similar to how iterables provide a forEach method, so 4:30 does the stream interface. 4:34 So let's do that, forEach, And 4:35 then we're gonna use our method reference to print line on System.out. 4:40 So System.out and we'll just get to print line here so 4:47 we'll print each one of those through in I need a cynical. 4:52 Okay, so we are gonna run this code, let's take a look. 4:55 And, boom, it works, same five jobs. 5:02 Now, did anything in that feel weird? 5:05 Were you wondering why we made two 5:08 filter statements instead of one expression like we did here? 5:10 Does writing two methods here feel like we are doing extra unnecessary work? 5:14 Now, it does seem that way if we look at thing from an imperative point of view. 5:20 But let's take a second to break this down. 5:25 Now, this is a common mental hurdle, so 5:27 let's take a gander at the imperative printing style over here. 5:29 In our expression, we are joining two expressions with a double ambersand, 5:34 meaning that this must be true and this must be true. 5:39 As you probably know, Java will optimize or 5:44 short circuit the expression if this first one here is false. 5:47 It will never run this one, because they both need to be true in order to continue. 5:51 So if we look at this stream code here with a bad assumption, 5:56 that these are working in an imperative way. 6:01 Again, this is not what is happening but it's a common misconception. 6:03 It seems like this line here is gonna be expensive, right? 6:08 It's gonna take all of the Oregon ones and then pile them up and 6:12 then do the next one, the next filter, and then it does it again. 6:15 Now, imperatively, it would seem like we made some sort of new data structure that 6:19 returns that and so on but wait, this isn't what is happening. 6:23 Really what is happening is these methods are chained or 6:28 fused together into a pipeline. 6:31 You need to visualize these intermediate operations like this filter, 6:33 these two as a single fused together method. 6:37 So here, try this. 6:42 Imagine we have this list of jobs, and imagine it being, well, 6:43 just like one of those marbles that we talked about dropping into the stream. 6:47 So here, let's do this. 6:50 Let's set up some fake data here. 6:51 So let's say that we have a job that's in Louisville Kentucky. 6:54 And a job that is in Bend Oregon. 7:01 So we're gonna do this one at a time, just one at a time. 7:05 So that's the thing to remember here. 7:09 When you look at these streams, it's one by one, 7:10 the job's gonna go through the pipeline. 7:13 So the first one comes through one by one. 7:15 The first one is Louisville. 7:19 Louisville, Kentucky, it comes in, the first job comes in. 7:21 Let's drop that marble comes in, the job, does it equal Oregon? 7:23 No, it does not. 7:28 Bloop, it gets discarded. 7:29 Okay? 7:31 So it's sort of the same as the short circuiting, right? 7:32 This is false. 7:35 Why keep going? 7:35 Why keep going to this next one? 7:36 It doesn't need to. 7:37 So it's gone. 7:38 The next one comes in, and it's for Bend, Oregon, and it drops through. 7:40 Drop that marble through. 7:43 The first one is true, right? 7:44 Then it moves down to the next one. 7:48 Is it not this one? 7:49 And then it discards it. 7:50 Now, if that didn't make sense, rewind me a bit and watch it again. 7:52 We're going to build on these concepts. 7:56 And I wanna make sure that you understand that these intermediate operations 7:59 are a pipeline that you pass each of the items through from the source one by one. 8:03 Not all at once. 8:08 So I'm gonna refactor this, I'm gonna highlight. 8:09 And I'm gonna choose extract method. 8:15 And we're gonna say print PortlandJobs, 8:19 we'll call it Stream Cool, 8:23 and let's just run it make sure that, that still works, awesome. 8:29 So the way this works we're gonna keep these methods around. 8:33 So you can kind of see the difference between the imperative and 8:36 the declarative style. 8:39 And feel free to explore around. 8:40 So that's looking pretty good, right? 8:42 So not only does the method on each line look more maintainable, right? 8:44 Each one of these methods on it's own line. 8:48 You can also comment parts out like this. 8:50 So let's image that I wanted to see all jobs in Oregon, so 8:53 I could comment out this intermediate abrasion really easy. 8:57 So then I'm gonna go ahead and run it. 9:01 And we'll see here that there's some stuff in Beaverton and Hillsborough, 9:07 which are bordering. 9:11 See, look I can get this job here at Nike headquarters in Beaverton, 9:13 a bordering city to Portland. 9:17 So let's take a look at these two on the screen at the same time. 9:19 So these are pretty similar, right? 9:24 Now, a common need for filtering is to produce a subset of items. 9:27 Here we're just printing them out. 9:31 Let's practice some more filtering right after this quick break. 9:32
You need to sign up for Treehouse in order to download course files.Sign up