Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Harnessing the Power of Java 8 Streams

Harnessing the Power of Java 8 Streams

This talk was given at IndicThreads Conference, 3-4 June 2016, Pune, India (http://pune16.indicthreads.com/).

Collection Streams, introduced in Java 8, requires a software developer to start thinking in declarative paradigm. For one who has been accustomed to the imperative paradigm, writing declarative code is not immediately intuitive.

My goal from this talk are:
- Help the attendees make the transition to the new paradigm easy and
- Help the attendees to start harnessing the power of Streams in their daily work.

Collection Streams
– Solving a problem declarative style
– External Iteration and Internal Iteration
– Stream as a Builder
– Intermediate Operations (filtering, slicing, mapping)
– Terminal Operation (reduction and collection)
– Reduction (finding, matching)
– Collection (Collectors, grouping and downstream)

Praveer Gupta

June 03, 2016
Tweet

More Decks by Praveer Gupta

Other Decks in Technology

Transcript

  1. 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
  2. –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..”
  3. Stream Collectors collect reduce 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
  4. 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
  5. 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());
  6. 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) { }
  7. 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
  8. Stream computation creation Harnessing the power Java 8 Streams Declarative

    Programming Internal Iteration Programming Paradigm Concepts
  9. Stream a read-only sequence of elements computational operations that will

    be performed in aggregate Collection efficient management of elements efficient access to elements
  10. Stream Terminal Operator Operator 1 Operator 2 Operator 3 Stream

    Pipeline List<String> namesOfAdultsInTheGroup(List<Person> group) {
 return
 
 
 
 } group.stream() .filter(p -> p.age() > 18) .map(Person::name) .collect(Collectors.toList());
  11. 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
  12. 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);
  13. Creating Stream From an I/O Channel try (Stream<Path> stream =

    Files.list(Paths.get(“.”));) { … } Stream interface extends AutoCloseable
  14. 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();
  15. Parallel Stream Performance Impact Always measure performance before using parallel

    Stream size predictability & Amount of data Decomposability of source data structure Computational Cost
  16. Stream Intermediate Operators computation creation stateless/stateful Harnessing the power Java

    8 Streams Declarative Programming Internal Iteration chained categories Programming Paradigm Concepts
  17. 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);
  18. 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);
  19. 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);
  20. 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
  21. 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();
  22. 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();
  23. Stream Collectors collect reduce 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
  24. 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);
  25. 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);
  26. 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 !!
  27. 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
  28. 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));
  29. 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
  30. 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
  31. Stream Collectors collect reduce 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
  32. Primitive Streams IntStream DoubleStream LongStream Avoid boxing and unboxing costs

    Numeric operations are available XXXFunction XXXPredicate XXXSupplier XXXConsumer XXXToXXXFunction Primitive Functional Interfaces
  33. 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
  34. 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);
  35. 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();
  36. Stream Collectors collect reduce 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