Collecting and Limiting11:16 with Craig Dennis
Let's explore how to collect elements into a new collection.
Example Job Titles
// "Senior Dev", "Jr. Java Engineer", "Java Evangelist", "Junior Java Dev", "Sr. Java Wizard Ninja", "Junior Java Wizard Ninja", "Full Stack Java Engineer"
Intermediate operations are further divided into stateless and stateful operations. Stateless operations, such as filter and map, retain no state from previously seen element when processing a new element -- each element can be processed independently of operations on other elements. Stateful operations, such as distinct and sorted, may incorporate state from previously seen elements when processing new elements.
So our imperative method that prints out Portland Job is looking similar to our 0:00 declarative stream based approach. 0:04 Now, I'd like to add a little complexity to show off some of the real power of 0:07 streams which their declarative style. 0:11 Okay, so how about this? 0:13 How about instead of printing, let's do this. 0:15 Why don't we create a method, 0:18 that returns the first three jobs in our list that are junior jobs. 0:20 So let's solve that imperatively first. 0:25 Okay, so let's see. 0:27 So we'll say, private static. 0:28 We're gonna have it return, instead of void here. 0:34 We'll have it return a list of jobs and 0:35 we will make that, we're gonna get three, getThreeJuniorJobsImperiatively. 0:39 List, we're gonna give it a list of our all the jobs and we'll filter that down. 0:50 Okay, we probably wanna create a separate list, right? 0:56 So we're gonna make a new list here. 1:00 So we'll say List Job and we'll call those juniorJobs to not confuse the two. 1:02 And we'll make a new ArrayList, great. 1:08 Okay, and now we wanna loop through the jobs that were passed in. 1:12 Okay, so again that's for 1:16 Job_job and jobs, okay. 1:20 And then we'll search for certain terms. 1:24 It's a little cheesy, but we should lower case probably. 1:25 Let's lower case the title job. 1:29 So let's say string title = job.getTitle, and we'll say toLowerCase. 1:30 Okay, so now we've got a lower case title. 1:37 And now we know that if the title.contains, let's see junior or 1:39 if the title.contains let's say another like the, 1:46 the abbreviation style of junior. 1:52 If that contains either one of those it's probably a junior job and so 1:56 we'll add to that list, right? 1:59 We'll say add job. 2:01 If this happens to be the third one, we don't need to keep going any more, right? 2:04 We can actually break this for loop, 2:09 because why keep looking at the jobs, right? 2:12 So we'll say if the juniorJobs.size >= 3 we will break. 2:15 Break is known to break your code, don't forget that. 2:24 So, all right, so here we go. 2:29 So we will return our juniorJobs. 2:29 And so we'll say get three junior jobs imperatively and 2:33 let's go up here and let's explore that. 2:37 So we'll getThreeJuniorJobsImperatively and we'll pass at our jobs. 2:41 Let's take a look and let's see how we did. 2:45 I forgot that I need to print that out, didn't I? 2:48 So let's just use our new friend, we've got a list here which has forEach and 2:50 we'll put System.out and we'll print out, println, there we go. 2:56 Cool, so there are three that we got. 3:03 Okay, and now let's try the stream version of that same operation. 3:06 So again, we want the first three juniorJobs, and we want to return them. 3:10 So we'll make a new type declaration here. 3:15 We'll say, private static List Job and 3:17 we'll say getThreeJuniorJobsStream. 3:24 And we'll do the same sort of signature here, List<Jobs> jobs, all right? 3:30 And now instead of doing like we did here where we made it a new array list, 3:37 streams can actually collect values. 3:40 They can create a new collection just like we did imperatively, but 3:43 they can do it themself. 3:48 So instead of making a new collection, 3:49 let's just make sure that we return from the stream. 3:51 So we're gonna say, jobs.stream, okay? 3:56 And we're gonna come down and we're gonna do a filter. 3:59 Now we could basically just drop this code in here but 4:02 why don't we refactor this code and make it shared, right? 4:05 So let's do this. 4:11 Okay, so why don't we take this little method here and let's make our own method. 4:14 Let's make, we'll make a private static method that returns a Boolean, 4:17 that says, isJuniorJob and we'll make it take a job, right? 4:25 So you pass in a job, and it will return a true or false, and 4:31 we already have the code for this. 4:34 So we can do this here, we can just copy this up here. 4:35 And we are just going to return from this 4:38 method the expression here, right? 4:43 And so it'll be a logical or that will get returned here on either one of those. 4:47 So now we can just say let's get rid of this line here and we'll say if 4:52 isJuniorJob and we'll pass in the job there, that feels better on this one. 5:01 And then let's see how that fills up here. 5:06 So now we can filter and we can use a method reference, 5:08 cuz remember filter takes a predicate, okay? 5:12 So we can say App, and it's suggesting it here, 5:16 it's suggesting that a predicate of job, right? 5:19 So isJuniorJob, now because it takes an item and returns a true, 5:21 it's a predicate matches the method signature or the function shape. 5:25 Now remember we only want three, right? 5:30 We only want to get three of these. 5:34 So we want to limit. 5:36 Now I only want three. 5:42 Limit is an intermediate method on streams. 5:45 Now remember this means that nothing will happen just because I wrote limit here, 5:47 it's still lazy. 5:51 And it will just be part of the functional pipeline. 5:53 But limit is a little different then our filter method. 5:56 Filter is what is known as a stateless intermediate function, 6:00 it doesn't care about what's going on around it. 6:03 It's always going to do the same thing no matter what is going on 6:06 in the pipeline around it. 6:09 It does not care about state. 6:11 But limit here has some knowledge of the stream so 6:12 it's categorized as a stateful intermediate operation. 6:15 Now the state that this method knows about is how many jobs have come through. 6:19 It also is known as a short-circuiting operation. 6:23 So just like how our logical expressions like ands or 6:27 ors can be short circuited like this, right? 6:30 If either one of these is true, 6:32 there's no need to check the rest of them, can be short circuited. 6:34 And just like that, limit here will short circuit the stream's processing. 6:37 So limit is said to be a stateful short circuiting intermediate operation. 6:42 So I've added some more in the teacher's notes. 6:48 But I just wanted to let you hear some of these terms. 6:50 You'll see these categorization of intermediate methods 6:53 as you explore what streams can do. 6:56 And I just wanted to get you a little bit comfortable with them. 6:58 Now don't worry, we'll revisit them. 7:02 So now we've got our stream limiting to three junior jobs. 7:04 We just need to collect them somehow so that we can return them. 7:08 Well, lucky for us there is a terminal operation named quite intuitively collect. 7:11 So let's do that. 7:17 Let say .collect. 7:17 Now there are different ways to collect items from the stream but 7:20 what we want is a list, right? 7:24 We wanna return a list of jobs. 7:26 So we can do just that, we can say collectors.toList. 7:29 And if we switch these to our function 7:33 and we run, we'll see that it's working. 7:42 And that's pretty isn't it? 7:47 This looks really nice. 7:48 I move, I'm gonna go ahead and move this out of the way so 7:53 that we can get these together. 7:56 Let's move this up here. 7:57 There we go. 7:59 It's pretty, isn't it? 8:01 So let's walk it really quick. 8:03 Now remember these go one at a time so let's just throw some jobs up here. 8:04 I've got a list of possible job title that are in the teacher's notes. 8:08 So let's just go ahead and I'm gonna push just like we did before. 8:12 I'll push this here so we can imagine what's going on. 8:17 I'll break this so we have some clear, more clear. 8:20 All right, so let's make it rain some jobs. 8:23 So a senior dev comes through, drops the first one through, is it a junior job? 8:26 Nope, it's not. 8:31 So next up, we actually have one. 8:32 We have a junior job engineer. 8:33 It comes through, it hits limit, and 8:34 our limit method keeps some state that a job has passed through and 8:37 a new bucket is conceptually created to collect all these job raindrops, right? 8:40 So our bucket now has a junior Java Engineer in it. 8:45 And then Java Evangelist comes through. 8:49 It's not a junior Java job. 8:51 The next one comes through a Junior Java Dev and it does some of it's two, 8:53 and then our next one rejects, the senior Java Wizard does not make it through but 8:55 the Junior Java Wizard Ninja does. 9:00 And then limit short circuits the stream. 9:03 So the remaining here, 9:08 this Full Stack Java Engineer never runs through, because we now have enough. 9:09 So finally, we collect all of those and return them to our caller. 9:15 Now look at the difference between these two methods. 9:21 Do you see how much more concise the declarative stream-based approach is? 9:23 Now oftentimes people new to the declarative approach 9:27 make a very common mistake. 9:30 So you could, in fact, well here, let me show you, but wait. 9:33 First, promise me something. 9:37 Promise me that you won't try this at home. 9:38 Do not try this at home. 9:40 I'm gonna copy the code and I am going to comment it out. 9:42 And I'll repaste it here. 9:47 What we could do, is this. 9:48 So we could make a new array list just like we did down here. 9:52 In fact, I'm just gonna copy this line and we'll put it here, okay? 9:55 And instead of using a collect, we could use a forEach, right? 9:59 We'll do a forEach, and that takes a consumer and 10:06 what that will do is that will push each one of those jobs through, right? 10:10 And we could say junior jobs and call add on it. 10:15 And then we would just return our junior jobs. 10:21 Now this here is actually an example of a method relying on a side effect. 10:25 This for each here requires something that's outside of the stream, right? 10:31 It's requiring this juniorJobs, it's outside of the stream. 10:35 This is just like the balloon in that Rube Goldberg machine example. 10:39 And although it works in this case, it's bad form. 10:42 Because you could solve this declaratively without side effects, 10:45 as we saw in this code here. 10:48 I'm keeping the topic of side effects parked in our parking lot and 10:51 I will refer back to this example when we unpark it more. 10:54 Let's undo our way back. 10:57 Undo, undo, don't you wish you could do this in real life, wouldn't that be great. 11:00 Let's get back to the pretty. 11:06 There it is, all right, save that. 11:09 So let's take a quick break and then take a look at transforming values. 11:12
You need to sign up for Treehouse in order to download course files.Sign up