Top Banner
Journey’s End, JDK.IO, September 2016 Journey’s End Collection and Reduction in the Stream API JavaOne 2016 Maurice Naftalin @mauricenaftalin
189

Journey's end

Jan 12, 2017

Download

Software

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Journey's end

Journey’s End, JDK.IO, September 2016

Journey’s EndCollection and Reduction in the Stream API

JavaOne 2016Maurice Naftalin@mauricenaftalin

Page 2: Journey's end

Journey’s End, JavaOne, September 2016

Maurice Naftalin

Page 3: Journey's end

Journey’s End, JavaOne, September 2016

Maurice Naftalin

Java 5

Page 4: Journey's end

Journey’s End, JavaOne, September 2016

Maurice Naftalin

Java 5 Java 8

Page 5: Journey's end

Journey’s End, JavaOne, September 2016

Maurice Naftalin

Java 5 Java 8

Page 6: Journey's end

Journey’s End, JavaOne, September 2016

Maurice Naftalin

Java 5 Java 8

2013

Page 7: Journey's end

Journey’s End, JavaOne, September 2016

Maurice Naftalin

Java 5 Java 8

2014

Page 8: Journey's end

Journey’s End, JavaOne, September 2016

Maurice Naftalin

Java 5 Java 8

2015

Page 9: Journey's end

Journey’s End, JavaOne, September 2016

• Why collectors?

• Using the predefined collectors

• Worked problems

• Writing your own

Journey’s End – Agenda

Page 10: Journey's end

Journey’s End, JavaOne, September 2016

Example Domain

city: City name: Stringage: int

Person

Person amy = new Person(Athens, "Amy", 21); ...

List<Person> people = Arrays.asList(jon, amy, bill);

Page 11: Journey's end

Journey’s End, JavaOne, September 2016

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)

Page 12: Journey's end

Journey’s End, JavaOne, September 2016

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)

Page 13: Journey's end

Journey’s End, JavaOne, September 2016

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)

Page 14: Journey's end

Journey’s End, JavaOne, September 2016

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)

Page 15: Journey's end

Journey’s End, JavaOne, September 2016

Terminal Operations

– Search operations

– Side-effecting operations

– Reductions

Page 16: Journey's end

Journey’s End, JavaOne, September 2016

Search Operations

Search operations -

• allMatch, anyMatch

• findAny, findFirst boolean allAdults = people.stream() .allMatch(p -> p.getAge() >= 21);

Page 17: Journey's end

Journey’s End, JavaOne, September 2016

Side-effecting OperationsSide-effecting operations

• forEach, forEachOrderedpeople.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; });

Page 18: Journey's end

Journey’s End, JavaOne, September 2016

Side-effecting OperationsSide-effecting operations

• forEach, forEachOrderedpeople.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!

Page 19: Journey's end

Journey’s End, JavaOne, September 2016

• 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];}

Page 20: Journey's end

Journey’s End, JavaOne, September 2016

• 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

+

+

+

Page 21: Journey's end

Journey’s End, JavaOne, September 2016

• Avoiding an accumulator:

Reduction – Why?

Page 22: Journey's end

Journey’s End, JavaOne, September 2016

• Avoiding an accumulator:

Reduction – Why?

Page 23: Journey's end

Journey’s End, JavaOne, September 2016

• 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

Page 24: Journey's end

Journey’s End, JavaOne, September 2016

• 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

+

+

+

Page 25: Journey's end

Journey’s End, JavaOne, September 2016

• 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

+

+

+

Page 26: Journey's end

Journey’s End, JavaOne, September 2016

• 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

+

+

+

Page 27: Journey's end

Journey’s End, JavaOne, September 2016

0 1 2 3 4 5 6 7

+ +

+

+

+

+

+

Reduction – Why?

Page 28: Journey's end

Journey’s End, JavaOne, September 2016

0 1 2 3 4 5 6 7

+ +

+

+

+

+

+

Reduction – Why?

Page 29: Journey's end

Journey’s End, JavaOne, September 2016

0 1 2 3 4 5 6 7

+ +

+

+

+

+

+

Intermediate operations

Reduction – Why?

Page 30: Journey's end

Journey’s End, JavaOne, September 2016

Reduction on Immutable Values

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);

Page 31: Journey's end

Journey’s End, JavaOne, September 2016

Reduction to Collections?

Page 32: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 33: Journey's end

Journey’s End, JavaOne, September 2016

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!

Page 34: Journey's end

Journey’s End, JavaOne, September 2016

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);

Page 35: Journey's end

Journey’s End, JavaOne, September 2016

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:

Page 36: Journey's end

Journey’s End, JavaOne, September 2016

Reduction over an Identity

+

+

+

0 1 2 3

+

+

+

0

4 5 6 7

0

++

+

Page 37: Journey's end

Journey’s End, JavaOne, September 2016

Reduction to Collections?

Page 38: Journey's end

Journey’s End, JavaOne, September 2016

Reduction to Collections?

Reduction over an identity doesn’t work with collections at all

• reduction reuses the identity element

Page 39: Journey's end

Journey’s End, JavaOne, September 2016

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!

Page 40: Journey's end

Journey’s End, JavaOne, September 2016

The Answer – Collectors

a

a

a

e0 e1 e2 e3

a

a

a

e4 e5 e6 e7

aa

c

Page 41: Journey's end

Journey’s End, JavaOne, September 2016

The Answer – Collectors

a

a

a

e0 e1 e2 e3

a

a

a

() -> []

e4 e5 e6 e7

aa

c

() -> []

Page 42: Journey's end

Journey’s End, JavaOne, September 2016

The Answer – Collectors

a

a

a

e0 e1 e2 e3

a

a

a

() -> []

e4 e5 e6 e7

aa

c

a: accumulatorc: combiner

() -> []

Page 43: Journey's end

Journey’s End, JavaOne, September 2016

Collectors

Page 44: Journey's end

Journey’s End, JavaOne, September 2016

Collectors

So to define a collector, you need to provide

• Supplier

• Accumulator

• Combiner

Page 45: Journey's end

Journey’s End, JavaOne, September 2016

Collectors

So to define a collector, you need to provide

• Supplier

• Accumulator

• Combiner

That sounds really hard!

Page 46: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 47: Journey's end

Journey’s End, JavaOne, September 2016

• Why collectors?

• Using the predefined collectors

• Worked problems

• Writing your own

Journey’s End – Agenda

Page 48: Journey's end

Journey’s End, JavaOne, September 2016

Collectors API

Factory methods in the Collectors class. They produce standalone collectors, accumulating to:

• framework-supplied containers

• custom collections

• classification maps

Page 49: Journey's end

Journey’s End, JavaOne, September 2016

Predefined Standalone Collectors – from factory methods in Collectors class

• toList(), toSet(), toMap(), joining()

• toMap(), toCollection()

• groupingBy(), partitioningBy(), groupingByConcurrent()

Using the Predefined Collectors

Page 50: Journey's end

Journey’s End, JavaOne, September 2016

Predefined Standalone Collectors – from factory methods in Collectors class

• toList(), toSet(), toMap(), joining()

• toMap(), toCollection()

• groupingBy(), partitioningBy(), groupingByConcurrent()

Using the Predefined Collectors

framework providesthe Supplier

Page 51: Journey's end

Journey’s End, JavaOne, September 2016

Predefined Standalone Collectors – from factory methods in Collectors class

• toList(), toSet(), toMap(), joining()

• toMap(), toCollection()

• groupingBy(), partitioningBy(), groupingByConcurrent()

Using the Predefined Collectors

user providesthe Supplier

framework providesthe Supplier

Page 52: Journey's end

Journey’s End, JavaOne, September 2016

Predefined Standalone Collectors – from factory methods in Collectors class

• toList(), toSet(), toMap(), joining()

• toMap(), toCollection()

• groupingBy(), partitioningBy(), groupingByConcurrent()

Using the Predefined Collectors

user providesthe Supplier

framework providesthe Supplier

produce a classification map

Page 53: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Collectors.toSet()

people.stream().collect(Collectors.toSet())

Page 54: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Stream<Person>

Collectors.toSet()

Set<Person>

people.stream().collect(Collectors.toSet())

Collector<Person,?,Set<Person>>

Page 55: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Stream<Person>

Collectors.toSet()

Set<Person>

people.stream().collect(Collectors.toSet())

bill

Collector<Person,?,Set<Person>>

Page 56: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Stream<Person>

Collectors.toSet()

Set<Person>

people.stream().collect(Collectors.toSet())

bill

Collector<Person,?,Set<Person>>

Page 57: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Stream<Person>

Collectors.toSet()

Set<Person>

people.stream().collect(Collectors.toSet())

bill

Collector<Person,?,Set<Person>>

Page 58: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Stream<Person>

Collectors.toSet()

Set<Person>

people.stream().collect(Collectors.toSet())

billjon

Collector<Person,?,Set<Person>>

Page 59: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Stream<Person>

Collectors.toSet()

Set<Person>

people.stream().collect(Collectors.toSet())

billjon

Collector<Person,?,Set<Person>>

Page 60: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Stream<Person>

Collectors.toSet()

Set<Person>

people.stream().collect(Collectors.toSet())

amybill

jon

Collector<Person,?,Set<Person>>

Page 61: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Stream<Person>

Collectors.toSet()

Set<Person>

people.stream().collect(Collectors.toSet())

amy

billjon

Collector<Person,?,Set<Person>>

Page 62: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Collectors.toSet()

Set<Person>

people.stream().collect(Collectors.toSet())

amy

billjon

Collector<Person,?,Set<Person>>

Page 63: Journey's end

Journey’s End, JavaOne, September 2016

Simple Collector – toSet()

Collectors.toSet()

Set<Person>{ , , }

people.stream().collect(Collectors.toSet())

amybilljon

Collector<Person,?,Set<Person>>

Page 64: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

people.stream().collect( Collectors.toMap(

Person::getCity, Person::getName))

Page 65: Journey's end

Journey’s End, JavaOne, September 2016

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))

Page 66: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

Collector<Person,?,Map<City,String>

Page 67: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

bill

Page 68: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

bill

Person::getCity

Page 69: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>London

bill

Page 70: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>London

bill Person::getName

Page 71: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>London “Bill”

bill Person::getName

Page 72: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>London “Bill”

Page 73: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

amy

London “Bill”

Page 74: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

Athensamy

London “Bill”

Page 75: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

“Amy”Athens

London “Bill”

Page 76: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

“Amy”Athensjon

London “Bill”

Page 77: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

“Amy”Athens

London “Bill”

Tulsa “Jon”

Page 78: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

toMap() Map<City,String>

“Amy”Athens

London “Bill”

Tulsa “Jon”

Page 79: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

toMap() Map<City,String>

“Amy”AthensLondon “Bill”

Tulsa “Jon”

Page 80: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

Page 81: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

“Amy”Athensjon

London “Bill”

Page 82: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

“Amy”Athensjon

London “Bill”

Athens

Page 83: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper)

Stream<Person>

toMap() Map<City,String>

“Amy”Athensjon

London

IllegalStateException

“Bill”

Athens

Page 84: Journey's end

Journey’s End, JavaOne, September 2016

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)))

Page 85: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction)

Stream<Person>

toMap() Map<City,String>

Page 86: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction)

Stream<Person>

toMap() Map<City,String>

“Amy”Athens

London “Bill”

Athens

Page 87: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction)

Stream<Person>

toMap() Map<City,String>

“Amy”Athens

London “Bill”

Athens

Page 88: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction)

Stream<Person>

toMap() Map<City,String>

“Amy”Athens

London “Bill”

“Jon”Athens

Page 89: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 90: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 91: Journey's end

Journey’s End, JavaOne, September 2016

Collectors API

Factory methods in the Collectors class. They produce standalone collectors, accumulating to:

• framework-supplied containers

• custom collections

• classification maps

Page 92: Journey's end

Journey’s End, JavaOne, September 2016

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))

Page 93: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction, Supplier<M> mapFactory)

Stream<Person>

toMap() Map<City,String>

Page 94: Journey's end

Journey’s End, JavaOne, September 2016

toMap(Function<T,K> keyMapper, Function<T,U> valueMapper BinaryOperator<U> mergeFunction, Supplier<M> mapFactory)

Stream<Person>

toMap() Map<City,String>

Page 95: Journey's end

Journey’s End, JavaOne, September 2016

Collecting to Custom Collections

Page 96: Journey's end

Journey’s End, JavaOne, September 2016

Collecting to Custom Collections

toCollection(Supplier<C> collectionFactory)

Page 97: Journey's end

Journey’s End, JavaOne, September 2016

Collecting to Custom Collections

<C extends Collection<T>>toCollection(Supplier<C> collectionFactory)

Page 98: Journey's end

Journey’s End, JavaOne, September 2016

Collecting to Custom Collections

returns

Collector<T,?,C>

<C extends Collection<T>>toCollection(Supplier<C> collectionFactory)

Page 99: Journey's end

Journey’s End, JavaOne, September 2016

Collecting to Custom Collections

returns

Collector<T,?,C>

<C extends Collection<T>>

NavigableSet<String> sortedNames = people.stream().map(Person::getName) .collect(toCollection(TreeSet::new));

toCollection(Supplier<C> collectionFactory)

Page 100: Journey's end

Journey’s End, JavaOne, September 2016

Collectors API

Factory methods in the Collectors class. They produce standalone collectors, accumulating to:

• framework-supplied containers

• custom collections

• classification maps

Page 101: Journey's end

Journey’s End, JavaOne, September 2016

Collecting to Classification Maps

groupingBy

• simple

• with downstream

• with downstream and map factory

partitioningBy

Page 102: Journey's end

Journey’s End, JavaOne, September 2016

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));

Page 103: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 104: Journey's end

Journey’s End, JavaOne, September 2016

Stream<Person>

groupingBy() Map<City,List<Person>>

bill

jon

amy Athens

London

groupingBy(Function<Person,City>)

Page 105: Journey's end

Journey’s End, JavaOne, September 2016

Stream<Person>

groupingBy() Map<City,List<Person>>

bill

jon

amy Athens

bill London

groupingBy(Function<Person,City>)

Page 106: Journey's end

Journey’s End, JavaOne, September 2016

Stream<Person>

groupingBy() Map<City,List<Person>>

bill

jon

amy Athens

billLondon

groupingBy(Function<Person,City>)

[ ]

Page 107: Journey's end

Journey’s End, JavaOne, September 2016

Stream<Person>

groupingBy() Map<City,List<Person>>

bill

jon

amy Athens [ ]

bill

amy

London

groupingBy(Function<Person,City>)

[ ]

Page 108: Journey's end

Journey’s End, JavaOne, September 2016

Stream<Person>

groupingBy() Map<City,List<Person>>

bill

jon

amy Athens [ ]

[ , ]bill

amy

jonLondon

groupingBy(Function<Person,City>)

Page 109: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy() Map<City,List<Person>>

bill

jon

amy Athens [ ]

[ , ]bill

amy

jonLondon

groupingBy(Function<Person,City>)

Page 110: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy() Map<City,List<Person>>

bill

jon

amy

Athens [ ]

[ , ]bill

amy

jonLondon

groupingBy(Function<Person,City>)

Page 111: Journey's end

Journey’s End, JavaOne, September 2016

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));

Page 112: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(classifier, downstream)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,List<Person>> peopleByCity = people.stream() .collect(Collectors.groupingBy(Person::getCity,toSet()));

Page 113: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens

DownstreamCollector

—toSet()

Stream<Person>

Classifier

Person→City

Page 114: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens

Page 115: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens

bill

Page 116: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens

bill

Page 117: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens

bill

Page 118: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athensamy

bill

Page 119: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens amy

bill

Page 120: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens amy

bill

Page 121: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens amy

jon bill

Page 122: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

Stream<Person>

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens amy

jonbill

Page 123: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens amy

jonbill

Page 124: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens amy

jonbill

Page 125: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens { }amy

{ , }jonbill

Page 126: Journey's end

Journey’s End, JavaOne, September 2016

groupingBy(Function classifier,Collector downstream))

groupingBy()Map<City,Set<Person>>

bill

jon

amy

London

Athens { }amy

{ , }jonbill

Page 127: Journey's end

Journey’s End, JavaOne, September 2016

mapping(Function mapper,Collector downstream))

Applies a mapping function to each input element before passing it to the downstream collector.

Page 128: Journey's end

Journey’s End, JavaOne, September 2016

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()));

Animation example

Page 129: Journey's end

Journey’s End, JavaOne, September 2016

mapping(Function mapper,Collector downstream))

LondonStream<Person>

mapping()

bill

jon

amy Athens

Mapper

Person→City

DownstreamCollector

—toSet()

Stream<City>

Set<City>

Page 130: Journey's end

Journey’s End, JavaOne, September 2016

mapping(Function mapper,Collector downstream))

LondonStream<Person>

mapping()

bill

jon

amy Athens

Set<City>

Page 131: Journey's end

Journey’s End, JavaOne, September 2016

mapping(Function mapper,Collector downstream))

LondonStream<Person>

mapping()

bill

jon

amy Athens

LondonSet<City>

Page 132: Journey's end

Journey’s End, JavaOne, September 2016

mapping(Function mapper,Collector downstream))

LondonStream<Person>

mapping()

bill

jon

amy Athens

Athens

LondonSet<City>

Page 133: Journey's end

Journey’s End, JavaOne, September 2016

mapping(Function mapper,Collector downstream))

LondonStream<Person>

mapping()

bill

jon

amy Athens

Athens

LondonLondonSet<City>

Page 134: Journey's end

Journey’s End, JavaOne, September 2016

mapping(Function mapper,Collector downstream))

London

mapping()

bill

jon

amy Athens

Athens

LondonLondonSet<City>

Page 135: Journey's end

Journey’s End, JavaOne, September 2016

mapping(Function mapper,Collector downstream))

London

mapping()

bill

jon

amy

{ , }

Athens

AthensLondon

Set<City>

Page 136: Journey's end

Journey’s End, JavaOne, September 2016

mapping(Function mapper,Collector downstream))

London

mapping()

bill

jon

amy

{ , }

Athens

AthensLondon

Set<City>

Page 137: Journey's end

Journey’s End, JavaOne, September 2016

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()));

Animation example

Page 138: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 139: Journey's end

Collectors’ Fair, JavaOne, October 2016

groupingBy()

bill

jon

amy Athens

billamyjon

London

Collector<Person,?,String>

Classifier

Person→City

JDK Collectors with Java 8 Streams

mapping()

Mapper

Person→String

Stream<String>

joining()

Collector<CharSequence,?,String>

Page 140: Journey's end

Journey’s End, JavaOne, September 2016

Dualling Convenience Reductions

Terminal operation Collectors factory method

count() counting()

max() min()

maxBy() minBy()

sum() average()

summingXxx() averagingXxx()

summaryStatistics() summarizingXxx()

reduce(accumulator) reduce(identity, accumulator)

reduce(identity, accumulator, combiner)

reducing(accumulator) reducing(identity, accumulator)

reducing(identity, accumulator, combiner)

Page 141: Journey's end

Journey’s End, JavaOne, September 2016

Concurrent Collection

Page 142: Journey's end

Journey’s End, JavaOne, September 2016

Concurrent Collection

Page 143: Journey's end

Journey’s End, JavaOne, September 2016

Thread safety is guaranteed by the framework

• Even for non-threadsafe containers!

Concurrent Collection

Page 144: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 145: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 146: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 147: Journey's end

Journey’s End, JavaOne, September 2016

• Why collectors?

• Using the predefined collectors

• Worked problems

• Writing your own

Journey’s End – Agenda

Page 148: Journey's end

Most Popular Age

Page 149: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge

Page 150: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet()

Page 151: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet() .stream()

Page 152: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet() .stream() .sorted(Entry.<Integer,Long>comparingByValue().reversed())

Page 153: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet() .stream() .sorted(Entry.<Integer,Long>comparingByValue().reversed()) .map(Entry::getKey)

Page 154: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet() .stream() .sorted(Entry.<Integer,Long>comparingByValue().reversed()) .map(Entry::getKey) .findFirst();

Page 155: Journey's end

Most Popular Age

Page 156: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge

Page 157: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet()

Page 158: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet() .stream()

Page 159: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet() .stream() .collect(maxBy(Comparator.comparing(Map.Entry::getValue)))

Page 160: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet() .stream() .collect(maxBy(Comparator.comparing(Map.Entry::getValue))) .map(Map.Entry::getKey);

Page 161: Journey's end

Most Popular Age

Optional<Integer> modalAge = populationByAge .entrySet() .stream() .collect(maxBy(Comparator.comparing(Map.Entry::getValue))) .map(Map.Entry::getKey);

Page 162: Journey's end

Map<Long, Set<Integer>> collect = people.stream() .collect(groupingBy(People::getAge, counting())) .entrySet() .stream() .collect(groupingBy(Entry::getValue,

mapping(Entry::getKey, toSet())));

Most Popular Ages

Page 163: Journey's end

Journey’s End, JavaOne, September 2016

• Why collectors?

• Using the predefined collectors

• Worked problems

• Writing your own

Journey’s End – Agenda

Page 164: Journey's end

Journey’s End, JavaOne, September 2016

Writing a Collector

Page 165: Journey's end

Journey’s End, JavaOne, September 2016

Writing a Collector

Why would you want to?

Page 166: Journey's end

Journey’s End, JavaOne, September 2016

Writing a Collector

Why would you want to?

• accumulate to a container that doesn’t implement Collection

Page 167: Journey's end

Journey’s End, JavaOne, September 2016

Writing a Collector

Why would you want to?

• accumulate to a container that doesn’t implement Collection

• share state between values being collected

Page 168: Journey's end

Journey’s End, JavaOne, September 2016

Oprah’s Problem

Page 169: Journey's end

Journey’s End, JavaOne, September 2016

Oprah’s Problem

How to find a book?

Page 170: Journey's end

Journey’s End, JavaOne, September 2016

Oprah’s Problem

How to find a book?

336640

144624

Page count 239640

3841104

172400

Page 171: Journey's end

Journey’s End, JavaOne, September 2016

What Oprah Needs

New Earth 0Poisonwood Bible 336

Night 976A Fine Balance 1120

...

Cumulative page counts

Page 172: Journey's end

Journey’s End, JavaOne, September 2016

Supplier and Accumulator

“NE” 336 0 “PB” 640 336[ ],

]“NE” 336 0[

][

aNewEarth thePoisonwoodBible

accumulator

accumulator

Page 173: Journey's end

Journey’s End, JavaOne, September 2016

Combiner

,“Night” 144 976 “AFB” 624 1120 ]“NE” 336 0 “PB” 640 336[ , ,

Page 174: Journey's end

Journey’s End, JavaOne, September 2016

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[ , ,

Page 175: Journey's end

Journey’s End, JavaOne, September 2016

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[ , ,

Page 176: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 177: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 178: Journey's end

Journey’s End, JavaOne, September 2016

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[ , ,

Page 179: Journey's end

Journey’s End, JavaOne, September 2016

Using Reduction Instead...

“New Earth” 336 0 “Poisonwood Bible” 640 336[ , “Night” 144 976, ]

newEarth poisonwood night

Page 180: Journey's end

Journey’s End, JavaOne, September 2016

Using Reduction Instead...

“New Earth” 336 0 “Poisonwood Bible” 640 336[ , “Night” 144 976, ]

newEarth poisonwood night

Page count

Start displacement

Page 181: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 182: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 183: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 184: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 185: Journey's end

Journey’s End, JavaOne, September 2016

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

Page 186: Journey's end

Journey’s End, JavaOne, September 2016

Performance of CollectorsDepends 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.

Page 187: Journey's end

Journey’s End, JavaOne, September 2016

ConclusionCollectors

• 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!

Page 188: Journey's end

Journey’s End, JavaOne, September 2016

Questions?

Page 189: Journey's end

Journey’s End, JavaOne, September 2016

Questions?