Compare groupingBy() and partitioningBy(). The groupingBy() method is a terminal operation that creates a Map. The keys and return types are determined by the parameters you pass. The values in the Map are a Collection for all the entries that map to that key. The partitioningBy() method also returns a Map. This time, the keys are true and false. The values are again a Collection of matches. If there are no matches for that boolean, the Collection is empty.
I actually found this paragraph very misleading, at the point that I had to go back and review the topic, after many hours spent trying to get and memorize comparators.
For what I finally got, groupingBy() and partitioningBy() methods are not terminal operations and they don't return Map. They aren't Stream's methods, but they are static methods in class Collectors, that returns collector objects. The terminal operation in this case is collect().
Yup, that's exactly right. Typically, people create the groupingBy() collector in the same line as the collect() method call, so it's tempting to think of them as all happening together in the same step. But when you look more closely, you're quite correct that the groupingBy is not terminal, and not even a stream operation... but the collect() is what actually terminates the stream.