23

Consider the following code:

 List<Integer> odd = new ArrayList<Integer>();
 List<Integer> even = null;  
 List<Integer> myList = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
 even = myList.stream()
              .filter(item -> {
                   if(item%2 == 0) { return true;}
                   else { 
                           odd.add(item); 
                           return false;
                   }
              })
              .collect(Collectors.toList());

What I am trying to do here is get the even and odd values from a list into separate lists.

The stream filter() method returns true for even items and the stream collector will collect them.
For the odd case, the filter will return false and the item will never reach the collector.

So I am adding such odd numbers in another list I created before under the else block.

I know this is not an elegant way of working with streams. For example if I use a parallel stream then there will be thread safety issue with the odd list. I cannot run it multiple times with different filters because of performance reasons (should be O(n)).

This is just an example for one use-case, the list could contain any object and the lambda inside the filter needs to separate them based on some logic into separate lists.

In simple terms: from a list create multiple lists containing items separated based on some criteria.

Without streams it would be just to run a for loop and do simple if-else and collect the items based on the conditions.

piet.t
  • 11,718
  • 21
  • 43
  • 52
Roy
  • 235
  • 1
  • 2
  • 7

1 Answers1

41

Here is an example of how you could separate elements (numbers) of this list in even and odd numbers:

List<Integer> myList = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

Map<Boolean, List<Integer>> evenAndOdds = myList.stream()
        .collect(partitioningBy(i -> i % 2 == 0));

You would get lists of even/odd numbers like this (either list may be empty):

List<Integer> even = evenAndOdds.get(true);
List<Integer> odd = evenAndOdds.get(false);

You could pass any lambda with required logic in partitioningBy.

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
  • 10
    When grouping by a condition, you may use `partitioningBy` instead. Besides the possibility to be slightly more efficient, it will always have a result for `true` and `false` in the `Map`, i.e. an empty list if no element fell into that group, rather than `null`. – Holger May 03 '17 at 17:48
  • @Holger Thanks for the insight, updated answer. The empty list vs null is a very useful feature I wasn't aware of and not obvious from the docs. – Manos Nikolaidis May 03 '17 at 17:58
  • 8
    that’s a documentation flaw that has already been identified and [fixed in Java 9](http://download.java.net/java/jdk9/docs/api/java/util/stream/Collectors.html#partitioningBy-java.util.function.Predicate-). – Holger May 03 '17 at 18:00
  • Thanks @ManosNikolaidis. I think this might work. I will give it a try and up vote your answer if it works. Thanks again!! – Roy May 03 '17 at 18:20