If you want to take a look a small sample of objects in a Stream sequence, feel free to use the limit() method.

In this guide, I'll show you how to do that.

It's a fairly easy process. Just keep in mind that limit() is often used with complex, chained operations. Here, I'll just focus on doing something easy so you can get your hands dirty.

Then you can adapt its usage as you see fit.

So let's get started.

The CRM App

Let's say you're building a CRM app. It does the normal stuff that CRM apps do: tracks activities between sales reps and contacts.

Those activities get stored in a MongoDB database as documents. Each document persists info like the title of the activity as well as the type, outcome, location, start time, end time, notes, and the contact involved.

As it stands right now, if you retrieve all the documents from the activities collection, the resulting data set looks like the JSON dump at this link.

As you can see, we're not messing around here. You're going to be working with real-world data.

On the Java side, the Activity class with its related classes mimic the data set that you see above. You can see examples of those classes over on GitHub.

So you can just do a findAll() on that collection above and get a List of Java objects that represent that JSON output. Then, you can use a Java Stream to filter, find, and map as you see fit.

That's what you'll do in this guide.

And, yes, you could do that kind of stuff with MongoDB aggregations. But you're not here to learn about aggregations are you?

Take It to the Limit

Management has approached you about the CRM app and told you that they'd like to "keep tabs" on the latest sales activities. 

To that end, you'll create a UI that looks like a dashboard. Okay, it will be a dashboard.

One of the panels in that dashboard will show the most recent 5 sales activities. That way, management can take a quick look and see what's going on with all the latest happenings.

But your boss says they only want to see activites that are getting results. In other words, sales activities with some type of outcome.

So here's what you're going to do: you're going to retrieve all activities in the MongoDB collection sorted by date in descending order. Then, you're going to filter them so that you only see activities with results. Then, you'll just grab the top five activities and spit them out on the panel.

For the purposes of this guide, I'll just cover the back-end work. 

Here's what that code looks like:

List<Activity> activities = activityRepo.findAllByOrderByStartDateDesc();

List<Activity> filteredActivities = activities
                .stream()
                .filter(activity -> activity.getOutcome() != null)
                .limit(5)
                .collect(Collectors.toList());

try {
    ObjectMapper objectMapper = new ObjectMapper();
    System.err.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(filteredActivities));
} catch (Exception e) {
    e.printStackTrace();
}

First thing's first: the top line grabs all activities from the MongoDB collection and orders them by starting date in descending order.

That method name, by the way, is not misconstructed. That's how you have to word it if you're not using any criteria in your search. There's nothing after "findAllBy" that filters the search because that's not what you're doing here.

Anyhoo, thanks to the Spring framework, you only need to name the method as you see above to give you everything in reverse chronological order. That's a pretty cool feature, actually.

And yes, once more, there are other ways to accomplish what you're trying to accomplish with Stream. But you're here to learn about Stream and limit(). So that's how you'll skin this cat.

Now take a look at the second line where the code gets to the Stream work. 

The code converts the List object to a Stream object. It does that with the stream() method.

Once the code has a handle on a Stream object, it filters the list of activities. That filter() method takes out any Activity objects that don't have an outcome.

But remember: you only want a maximum of five results. Odds are better than even money that even with the filter, you're going to end up with more than five results.

Enter limit().

The limit() method accepts a Long value as its sole parameter. In this case, the code sets it to five because that's what management wants.

Always keep the boss happy.

But wait a second. How can the code above do filter() and limit() together?

To answer that question, we must take a trip down Memory Lane.

Your Interface Is Fluent

Way back in the mid-2000's, some guy named Martin Fowler (kind of a big deal in modern-day software development) coined the phrase "Fluent Interface."

Why did he coin it? To describe a new design pattern.

In this case the pattern involves a method that returns the object itself. The reason it does that is so that developers can use something called method-chaining to reduce lines of code and make everything look neat and tidy.

And what does all this have to do with the price of tea in southwest suburban Bavaria?

The Stream class employs the fluent interface. To answer the question at the end of the previous section, the code can do filter() and limit() together because both of those methods return the Stream object itself.

When the code invokes filter(), the result it gets is the Stream object with fewer elements in the sequence.

And since you've still got an instance of the Stream object, you can invoke limit(). That method also returns the Stream object.

So, theoretically, you could keep on invoking operations forever as long as those operations all return an instance of Stream. And many of them do.

At the end of the day, though, you don't want a Stream object. You want a List object.

That's why you see the collect() method at the very end of the method chain above. That translates the Stream to a List.

A Time to Test

Now let's make sure the code above works.

You'll see at the very end of the code block above that it prints out the list of Activity objects in JSON format. That makes it easy for you to do a quick sanity check and ensure that everything is up to snuff.

So, given the dataset that I referenced earlier, if you run that code, you'll see this output:

[ {
  "id" : "601fe6f38fc6df7eddcf3af9",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbc",
    "name" : "Phone Call",
    "icon" : "phone"
  },
  "title" : "Went with another company",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06b",
    "name" : "Not Interested"
  },
  "notes" : "Decided to go with another company for services. Will follow up in several months.",
  "location" : null,
  "startDate" : 1612358100000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff96",
    "firstName" : "Mercy",
    "lastName" : "Windsor",
    "account" : {
      "id" : "60141483b56f731fe77e902f",
      "name" : "Cloud City"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe5ee8fc6df7eddcf3af5",
  "type" : {
    "id" : "6016a64c33ffe20d90fa8232",
    "name" : "Email",
    "icon" : "email"
  },
  "title" : "Email followup",
  "outcome" : {
    "id" : "6016a407ae0e817a115fd069",
    "name" : "Did Not Respond"
  },
  "notes" : "Followup email after lunch appointment.",
  "location" : null,
  "startDate" : 1612357200000,
  "endDate" : null,
  "contact" : {
    "id" : "6014199147692f2a4194ff97",
    "firstName" : "Blinky",
    "lastName" : "Scene",
    "account" : {
      "id" : "60141483b56f731fe77e9030",
      "name" : "For Luke"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe3848fc6df7eddcf3aef",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : "Good conversation. Ready to pull the trigger.",
  "location" : "Izzy's",
  "startDate" : 1612281600000,
  "endDate" : 1612285200000,
  "contact" : {
    "id" : "6014199147692f2a4194ff99",
    "firstName" : "Opus",
    "lastName" : "Mei",
    "account" : {
      "id" : "60141483b56f731fe77e9032",
      "name" : "Sandz"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe4f98fc6df7eddcf3af4",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : "Talked more about Java Enterprise and the work we do. Gave highlights of some of the solutions we've delivered in the past.",
  "location" : "Loony's",
  "startDate" : 1611939600000,
  "endDate" : 1611943200000,
  "contact" : {
    "id" : "6014199147692f2a4194ff97",
    "firstName" : "Blinky",
    "lastName" : "Scene",
    "account" : {
      "id" : "60141483b56f731fe77e9030",
      "name" : "For Luke"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
}, {
  "id" : "601fe6aa8fc6df7eddcf3af8",
  "type" : {
    "id" : "6016a960ca8c08019b4dfcbe",
    "name" : "Appointment",
    "icon" : "calendar_today"
  },
  "title" : "Lunch",
  "outcome" : {
    "id" : "6016a408ae0e817a115fd06a",
    "name" : "Interested"
  },
  "notes" : null,
  "location" : "Izzy's",
  "startDate" : 1611854100000,
  "endDate" : 1611857700000,
  "contact" : {
    "id" : "6014199147692f2a4194ff96",
    "firstName" : "Mercy",
    "lastName" : "Windsor",
    "account" : {
      "id" : "60141483b56f731fe77e902f",
      "name" : "Cloud City"
    },
    "salesOwner" : {
      "id" : "6014081e221e1b534a8aa432",
      "firstName" : "Milton",
      "lastName" : "Jones",
      "username" : "milton"
    }
  }
} ]

And that's exactly what you'd expect. Five activities sorted in descending order by start date. Also, each activity has an outcome so you know the filter worked.

You have succeeded.

Wrapping It Up

Now you know how to limit yourself.

At this point, it's up to you to apply what you've learned here. Use limit() in your own applications to display just a subset of objects in a List.

Think about how you might use it with other methods besides filter(). Do your own method-chaining.

And, as always, have fun!