Presented at the IndicThreads.com Software Development Conference 2016 held in Pune, India. More at http://www.IndicThreads.com and http://Pune16.IndicThreads.com
--
3. 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
4. –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..”
7. Harnessing the power Java 8 Streams
Declarative
Programming
Internal
Iteration
Programming Paradigm Concepts
8. 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
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 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) {
}
12. 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
14. Stream
a read-only sequence of elements
computational operations that will be performed
in aggregate
Collection
efficient management of elements
efficient access to elements
17. 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
19. Creating Stream
From an I/O Channel
try (Stream<Path> stream =
Files.list(Paths.get(“.”));) {
…
}
Stream interface extends AutoCloseable
20. Creating Stream
Using Generator Functions
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();
23. Parallel Stream
Performance Impact
Always measure performance before using parallel
Stream size predictability & Amount of data
Decomposability of source data structure
Computational Cost
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();
34. 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);
35. 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);
36. 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 !!
37. 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
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
43. 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