Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Journey's End – Collection and Reduction in the Stream API

449 views

Published on

Popular tutorial (81/85 positive ratings) at JavaOne, San Francisco, October 2015. Video of earlier version (JavaOne 2014) is at https://www.youtube.com/watch?v=6tFZelz7Gvg.

Published in: Software
  • Be the first to comment

Journey's End – Collection and Reduction in the Stream API

  1. 1. Journey’s End Collection and Reduction in the Stream API JavaOne, October 2015
  2. 2. Developer, designer, architect, teacher, learner, writer Maurice Naftalin Co-author Current Projects www.lambdafaq.org 2
  3. 3. • Why collectors? • Using the predefined collectors • Intermission! • Worked problems • Writing your own Journey’s End – Agenda
  4. 4. Journey’s End, JavaOne, October 2015 Example Domain city: City name: String age: int Person Person amy = new Person(Athens, "Amy", 21);
 ... List<Person> people = Arrays.asList(jon, amy, bill);

  5. 5. Journey’s End, JavaOne, October 2015 Collectors: Journey’s End for a Stream The Life of a Stream Element • Born (at a spliterator) • Transformed (by intermediate operations) • Collected (by a terminal operation)
  6. 6. Journey’s End, JavaOne, October 2015 Collectors: Journey’s End for a Stream The Life of a Stream Element • Born (at a spliterator) • Transformed (by intermediate operations) • Collected (by a terminal operation)
  7. 7. Journey’s End, JavaOne, October 2015 Collectors: Journey’s End for a Stream The Life of a Stream Element • Born (at a spliterator) • Transformed (by intermediate operations) • Collected (by a terminal operation)
  8. 8. Journey’s End, JavaOne, October 2015 Collectors: Journey’s End for a Stream The Life of a Stream Element • Born (at a spliterator) • Transformed (by intermediate operations) • Collected (by a terminal operation)
  9. 9. Journey’s End, JavaOne, October 2015 Collectors: Journey’s End for a Stream ? The Life of a Stream Element • Born (at a spliterator) • Transformed (by intermediate operations) • Collected (by a terminal operation)
  10. 10. Journey’s End, JavaOne, October 2015 Terminal Operations – Search operations – Side-effecting operations – Reductions

  11. 11. Journey’s End, JavaOne, October 2015 Search Operations Search operations - • allMatch, anyMatch • findAny, findFirst boolean allAdults = people.stream()
 .allMatch(p -> p.getAge() >= 21);

  12. 12. Journey’s End, JavaOne, October 2015 Side-effecting Operations Side-effecting operations • forEach, forEachOrdered
 
 people.stream()
 .forEach(System.out::println); • So could we calculate total ages like this?
 
 int sum = 0;
 people.stream()
 .mapToInt(Person::getAge)
 .forEach(a -> { sum += a }); people.stream()
 .forEach(System.out::println);
 int sum = 0;
 people.stream()
 .mapToInt(Person::getAge)
 .forEach(a -> { sum += a; });

  13. 13. Journey’s End, JavaOne, October 2015 Side-effecting Operations Side-effecting operations • forEach, forEachOrdered
 
 people.stream()
 .forEach(System.out::println); • So could we calculate total ages like this?
 
 int sum = 0;
 people.stream()
 .mapToInt(Person::getAge)
 .forEach(a -> { sum += a }); people.stream()
 .forEach(System.out::println);
 int sum = 0;
 people.stream()
 .mapToInt(Person::getAge)
 .forEach(a -> { sum += a; });
 Don’t do this!
  14. 14. Journey’s End, JavaOne, October 2015 • Using an accumulator: Reduction – Why? int[] vals = new int[100]; Arrays.setAll(vals, i -> i); int sum = 0; for (int i = 0 ; i < vals.length ; i++) { sum += vals[i]; }

  15. 15. Journey’s End, JavaOne, October 2015 • Using an accumulator: Reduction – Why? int[] vals = new int[100]; Arrays.setAll(vals, i -> i); int sum = 0; for (int i = 0 ; i < vals.length ; i++) { sum += vals[i]; }
 0 1 2 3 + +
  16. 16. Journey’s End, JavaOne, October 2015 • Using an accumulator: Reduction – Why? int[] vals = new int[100]; Arrays.setAll(vals, i -> i); int sum = 0; for (int i = 0 ; i < vals.length ; i++) { sum += vals[i]; }
 0 1 2 3 + + +
  17. 17. Journey’s End, JavaOne, October 2015 • Avoiding an accumulator: Reduction – Why?
  18. 18. Journey’s End, JavaOne, October 2015 • Avoiding an accumulator: Reduction – Why?
  19. 19. Journey’s End, JavaOne, October 2015 • Avoiding an accumulator: Reduction – Why? int[] vals = new int[100]; Arrays.setAll(vals, i -> i); OptionalInt sum = Arrays.stream(vals) .reduce((a,b) -> a + b);
 + + + 1 2 30
  20. 20. Journey’s End, JavaOne, October 2015 • Avoiding an accumulator: Reduction – Why? int[] vals = new int[100]; Arrays.setAll(vals, i -> i); OptionalInt sum = Arrays.stream(vals) .reduce((a,b) -> a + b);
 + + + 1 2 30 + + +
  21. 21. Journey’s End, JavaOne, October 2015 • Avoiding an accumulator: Reduction – Why? int[] vals = new int[100]; Arrays.setAll(vals, i -> i); OptionalInt sum = Arrays.stream(vals) .reduce((a,b) -> a + b);
 BinaryOperator must be associative! + + + 1 2 30 + + +
  22. 22. Journey’s End, JavaOne, October 2015 • Avoiding an accumulator: Reduction – Why? int[] vals = new int[100]; Arrays.setAll(vals, i -> i); OptionalInt sum = Arrays.stream(vals) .reduce((a,b) -> a + b);
 BinaryOperator must be associative! a + (b + c) = (a + b) + c + + + 1 2 30 + + +
  23. 23. Journey’s End, JavaOne, October 2015 Why Reduction? 0 1 2 3 4 5 6 7 + + + + + + +
  24. 24. Journey’s End, JavaOne, October 2015 Why Reduction? 0 1 2 3 4 5 6 7 + + + + + + +
  25. 25. Journey’s End, JavaOne, October 2015 Why Reduction? 0 1 2 3 4 5 6 7 + + + + + + + Intermediate operations
  26. 26. Journey’s End, JavaOne, October 2015 Reduction on ImmutableValues Reduction works on immutable values too BigDecimal[] vals = new BigDecimal[100]; Arrays.setAll(vals, i -> new BigDecimal(i)); Optional<BigDecimal> sum = Arrays.stream(vals) .reduce(BigDecimal::add);

  27. 27. Journey’s End, JavaOne, October 2015 Reduction on ImmutableValues Reduction works on immutable values too BigDecimal[] vals = new BigDecimal[100]; Arrays.setAll(vals, i -> new BigDecimal(i)); Optional<BigDecimal> sum = Arrays.stream(vals) .reduce(BigDecimal::add);

  28. 28. Journey’s End, JavaOne, October 2015 Reduction to Collections?
  29. 29. Journey’s End, JavaOne, October 2015 Reduction to Collections? This also works with collections – sort of ... • for each element, client code creates a new empty collection and adds the single element to it • combines collections using addAll
  30. 30. Journey’s End, JavaOne, October 2015 Reduction to Collections? This also works with collections – sort of ... • for each element, client code creates a new empty collection and adds the single element to it • combines collections using addAll We can do better!
  31. 31. Journey’s End, JavaOne, October 2015 Reduction over an Identity BigDecimal[] vals = new BigDecimal[100]; Arrays.setAll(vals, i -> new BigDecimal(i)); BigDecimal sum = Arrays.stream(vals) .reduce(BigDecimal.ZERO,BigDecimal::add);

  32. 32. Journey’s End, JavaOne, October 2015 Reduction over an Identity BigDecimal[] vals = new BigDecimal[100]; Arrays.setAll(vals, i -> new BigDecimal(i)); BigDecimal sum = Arrays.stream(vals) .reduce(BigDecimal.ZERO,BigDecimal::add);
 Works for immutable objects:
  33. 33. Journey’s End, JavaOne, October 2015 Reduction over an Identity + + + 0 1 2 3 + + + 0 4 5 6 7 0 ++ +
  34. 34. Journey’s End, JavaOne, October 2015 Reduction to Collections?
  35. 35. Journey’s End, JavaOne, October 2015 Reduction to Collections? Reduction over an identity doesn’t work with collections at all • reduction reuses the identity element
  36. 36. Journey’s End, JavaOne, October 2015 Reduction to Collections? Reduction over an identity doesn’t work with collections at all • reduction reuses the identity element We’ve got to do better!
  37. 37. Journey’s End, JavaOne, October 2015 The Answer – Collectors a a a e0 e1 e2 e3 a a a e4 e5 e6 e7 aa c a: accumulator c: combiner
  38. 38. Journey’s End, JavaOne, October 2015 The Answer – Collectors a a a e0 e1 e2 e3 a a a () -> [] e4 e5 e6 e7 aa c a: accumulator c: combiner () -> []
  39. 39. Journey’s End, JavaOne, October 2015 Collectors So to define a collector, you need to provide • Supplier • Accumulator • Combiner That sounds really hard! Good then that we don’t have to do it • – very often
  40. 40. Journey’s End, JavaOne, October 2015 Collectors API Factory methods in the Collectors class.They produce standalone collectors, accumulating to: • framework-supplied containers; • custom collections; • classification maps.
  41. 41. • Why collectors? • Using the predefined collectors • Intermission! • Worked problems • Writing your own Journey’s End – Agenda
  42. 42. Journey’s End, JavaOne, October 2015 Predefined Standalone Collectors – from factory methods in Collections class • toList(), toSet(), toMap(), joining() • toMap(), toCollection() groupingBy(), partitioningBy(), groupingByConcurrent() Using the Predefined Collectors
  43. 43. Journey’s End, JavaOne, October 2015 Predefined Standalone Collectors – from factory methods in Collections class • toList(), toSet(), toMap(), joining() • toMap(), toCollection() groupingBy(), partitioningBy(), groupingByConcurrent() Using the Predefined Collectors framework provides the Supplier
  44. 44. Journey’s End, JavaOne, October 2015 Predefined Standalone Collectors – from factory methods in Collections class • toList(), toSet(), toMap(), joining() • toMap(), toCollection() groupingBy(), partitioningBy(), groupingByConcurrent() Using the Predefined Collectors user provides the Supplier framework provides the Supplier
  45. 45. Journey’s End, JavaOne, October 2015 Predefined Standalone Collectors – from factory methods in Collections class • toList(), toSet(), toMap(), joining() • toMap(), toCollection() groupingBy(), partitioningBy(), groupingByConcurrent() Using the Predefined Collectors user provides the Supplier framework provides the Supplier produce a 
 classification map
  46. 46. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Collectors.toSet() people.stream().collect(Collectors.toSet())
  47. 47. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Stream<Person> Collectors.toSet() Set<Person> people.stream().collect(Collectors.toSet()) Collector<Person,?,Set<Person>>
  48. 48. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Stream<Person> Collectors.toSet() Set<Person> people.stream().collect(Collectors.toSet()) bill Collector<Person,?,Set<Person>>
  49. 49. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Stream<Person> Collectors.toSet() Set<Person> people.stream().collect(Collectors.toSet()) bill Collector<Person,?,Set<Person>>
  50. 50. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Stream<Person> Collectors.toSet() Set<Person> people.stream().collect(Collectors.toSet()) bill Collector<Person,?,Set<Person>>
  51. 51. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Stream<Person> Collectors.toSet() Set<Person> people.stream().collect(Collectors.toSet()) bill jon Collector<Person,?,Set<Person>>
  52. 52. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Stream<Person> Collectors.toSet() Set<Person> people.stream().collect(Collectors.toSet()) bill jon Collector<Person,?,Set<Person>>
  53. 53. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Stream<Person> Collectors.toSet() Set<Person> people.stream().collect(Collectors.toSet()) amy bill jon Collector<Person,?,Set<Person>>
  54. 54. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Stream<Person> Collectors.toSet() Set<Person> people.stream().collect(Collectors.toSet()) amy bill jon Collector<Person,?,Set<Person>>
  55. 55. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Collectors.toSet() Set<Person> people.stream().collect(Collectors.toSet()) amy bill jon Collector<Person,?,Set<Person>>
  56. 56. Journey’s End, JavaOne, October 2015 Simple Collector – toSet() Collectors.toSet() Set<Person> { , , } people.stream().collect(Collectors.toSet()) amybilljon Collector<Person,?,Set<Person>>
  57. 57. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) people.stream().collect( Collectors.toMap( Person::getCity,
 Person::getName))
  58. 58. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> Collector<Person,?,Map<City,String> people.stream().collect(toMap(Person::getCity,Person::getName))
  59. 59. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> Collector<Person,?,Map<City,String>
  60. 60. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> bill
  61. 61. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> bill Person::getCity
  62. 62. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> London bill
  63. 63. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> London bill Person::getName
  64. 64. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> London “Bill” bill Person::getName
  65. 65. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> London “Bill”
  66. 66. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> amy London “Bill”
  67. 67. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> Athens amy London “Bill”
  68. 68. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> “Amy”Athens London “Bill”
  69. 69. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> “Amy”Athens jon London “Bill”
  70. 70. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> “Amy”Athens London “Bill” Tulsa “Jon”
  71. 71. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) toMap() Map<City,String> “Amy”Athens London “Bill” Tulsa “Jon”
  72. 72. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) toMap() Map<City,String> “Amy”Athens London “Bill” Tulsa “Jon”
  73. 73. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String>
  74. 74. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> “Amy”Athens jon London “Bill”
  75. 75. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> “Amy”Athens jon London “Bill” Athens
  76. 76. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper) Stream<Person> toMap() Map<City,String> “Amy”Athens jon London IllegalStateException “Bill” Athens
  77. 77. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction) people.stream().collect( Collectors.toMap( Person::getCity,
 Person::getName, (a,b) -> a.concat(b)))
  78. 78. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction) Stream<Person> toMap() Map<City,String>
  79. 79. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction) Stream<Person> toMap() Map<City,String> “Amy”Athens London “Bill” Athens
  80. 80. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction) Stream<Person> toMap() Map<City,String> “Amy”Athens London “Bill” Athens
  81. 81. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction) Stream<Person> toMap() Map<City,String> “Amy”Athens London “Bill” “Jon” Athens
  82. 82. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction) Stream<Person> toMap() Map<City,String> “Amy”Athens London “Bill” “Jon” (a,b) -> a.concat(b) Athens
  83. 83. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction) Stream<Person> toMap() Map<City,String> Athens London “Bill” (a,b) -> a.concat(b) “AmyJon” Athens
  84. 84. Journey’s End, JavaOne, October 2015 Collectors API Factory methods in the Collectors class.They produce standalone collectors, accumulating to: • framework-supplied containers; • custom collections; • classification maps.
  85. 85. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction) toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction, Supplier<M> mapFactory) people.stream().collect( Collectors.toMap( Person::getCity,
 Person::getName, (a,b) -> a.concat(b),
 TreeMap::new))
  86. 86. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction, Supplier<M> mapFactory) Stream<Person> toMap() Map<City,String>
  87. 87. Journey’s End, JavaOne, October 2015 toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction, Supplier<M> mapFactory) Stream<Person> toMap() Map<City,String>
  88. 88. Journey’s End, JavaOne, October 2015 Collecting to Custom Collections <C extends Collection<T>> NavigableSet<String> sortedNames = people.stream() .map(Person::getName)
 .collect(toCollection(TreeSet::new));
  89. 89. Journey’s End, JavaOne, October 2015 Collecting to Custom Collections toCollection(Supplier<C> collectionFactory) <C extends Collection<T>> NavigableSet<String> sortedNames = people.stream() .map(Person::getName)
 .collect(toCollection(TreeSet::new));
  90. 90. Journey’s End, JavaOne, October 2015 Collectors API Factory methods in the Collectors class.They produce standalone collectors, accumulating to: • framework-supplied containers; • custom collections; • classification maps.
  91. 91. Journey’s End, JavaOne, October 2015 Collecting to Classification Maps groupingBy • simple • with downstream • with downstream and map factory partitioningBy
  92. 92. Journey’s End, JavaOne, October 2015 groupingBy(Function<T,K> classifier) Uses the classifier function to make a classification mapping Like toMap(), except that the values placed in the map are lists of the elements, one List corresponding to each classification key: For example, use Person.getCity() to make a Map<City,List<Person>> Map<City,List<Person>> peopleByCity = people.stream().
 collect(Collectors.groupingBy(Person::getCity));
  93. 93. Journey’s End, JavaOne, October 2015 Stream<Person> groupingBy() Map<City,List<Person>> bill jon amy Athens London Collector<Person,?,Map<City,List<Person> groupingBy(Function<Person,City>) Classifier Person→City
  94. 94. Journey’s End, JavaOne, October 2015 Stream<Person> groupingBy() Map<City,List<Person>> bill jon amy Athens London groupingBy(Function<Person,City>)
  95. 95. Journey’s End, JavaOne, October 2015 Stream<Person> groupingBy() Map<City,List<Person>> bill jon amy Athens bill London groupingBy(Function<Person,City>)
  96. 96. Journey’s End, JavaOne, October 2015 Stream<Person> groupingBy() Map<City,List<Person>> bill jon amy Athens billLondon groupingBy(Function<Person,City>) [ ]
  97. 97. Journey’s End, JavaOne, October 2015 Stream<Person> groupingBy() Map<City,List<Person>> bill jon amy Athens [ ] bill amy London groupingBy(Function<Person,City>) [ ]
  98. 98. Journey’s End, JavaOne, October 2015 Stream<Person> groupingBy() Map<City,List<Person>> bill jon amy Athens [ ] [ , ]bill amy jonLondon groupingBy(Function<Person,City>)
  99. 99. Journey’s End, JavaOne, October 2015 groupingBy() Map<City,List<Person>> bill jon amy Athens [ ] [ , ]bill amy jonLondon groupingBy(Function<Person,City>)
  100. 100. Journey’s End, JavaOne, October 2015 groupingBy() Map<City,List<Person>> bill jon amy Athens [ ] [ , ]bill amy jonLondon groupingBy(Function<Person,City>)
  101. 101. Journey’s End, JavaOne, October 2015 groupingBy(Function<T,K> classifier) Uses the classifier function to make a classification mapping Like toMap(), except that the values placed in the map are lists of the elements, one List corresponding to each classification key: For example, use Person.getCity() to make a Map<City,List<Person>> Map<City,List<Person>> peopleByCity = people.stream().
 collect(Collectors.groupingBy(Person::getCity));
  102. 102. Journey’s End, JavaOne, October 2015 groupingBy(classifier, downstream) Map<City,List<Person>> peopleByCity = people.stream().
 collect(Collectors.groupingBy(Person::getCity,toSet())); Uses the classifier function to make a classification mapping into a container defined by a downstream Collector Like toMap(), except that the values placed in the map are containers of the elements, one container corresponding to each classification key: For example, use Person.getCity() to make a Map<City,Set<Person>> Map<City,Set<Person>> peopleByCity = people.stream().
 collect(Collectors.groupingBy(Person::getCity,toSet()));
  103. 103. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athens Downstream Collector — toSet() Stream<Person > Classifier Person→City
  104. 104. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athens
  105. 105. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athens bill
  106. 106. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athens bill
  107. 107. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athens bill
  108. 108. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athensamy bill
  109. 109. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athens amy bill
  110. 110. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athens amy bill
  111. 111. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athens amy jon bill
  112. 112. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) Stream<Person> groupingBy() Map<City,Set<Person> bill jon amy London Athens amy jon bill
  113. 113. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) groupingBy() Map<City,Set<Person> bill jon amy London Athens amy jon bill
  114. 114. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) groupingBy() Map<City,Set<Person> bill jon amy London Athens amy jon bill
  115. 115. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) groupingBy() Map<City,Set<Person> bill jon amy London Athens { }amy { , }jonbill
  116. 116. Journey’s End, JavaOne, October 2015 groupingBy(Function classifier,Collector downstream)) groupingBy() Map<City,Set<Person> bill jon amy London Athens { }amy { , }jonbill
  117. 117. Journey’s End, JavaOne, October 2015 mapping(Function mapper,Collector downstream)) Applies a mapping function to each input element before passing it to the downstream collector. Set<City> inhabited = people.stream()
 .collect(mapping(Person::getCity,toSet())); Map<City,String> namesByCity = people.stream()
 .collect(groupingBy(Person::getCity, mapping(Person::getName,joining())); Animation example Sensible example
  118. 118. mapping(Function mapper,Collector downstream)) LondonStream<Person> mapping() bill jon amy 41 Athens Mapper Person→City Downstream Collector — toSet() Stream<City> Set<City>
  119. 119. mapping(Function mapper,Collector downstream)) LondonStream<Person> mapping() bill jon amy 41 Athens Set<City>
  120. 120. mapping(Function mapper,Collector downstream)) LondonStream<Person> mapping() bill jon amy 41 Athens London Set<City>
  121. 121. mapping(Function mapper,Collector downstream)) LondonStream<Person> mapping() bill jon amy 41 Athens Athens London Set<City>
  122. 122. mapping(Function mapper,Collector downstream)) LondonStream<Person> mapping() bill jon amy 41 Athens Athens LondonLondon Set<City>
  123. 123. mapping(Function mapper,Collector downstream)) London mapping() bill jon amy 41 Athens Athens LondonLondon Set<City>
  124. 124. mapping(Function mapper,Collector downstream)) London mapping() bill jon amy { , } 41 Athens Athens London Set<City>
  125. 125. mapping(Function mapper,Collector downstream)) London mapping() bill jon amy { , } 41 Athens Athens London Set<City>
  126. 126. Dualling Convenience Reductions • Collectors.counting() • Collectors.maxBy • Collectors.minBy • Collectors.summarizingXXX 42
  127. 127. Journey’s End, JavaOne, October 2015 Concurrent Collection
  128. 128. Journey’s End, JavaOne, October 2015 Thread safety is guaranteed by the framework • Even for non-threadsafe containers! Concurrent Collection
  129. 129. Journey’s End, JavaOne, October 2015 Thread safety is guaranteed by the framework • Even for non-threadsafe containers! But at a price... So what if your container is already threadsafe? • A concurrentMap implementation, for example? Concurrent Collection
  130. 130. Journey’s End, JavaOne, October 2015 Thread safety is guaranteed by the framework • Even for non-threadsafe containers! But at a price... So what if your container is already threadsafe? • A concurrentMap implementation, for example? Concurrent Collection
  131. 131. Journey’s End, JavaOne, October 2015 Thread safety is guaranteed by the framework • Even for non-threadsafe containers! But at a price... So what if your container is already threadsafe? • A concurrentMap implementation, for example? Every overload of toMap() and groupingBy() has a dual • toConcurrentMap(...) • groupingByConcurrent(...) Concurrent Collection
  132. 132. • Why collectors? • Using the predefined collectors • Intermission! • Worked problems • Writing your own Journey’s End – Agenda
  133. 133. • Why collectors? • Using the predefined collectors • Intermission! • Worked problems • Writing your own Journey’s End – Agenda
  134. 134. Journey’s End, JavaOne, October 2015 Writing a Collector Why would you want to?
  135. 135. Journey’s End, JavaOne, October 2015 Writing a Collector Why would you want to? • accumulate to a container that doesn’t implement Collection
  136. 136. Journey’s End, JavaOne, October 2015 Writing a Collector Why would you want to? • accumulate to a container that doesn’t implement Collection • share state between values being collected
  137. 137. Journey’s End, JavaOne, October 2015 Oprah’s Problem
  138. 138. Journey’s End, JavaOne, October 2015 Oprah’s Problem How to find a book?
  139. 139. Journey’s End, JavaOne, October 2015 Oprah’s Problem How to find a book? 336 640 144 624 Page count 239 640 384 1104 172 400
  140. 140. Journey’s End, JavaOne, October 2015 What Oprah Needs New Earth 0 Poisonwood Bible 336 Night 976 A Fine Balance 1120 ... Cumulative page counts
  141. 141. Supplier and Accumulator “NE” 336 0 “PB” 640 336[ ], ]“NE” 336 0[ ][ aNewEarth thePoisonwoodBible accumulator accumulator
  142. 142. Combiner ,“Night” 144 976 “AFB” 624 1120 ]“NE” 336 0 “PB” 640 336[ , ,
  143. 143. Combiner ,“Night” 144 0[ “AFB” 624 144 ]“NE” 336 0 “PB” 640 336[ ], ,“Night” 144 976 “AFB” 624 1120 ]“NE” 336 0 “PB” 640 336[ , ,
  144. 144. Combiner combiner ,“Night” 144 0[ “AFB” 624 144 ]“NE” 336 0 “PB” 640 336[ ], ,“Night” 144 976 “AFB” 624 1120 ]“NE” 336 0 “PB” 640 336[ , ,
  145. 145. Combiner combiner ,“Night” 144 0[ “AFB” 624 144 ]“NE” 336 0 “PB” 640 336[ ], ,“Night” 144 976 “AFB” 624 1120 ]“NE” 336 0 “PB” 640 336[ , , 976
  146. 146. Combiner combiner ,“Night” 144 0[ “AFB” 624 144 ]“NE” 336 0 “PB” 640 336[ ], ,“Night” 144 976 “AFB” 624 1120 ]“NE” 336 0 “PB” 640 336[ , , 976
  147. 147. Combiner combiner ,“Night” 144 0[ “AFB” 624 144 ]“NE” 336 0 “PB” 640 336[ ], ,“Night” 144 976 “AFB” 624 1120 ]“NE” 336 0 “PB” 640 336[ , ,
  148. 148. Using Reduction Instead... “New Earth” 336 0 “Poisonwood Bible” 640 336[ , “Night” 144 976, ] newEarth poisonwood night
  149. 149. Using Reduction Instead... “New Earth” 336 0 “Poisonwood Bible” 640 336[ , “Night” 144 976, ] newEarth poisonwood night Page count Start displacement
  150. 150. Using Reduction Instead... “New Earth” 336 0 “Poisonwood Bible” 640 336[ , “Night” 144 976, ] ]“New Earth” 336 0 “Poisonwood Bible” 640 0[ ] ]“Night” 144 0 ][[ newEarth poisonwood night
  151. 151. Using Reduction Instead... “New Earth” 336 0 “Poisonwood Bible” 640 336[ , “Night” 144 976, ] ]“New Earth” 336 0 “Poisonwood Bible” 640 0[ ] ]“Night” 144 0 ][[ newEarth poisonwood night Map
  152. 152. Using Reduction Instead... “New Earth” 336 0 “Poisonwood Bible” 640 336[ , “Night” 144 976, ] ]“New Earth” 336 0 “Poisonwood Bible” 640 0[ ] ]“Night” 144 0 ][[ newEarth poisonwood night Reduce Map
  153. 153. Using Reduction Instead... “New Earth” 336 0 “Poisonwood Bible” 640 336[ , “Night” 144 976, ] ]“New Earth” 336 0 “Poisonwood Bible” 640 0[ ] ]“Night” 144 0 ][[ PartialResult::new ArrayDeque::new newEarth poisonwood night Reduce Map
  154. 154. Using Reduction Instead... “New Earth” 336 0 “Poisonwood Bible” 640 336[ , “Night” 144 976, ] ]“New Earth” 336 0 “Poisonwood Bible” 640 0[ ] ]“Night” 144 0 ][[ PartialResult::new ArrayDeque::new PartialResult::new ArrayDeque::new PartialResult::new ArrayDeque::new newEarth poisonwood night Reduce
  155. 155. Journey’s End, JavaOne, October 2015 Performance of Collectors Depends on the performance of accumulator and combiner functions • toList(), toSet(), toCollection – performance will probably be dominated by accumulator, but remember that the framework will need to manage multithread access to non-threadsafe containers for the combine operation toMap(), toConcurrentMap() • map merging is slow. Resizing maps, especially concurrent maps, is particularly expensive.Whenever possible, presize all data structures, maps in particular.
  156. 156. Journey’s End, JavaOne, October 2015 Conclusion Collectors • generalisation of reduction • allow a functional style while continuing to work with a language based on mutation • designed for composition • flexible and powerful programming tool • take a bit of getting used to! – but they’re worth it!
  157. 157. Journey’s End, JavaOne, October 2015 Questions?

×