Java 8 Stream API. A different way to process collections

download Java 8 Stream API. A different way to process collections

of 51

  • date post

    27-Aug-2014
  • Category

    Software

  • view

    419
  • download

    3

Embed Size (px)

description

A look on one of the features of Java 8 hidden behind the lambdas. A different way to iterate Collections. You'll never see the Collecions the same way. These are the slides I used on my talk at the "Tech Thursday" by Oracle in June in Madrid.

Transcript of Java 8 Stream API. A different way to process collections

  • Java8 Stream API A different way to process collections David Gmez G. @dgomezg dgomezg@autentia.com
  • Streams? Whats that?
  • A Stream is An convenience method to iterate over collections in a declarative way List numbers = new ArrayList(); for (int i= 0; i < 100 ; i++) { numbers.add(i); } List evenNumbers = new ArrayList(); for (int i : numbers) { if (i % 2 == 0) { evenNumbers.add(i); } } @dgomezg
  • A Stream is An convenience method to iterate over collections in a declarative way List numbers = new ArrayList(); for (int i= 0; i < 100 ; i++) { numbers.add(i); } List evenNumbers = numbers.stream() .filter(n -> n % 2 == 0) .collect(toList()); @dgomezg
  • So Streams are collections? Not Really Collections Streams Sequence of elements Computed at construction In-memory data structure Sequence of elements Computed at iteration Traversable only Once External Iteration Internal Iteration Finite size Infinite size @dgomezg
  • Iterating a Collection List evenNumbers = new ArrayList(); for (int i : numbers) { if (i % 2 == 0) { evenNumbers.add(i); } } External Iteration - Use forEach or Iterator - Very verbose Parallelism by manually using Threads - Concurrency is hard to be done right! - Lots of contention and error-prone - Thread-safety@dgomezg
  • Iterating a Stream List evenNumbers = numbers.stream() .filter(n -> n % 2 == 0) .collect(toList()); Internal Iteration - No manual Iterators handling - Concise - Fluent API: chain sequence processing Elements computed only when needed @dgomezg
  • Iterating a Stream List evenNumbers = numbers.parallelStream() .filter(n -> n % 2 == 0) .collect(toList()); Easily Parallelism - Concurrency is hard to be done right! - Uses ForkJoin - Process steps should be - stateless - independent @dgomezg
  • Lambdas & Method References
  • @FunctionalInterface @FunctionalInterface public interface Predicate { boolean test(T t); ! ! ! ! ! } An interface with exactly one abstract method ! ! @dgomezg
  • @FunctionalInterface @FunctionalInterface public interface Predicate { boolean test(T t); ! default Predicate negate() { return (t) -> !test(t); } ! } An interface with exactly one abstract method Could have default methods, though! ! @dgomezg
  • Lambda Types Based on abstract method signature from @FunctionalInterface: (Arguments) -> @FunctionalInterface public interface Predicate { boolean test(T t); } T -> boolean @dgomezg
  • Lambda Types Based on abstract method signature from @FunctionalInterface: (Arguments) -> @FunctionalInterface public interface Runnable { void run(); } () -> void @dgomezg
  • Lambda Types Based on abstract method signature from @FunctionalInterface: (Arguments) -> @FunctionalInterface public interface Supplier { T get(); } () -> T @dgomezg
  • Lambda Types Based on abstract method signature from @FunctionalInterface: (Arguments) -> @FunctionalInterface public interface BiFunction { R apply(T t, U t); } (T, U) -> R @dgomezg
  • Lambda Types Based on abstract method signature from @FunctionalInterface: (Arguments) -> @FunctionalInterface public interface Comparator { int compare(T o1, T o2); } (T, T) -> int @dgomezg
  • Method References Allows to use a method name as a lambda Usually better readability ! Syntax: :: ! TargetReference: Instance or Class @dgomezg
  • Method References phoneCall -> phoneCall.getContact() Method ReferenceLambda PhoneCall::getContact () -> Thread.currentThread() Thread::currentThread (str, c) -> str.indexOf(c) String::indexOf (String s) -> System.out.println(s) System.out::println @dgomezg
  • From Collections to Streams
  • Characteristics of A Stream Interface to Sequence of elements Focused on processing (not on storage) Elements computed on demand (or extracted from source) Can be traversed only once Internal iteration Parallel Support Could be Infinite @dgomezg
  • Anatomy of a Stream Source Intermediate Operations filter map order function Final operation pipeline @dgomezg
  • Anatomy of Stream Iteration 1. Start from the DataSource (Usually a collection) and create the Stream List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Stream numbersStream = numbers.stream(); @dgomezg
  • Anatomy of Stream Iteration 2. Add a chain of intermediate Operations (Stream Pipeline) Stream numbersStream = numbers.stream() .filter(new Predicate() { @Override public boolean test(Integer number) { return number % 2 == 0; } }) ! .map(new Function() { @Override public Integer apply(Integer number) { return number * 2; } }); @dgomezg
  • Anatomy of Stream Iteration 2. Add a chain of intermediate Operations (Stream Pipeline) - Better using lambdas Stream numbersStream = numbers.stream() .filter(number -> number % 2 == 0) .map(number -> number * 2); @dgomezg
  • Anatomy of Stream Iteration 3. Close with a Terminal Operation List numbersStream = numbers.stream() .filter(number -> number % 2 == 0) .map(number -> number * 2) .collect(Collectors.toList()); The terminal operation triggers Stream Iteration Before that, nothing is computed. Depending on the terminal operation, the stream could be fully traversed or not. @dgomezg
  • Stream operations
  • Operation Types Intermediate operations Always return a Stream Chain as many as needed (Pipeline) Guide processing of data Does not start processing Can be Stateless or Stateful Terminal operations Can return an object, a collection, or void Start the pipeline process After its execution, the Stream can not be revisited
  • Intermediate Operations // T -> boolean Stream filter(Predicate