KEMBAR78
Harnessing the Power of Java 8 Streams | PDF
Harnessing the power of
Java 8 Streams
Praveer Gupta
Default Methods
Lambda Expressions
Streams
Date-Time API
CompletableFuture
Optional
helps to make a strategic decision about what
programming language should be adopted
when starting to build a new software system
Java 8 released on
Mar 18, 2014
–Robert C. Martin
“There are two parts to learning
craftsmanship: knowledge and work.
You must gain the knowledge of
principles, patterns, practices, and
heuristics that a craftsman knows,
and
you must also grind that knowledge
into your fingers, eyes, and gut by
working hard and
practicing..”
Stream
Intermediate Operators
Terminal Operators
Harnessing the power Java 8 Streams
Programming Paradigm Concepts
Stream
Collectorscollectreduce
Intermediate Operators
Terminal Operators
computation creation Primitive Streams
stateless/stateful
Lazy &
Short-Circuited
Harnessing the power Java 8 Streams
Declarative
Programming
Internal
Iteration
chained categories
Programming Paradigm Concepts
Harnessing the power Java 8 Streams
Declarative
Programming
Internal
Iteration
Programming Paradigm Concepts
Declarative
SELECT NAME FROM PERSON WHERE AGE > 18;
List<String> adults = group.stream()

.filter(p -> p.age() > 18)
.map(Person::name)

.collect(toList());
You declare what the program has to do
and the library takes care of how to do it
Declarative
Focuses on
What
List<String> adults = new ArrayList<>();

for (Person person: group) 

if (person.age() > 18)

adults.add(person.name());
Focuses on
How and
What
vs Imperative
List<String> adults = group.stream()

.filter(p -> p.age() > 18)
.map(Person::name)

.collect(toList());
Old way vs New way
final List<String> names = new ArrayList<>();

for (Person p : group)

if (p.age() > 18)
names.add(p.name());

return names;
return group.stream()

.filter(p -> p.age() > 18)

.map(Person::name)

.collect(toList());
List<String> namesOfAdultsInTheGroup(List<Person> group) {
}
External Iteration
Internal Iteration
new declarative way
old imperative way
List<String> namesOfAdultsInTheGroup(List<Person> group) {
}
Application of Streams
interface CustomerRepository {

List<Customer> findByCity(String cityName);

}
API Definition
Application of Streams
interface CustomerRepository {

Stream<Customer> findByCity(String cityName);

}
try (Stream<String> stream =
repository.findByCity(“Pune")) {

return stream.filter(…).count();

}
API Definition
Usage of the API
Consume items as they arrive
Efficient memory usage
Stream
computation creation
Harnessing the power Java 8 Streams
Declarative
Programming
Internal
Iteration
Programming Paradigm Concepts
Stream
a read-only sequence of elements
computational operations that will be performed
in aggregate
Collection
efficient management of elements
efficient access to elements
Stream Pipeline
Stream
Terminal
Operator
Operator1
Operator2
Operator3
Intermediate
Operators
(Zero or more)
Stream
Terminal
Operator
Operator1
Operator2
Operator3
Stream Pipeline
List<String> namesOfAdultsInTheGroup(List<Person> group) {

return







}
group.stream()
.filter(p -> p.age() > 18)
.map(Person::name)
.collect(Collectors.toList());
names
group
Stream<Person>
Archer
(22 years)
Barbara
(17 years)
Daisy
(25 years)
is person’s age > 18 ?
Stream<Person>
Stream<String>
map to name of person
collect into a list
group.stream()
.filter(p ->
p.age() > 18)
.map(Person::name)
.collect(
Collectors.toList());
Archer
(22 years)
Barbara
(17 years)
Daisy
(25 years)
Archer
(22 years)
Daisy
(25 years)
Archer Daisy
Archer Daisy
Creating Stream
From Collection
List<String> list = Arrays.asList("a", "b", "c");

Stream<String> stream = list.stream();
String[] array = {"a", "b", "c"};

Stream<String> stream = Arrays.stream(array);
Creating Stream
From an I/O Channel
try (Stream<Path> stream =
Files.list(Paths.get(“.”));) {
…
}
Stream interface extends AutoCloseable
Creating Stream
Using Generator Functions
Stream<Double> stream = Stream.generate(Math::random);
Stream<Integer> stream = Stream.iterate(0, n -> n + 3);
Both are unbounded
Parallel Stream
From Collection
List<String> list = Arrays.asList("a", "b", "c");

Stream<String> stream = list.parallelStream();
From another Stream
Stream<String> parallelStream = stream.parallel();
List<String> list = Arrays.asList("a", "b", "c");

Stream<String> stream = list.parallelStream();
Stream<String> parallelStream = stream.parallel();
Parallel Stream
How does it work?
Splitting Combining
Parallel
Processing
Parallel Stream
Performance Impact
Always measure performance before using parallel
Stream size predictability & Amount of data
Decomposability of source data structure
Computational Cost
Stream
Intermediate Operators
computation creation
stateless/stateful
Harnessing the power Java 8 Streams
Declarative
Programming
Internal
Iteration
chained categories
Programming Paradigm Concepts
Intermediate Operators
Stream
Terminal
Operator
Operator1
Operator2
Operator3
Intermediate
Operators
(Zero or more)
Intermediate Operators
Categories
Stream<Integer> stream = Stream.of(3, 2, 1);
Stream<Integer> filtered =
stream.filter(n -> n % 2 == 0);
Filtering
Type of stream remains the same
Stream<Integer> filtered =
stream.filter(n -> n % 2 == 0);
Intermediate Operators
Categories
Stream<Integer> stream = Stream.of(3, 2, 1);
Stream<String> mapped = stream.map(Object::toString);
Mapping
Type of stream gets altered (here Integer to String)
Stream<String> mapped = stream.map(Object::toString);
Intermediate Operators
Categories
Stream<Integer> stream = Stream.of(3, 2, 1);
Stream<Integer> sliced = stream.limit(1);
Slicing
Type of stream remains the same
Stream<Integer> sliced = stream.limit(1);
Stream.of(1, 2, 3, 4)

.peek(System.out::println)

.filter(n -> n % 2 == 0);
Intermediate Operators
Laziness
Stream.of(1, 2, 3, 4)

.peek(System.out::println)

.filter(n -> n % 2 == 0)

.collect(toList());
Stream.of(1, 2, 3, 4)

.peek(System.out::println)

.filter(n -> n % 2 == 0);
Terminal operator is required to start stream processing
Stream.of(1, 2, 3, 4)

.peek(System.out::println)

.filter(n -> n % 2 == 0)

.collect(toList());
Peek will not print
anything
Intermediate Operators
Short-Circuiting
Stream.of(1, 2, 3, 4)

.peek(System.out::println)

.filter(n -> n % 2 == 0)

.findFirst();
Stream will get short-circuited
after the first element is found
Peek will print
only 1 & 2
Stream.of(1, 2, 3, 4)

.peek(System.out::println)

.filter(n -> n % 2 == 0)

.findFirst();
Intermediate Operators
Stateless
vs Stateful
Stream.of(1, 2, 3, 4)

.peek(System.out::println)

.filter(n -> n % 2 == 0)

.findFirst();
Stream.of(1, 2, 3, 4)

.peek(System.out::println)

.sorted(Comparator.reverseOrder())

.filter(n -> n % 2 == 0)

.findFirst();
Will cause the
whole stream
to be
traversed
All operations
are done on
current value
in stream
Stream.of(1, 2, 3, 4)

.peek(System.out::println)

.sorted(Comparator.reverseOrder())

.filter(n -> n % 2 == 0)

.findFirst();
Stream
Collectorscollectreduce
Intermediate Operators
Terminal Operators
computation creation
stateless/stateful
Lazy &
Short-Circuited
Harnessing the power Java 8 Streams
Declarative
Programming
Internal
Iteration
chained categories
Programming Paradigm Concepts
Terminal Operators
Single Value Collection
Reduce Operation Collect Operation
Terminal Operators
reduce
<U> U reduce(U identity,

BiFunction<U, ? super T, U> accumulator,

BinaryOperator<U> combiner);
Stream.of(3, 2, 1).reduce(0, Integer::sum, Integer::sum);
Stream.of(3, 2, 1).reduce(0, Integer::sum);
Immutable Reduction Process
<U> U reduce(U identity,

BiFunction<U, ? super T, U> accumulator,

BinaryOperator<U> combiner);
<U> U reduce(U identity,

BiFunction<U, ? super T, U> accumulator,

BinaryOperator<U> combiner);
<U> U reduce(U identity,

BiFunction<U, ? super T, U> accumulator,

BinaryOperator<U> combiner);
Terminal Operators
reduce utility methods
Optional<Integer> max =
Stream.of(1, 2, 3)
.max(Comparator.naturalOrder());
boolean result = Stream.of(1, 2, 3)
.anyMatch(n -> n > 2);
Optional<Integer> max =
Stream.of(1, 2, 3)
.max(Comparator.naturalOrder());
boolean result = Stream.of(1, 2, 3)
.anyMatch(n -> n > 2);
Terminal Operators
collect
Mutable Reduction Process
Accumulates elements into a mutable result container
Stream.of("a", "b", "c").reduce("", String::concat);
String copying = Low Performance !!
Terminal Operators
collect
<R> R collect(Supplier<R> supplier,

BiConsumer<R, ? super T> accumulator,

BiConsumer<R, R> combiner);
StringBuilder builder = Stream.of("a", "b", "c").collect(

StringBuilder::new, 

StringBuilder::append, 

StringBuilder::append

);
StringBuilder is the mutable container here
Terminal Operators
Collectors class
String joinedString = Stream.of(“a", "b", “c")
.collect(Collectors.joining(", "));
IntSummaryStatistics statistics = group.stream()
.collect(Collectors.summarizingInt(Person::age));
IntSummaryStatistics{count=10, sum=280, min=26, average=28.000000, max=30}
Output: a, b, c
String joinedString = Stream.of(“a", "b", “c")
.collect(Collectors.joining(", "));
IntSummaryStatistics statistics = group.stream()
.collect(Collectors.summarizingInt(Person::age));
Terminal Operators
Downstream Collectors
Map<Integer, List<Person>> result = group.stream()
.collect(Collectors.groupingBy(Person::age,

Collectors.toList()));
Map<Integer, List<Person>> result = group.stream()
.collect(groupingBy(Person::age));
Divide into different age groups
Terminal Operators
Downstream Collectors
Map<Integer, Long> result = group.stream()
.collect(groupingBy(Person::age, counting()));
Map<Integer, List<String>> result = group.stream()
.collect(groupingBy(Person::age,

mapping(Person::name, toList())));
Count of people in each age group
Names on people in each age group
Stream
Collectorscollectreduce
Intermediate Operators
Terminal Operators
computation creation Primitive Streams
stateless/stateful
Lazy &
Short-Circuited
Harnessing the power Java 8 Streams
Declarative
Programming
Internal
Iteration
chained categories
Programming Paradigm Concepts
Primitive Streams
IntStream DoubleStreamLongStream
Avoid boxing and
unboxing costs
Numeric operations
are available
XXXFunction
XXXPredicateXXXSupplierXXXConsumer
XXXToXXXFunction
Primitive Functional Interfaces
Primitive Streams
Creating from factory methods
IntStream intStream = IntStream.range(1, 10);
DoubleStream doubleStream = DoubleStream.of(1.0, 2.0);
LongStream longStream =
LongStream.iterate(0L, n -> n + 4);
Generating a range of numbers
Stream of known set of numbers
Stream using iterative application of a function
Stream<Person> stream = group.stream();
Primitive Streams
Obtaining from Stream<T>
mapToXXX flatMapToXXX
IntStream intStream = stream.mapToInt(Person::age);
OptionalDouble averageAge = intStream.average();
Specialized methods on Primitive Streams
IntStream intStream = stream.mapToInt(Person::age);
Primitive Streams
Converting back to Stream<T>
Stream<Integer> boxed = IntStream.of(1, 2, 3).boxed();Stream<Integer> boxed = IntStream.of(1, 2, 3).boxed();
Stream
Collectorscollectreduce
Intermediate Operators
Terminal Operators
computation creation Primitive Streams
stateless/stateful
Lazy &
Short-Circuited
Harnessing the power Java 8 Streams
Declarative
Programming
Internal
Iteration
chained categories
Programming Paradigm Concepts
Questions?
http://praveer09.github.io
@praveerguptapraveer

Harnessing the Power of Java 8 Streams

  • 1.
    Harnessing the powerof Java 8 Streams Praveer Gupta
  • 2.
  • 3.
    helps to makea strategic decision about what programming language should be adopted when starting to build a new software system Java 8 released on Mar 18, 2014
  • 4.
    –Robert C. Martin “Thereare two parts to learning craftsmanship: knowledge and work. You must gain the knowledge of principles, patterns, practices, and heuristics that a craftsman knows, and you must also grind that knowledge into your fingers, eyes, and gut by working hard and practicing..”
  • 5.
    Stream Intermediate Operators Terminal Operators Harnessingthe power Java 8 Streams Programming Paradigm Concepts
  • 6.
    Stream Collectorscollectreduce Intermediate Operators Terminal Operators computationcreation Primitive Streams stateless/stateful Lazy & Short-Circuited Harnessing the power Java 8 Streams Declarative Programming Internal Iteration chained categories Programming Paradigm Concepts
  • 7.
    Harnessing the powerJava 8 Streams Declarative Programming Internal Iteration Programming Paradigm Concepts
  • 8.
    Declarative SELECT NAME FROMPERSON WHERE AGE > 18; List<String> adults = group.stream()
 .filter(p -> p.age() > 18) .map(Person::name)
 .collect(toList()); You declare what the program has to do and the library takes care of how to do it
  • 9.
    Declarative Focuses on What List<String> adults= new ArrayList<>();
 for (Person person: group) 
 if (person.age() > 18)
 adults.add(person.name()); Focuses on How and What vs Imperative List<String> adults = group.stream()
 .filter(p -> p.age() > 18) .map(Person::name)
 .collect(toList());
  • 10.
    Old way vsNew way final List<String> names = new ArrayList<>();
 for (Person p : group)
 if (p.age() > 18) names.add(p.name());
 return names; return group.stream()
 .filter(p -> p.age() > 18)
 .map(Person::name)
 .collect(toList()); List<String> namesOfAdultsInTheGroup(List<Person> group) { } External Iteration Internal Iteration new declarative way old imperative way List<String> namesOfAdultsInTheGroup(List<Person> group) { }
  • 11.
    Application of Streams interfaceCustomerRepository {
 List<Customer> findByCity(String cityName);
 } API Definition
  • 12.
    Application of Streams interfaceCustomerRepository {
 Stream<Customer> findByCity(String cityName);
 } try (Stream<String> stream = repository.findByCity(“Pune")) {
 return stream.filter(…).count();
 } API Definition Usage of the API Consume items as they arrive Efficient memory usage
  • 13.
    Stream computation creation Harnessing thepower Java 8 Streams Declarative Programming Internal Iteration Programming Paradigm Concepts
  • 14.
    Stream a read-only sequenceof elements computational operations that will be performed in aggregate Collection efficient management of elements efficient access to elements
  • 15.
  • 16.
    Stream Terminal Operator Operator1 Operator2 Operator3 Stream Pipeline List<String> namesOfAdultsInTheGroup(List<Person>group) {
 return
 
 
 
 } group.stream() .filter(p -> p.age() > 18) .map(Person::name) .collect(Collectors.toList());
  • 17.
    names group Stream<Person> Archer (22 years) Barbara (17 years) Daisy (25years) is person’s age > 18 ? Stream<Person> Stream<String> map to name of person collect into a list group.stream() .filter(p -> p.age() > 18) .map(Person::name) .collect( Collectors.toList()); Archer (22 years) Barbara (17 years) Daisy (25 years) Archer (22 years) Daisy (25 years) Archer Daisy Archer Daisy
  • 18.
    Creating Stream From Collection List<String>list = Arrays.asList("a", "b", "c");
 Stream<String> stream = list.stream(); String[] array = {"a", "b", "c"};
 Stream<String> stream = Arrays.stream(array);
  • 19.
    Creating Stream From anI/O Channel try (Stream<Path> stream = Files.list(Paths.get(“.”));) { … } Stream interface extends AutoCloseable
  • 20.
    Creating Stream Using GeneratorFunctions Stream<Double> stream = Stream.generate(Math::random); Stream<Integer> stream = Stream.iterate(0, n -> n + 3); Both are unbounded
  • 21.
    Parallel Stream From Collection List<String>list = Arrays.asList("a", "b", "c");
 Stream<String> stream = list.parallelStream(); From another Stream Stream<String> parallelStream = stream.parallel(); List<String> list = Arrays.asList("a", "b", "c");
 Stream<String> stream = list.parallelStream(); Stream<String> parallelStream = stream.parallel();
  • 22.
    Parallel Stream How doesit work? Splitting Combining Parallel Processing
  • 23.
    Parallel Stream Performance Impact Alwaysmeasure performance before using parallel Stream size predictability & Amount of data Decomposability of source data structure Computational Cost
  • 24.
    Stream Intermediate Operators computation creation stateless/stateful Harnessingthe power Java 8 Streams Declarative Programming Internal Iteration chained categories Programming Paradigm Concepts
  • 25.
  • 26.
    Intermediate Operators Categories Stream<Integer> stream= Stream.of(3, 2, 1); Stream<Integer> filtered = stream.filter(n -> n % 2 == 0); Filtering Type of stream remains the same Stream<Integer> filtered = stream.filter(n -> n % 2 == 0);
  • 27.
    Intermediate Operators Categories Stream<Integer> stream= Stream.of(3, 2, 1); Stream<String> mapped = stream.map(Object::toString); Mapping Type of stream gets altered (here Integer to String) Stream<String> mapped = stream.map(Object::toString);
  • 28.
    Intermediate Operators Categories Stream<Integer> stream= Stream.of(3, 2, 1); Stream<Integer> sliced = stream.limit(1); Slicing Type of stream remains the same Stream<Integer> sliced = stream.limit(1);
  • 29.
    Stream.of(1, 2, 3,4)
 .peek(System.out::println)
 .filter(n -> n % 2 == 0); Intermediate Operators Laziness Stream.of(1, 2, 3, 4)
 .peek(System.out::println)
 .filter(n -> n % 2 == 0)
 .collect(toList()); Stream.of(1, 2, 3, 4)
 .peek(System.out::println)
 .filter(n -> n % 2 == 0); Terminal operator is required to start stream processing Stream.of(1, 2, 3, 4)
 .peek(System.out::println)
 .filter(n -> n % 2 == 0)
 .collect(toList()); Peek will not print anything
  • 30.
    Intermediate Operators Short-Circuiting Stream.of(1, 2,3, 4)
 .peek(System.out::println)
 .filter(n -> n % 2 == 0)
 .findFirst(); Stream will get short-circuited after the first element is found Peek will print only 1 & 2 Stream.of(1, 2, 3, 4)
 .peek(System.out::println)
 .filter(n -> n % 2 == 0)
 .findFirst();
  • 31.
    Intermediate Operators Stateless vs Stateful Stream.of(1,2, 3, 4)
 .peek(System.out::println)
 .filter(n -> n % 2 == 0)
 .findFirst(); Stream.of(1, 2, 3, 4)
 .peek(System.out::println)
 .sorted(Comparator.reverseOrder())
 .filter(n -> n % 2 == 0)
 .findFirst(); Will cause the whole stream to be traversed All operations are done on current value in stream Stream.of(1, 2, 3, 4)
 .peek(System.out::println)
 .sorted(Comparator.reverseOrder())
 .filter(n -> n % 2 == 0)
 .findFirst();
  • 32.
    Stream Collectorscollectreduce Intermediate Operators Terminal Operators computationcreation stateless/stateful Lazy & Short-Circuited Harnessing the power Java 8 Streams Declarative Programming Internal Iteration chained categories Programming Paradigm Concepts
  • 33.
    Terminal Operators Single ValueCollection Reduce Operation Collect Operation
  • 34.
    Terminal Operators reduce <U> Ureduce(U identity,
 BiFunction<U, ? super T, U> accumulator,
 BinaryOperator<U> combiner); Stream.of(3, 2, 1).reduce(0, Integer::sum, Integer::sum); Stream.of(3, 2, 1).reduce(0, Integer::sum); Immutable Reduction Process <U> U reduce(U identity,
 BiFunction<U, ? super T, U> accumulator,
 BinaryOperator<U> combiner); <U> U reduce(U identity,
 BiFunction<U, ? super T, U> accumulator,
 BinaryOperator<U> combiner); <U> U reduce(U identity,
 BiFunction<U, ? super T, U> accumulator,
 BinaryOperator<U> combiner);
  • 35.
    Terminal Operators reduce utilitymethods Optional<Integer> max = Stream.of(1, 2, 3) .max(Comparator.naturalOrder()); boolean result = Stream.of(1, 2, 3) .anyMatch(n -> n > 2); Optional<Integer> max = Stream.of(1, 2, 3) .max(Comparator.naturalOrder()); boolean result = Stream.of(1, 2, 3) .anyMatch(n -> n > 2);
  • 36.
    Terminal Operators collect Mutable ReductionProcess Accumulates elements into a mutable result container Stream.of("a", "b", "c").reduce("", String::concat); String copying = Low Performance !!
  • 37.
    Terminal Operators collect <R> Rcollect(Supplier<R> supplier,
 BiConsumer<R, ? super T> accumulator,
 BiConsumer<R, R> combiner); StringBuilder builder = Stream.of("a", "b", "c").collect(
 StringBuilder::new, 
 StringBuilder::append, 
 StringBuilder::append
 ); StringBuilder is the mutable container here
  • 38.
    Terminal Operators Collectors class StringjoinedString = Stream.of(“a", "b", “c") .collect(Collectors.joining(", ")); IntSummaryStatistics statistics = group.stream() .collect(Collectors.summarizingInt(Person::age)); IntSummaryStatistics{count=10, sum=280, min=26, average=28.000000, max=30} Output: a, b, c String joinedString = Stream.of(“a", "b", “c") .collect(Collectors.joining(", ")); IntSummaryStatistics statistics = group.stream() .collect(Collectors.summarizingInt(Person::age));
  • 39.
    Terminal Operators Downstream Collectors Map<Integer,List<Person>> result = group.stream() .collect(Collectors.groupingBy(Person::age,
 Collectors.toList())); Map<Integer, List<Person>> result = group.stream() .collect(groupingBy(Person::age)); Divide into different age groups
  • 40.
    Terminal Operators Downstream Collectors Map<Integer,Long> result = group.stream() .collect(groupingBy(Person::age, counting())); Map<Integer, List<String>> result = group.stream() .collect(groupingBy(Person::age,
 mapping(Person::name, toList()))); Count of people in each age group Names on people in each age group
  • 41.
    Stream Collectorscollectreduce Intermediate Operators Terminal Operators computationcreation Primitive Streams stateless/stateful Lazy & Short-Circuited Harnessing the power Java 8 Streams Declarative Programming Internal Iteration chained categories Programming Paradigm Concepts
  • 42.
    Primitive Streams IntStream DoubleStreamLongStream Avoidboxing and unboxing costs Numeric operations are available XXXFunction XXXPredicateXXXSupplierXXXConsumer XXXToXXXFunction Primitive Functional Interfaces
  • 43.
    Primitive Streams Creating fromfactory methods IntStream intStream = IntStream.range(1, 10); DoubleStream doubleStream = DoubleStream.of(1.0, 2.0); LongStream longStream = LongStream.iterate(0L, n -> n + 4); Generating a range of numbers Stream of known set of numbers Stream using iterative application of a function
  • 44.
    Stream<Person> stream =group.stream(); Primitive Streams Obtaining from Stream<T> mapToXXX flatMapToXXX IntStream intStream = stream.mapToInt(Person::age); OptionalDouble averageAge = intStream.average(); Specialized methods on Primitive Streams IntStream intStream = stream.mapToInt(Person::age);
  • 45.
    Primitive Streams Converting backto Stream<T> Stream<Integer> boxed = IntStream.of(1, 2, 3).boxed();Stream<Integer> boxed = IntStream.of(1, 2, 3).boxed();
  • 46.
    Stream Collectorscollectreduce Intermediate Operators Terminal Operators computationcreation Primitive Streams stateless/stateful Lazy & Short-Circuited Harnessing the power Java 8 Streams Declarative Programming Internal Iteration chained categories Programming Paradigm Concepts
  • 47.