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

Java 8 Streams Deep Dive

Java 8 Streams Deep Dive

Streams are the new Java API that let's us manipulate collections of data in a declarative way. But this API is much more than just fancy iterators over collections of data.
Streams are the API that will completely change how we code in Java. In this talk we will make a deep dive in the Streams power, covering:
- Review Streams API covering filtering techniques, map-reduce, finding and matching and collectors;
- Learn how to build my own streams and collectors;
- Deep dive in parallels streams, spliterators and parallels best practices;
- Explore lazy evaluation and infinite streams;
The talk will consist of a balance between theoretical concepts and practical applications. Attendees will leave with deep knowledge of the theory and practical use of the power of the Streams API.

Eder Ignatowicz

June 28, 2016
Tweet

More Decks by Eder Ignatowicz

Other Decks in Technology

Transcript

  1. public Pug( String name, String color, Integer weight ) {

    this.name = nome; this.color = color; this.weight = weight; } Pug dora = new Pug( "Dora", "abricot", 10 ); Pug bento = new Pug( "Bento", "abricot", 13 ); Pug jesse = new Pug( "Jesse", "black", 9 );
  2. Em Java List<Pug> gordinhos = new ArrayList<>(); for ( Pug

    pug : pugs ) { if ( pug.getWeight() > 9 ) { gordinhos.add( pug ); } } Collections.sort( gordinhos, new Comparator<Pug>() { @Override public int compare( Pug p1, Pug p2 ) { return Integer.compare( p1.getWeight(), p2.getWeight() ); } }); List<String> nomeGordinhos = new ArrayList<>(); for ( Pug pug : gordinhos ) { nomeGordinhos.add( pug.getNome() ); }
  3. List<String> fatName = pugs.stream() .filter( p -> p.getWeight() > 9

    ) .sorted( comparing( Pug::getWeight ) ) .map( Pug::getNome ) .collect( toList() ); Em Java Seleciona > 9 kg Ordena por peso Extrai o nome Coleta em uma lista
  4. List<String> fatName = pugs.parallelStream() .filter( p -> dora.getWeight() > 9

    ) .sorted( comparing( Pug::getWeight ) ) .map( Pug::getNome ) .collect( toList() ); Em Java Seleciona > 9 kg Ordena por peso Extrai o nome Coleta em uma lista
  5. (

  6. )

  7. Streams Uma fonte de dados para a query Uma cadeia

    de operações intermediárias (pipeline) Uma operação terminal que gera o resultado
  8. public Venda( Vendedor vendedor, int ano, int valor ) {

    this.vendedor = vendedor; this.ano = ano; this.valor = valor; } public Vendedor( String nome, String cidade ) { this.nome = nome; this.cidade = cidade; }
  9. Vendedor eder = new Vendedor("Eder", "Campinas"); Vendedor pedro = new

    Vendedor("Pedro", "Apucarana"); Vendedor luciano = new Vendedor("Luciano", "Piracicaba"); Vendedor junior = new Vendedor("Junior", "Londrina"); List<Venda> transactions = Arrays.asList( new Venda( eder, 2015, 100 ), new Venda( eder, 2016, 200 ), new Venda( pedro, 2015, 300 ), new Venda( luciano, 2015, 500 ), new Venda( luciano, 2015, 400 ), new Venda( junior, 2016, 500 ));
  10. List<Venda> vendas2015 = transactions .stream() .filter( venda -> venda.getAno() ==

    2015 ) .sorted( comparing( Venda::getValor ) ) .collect( toList() );
  11. List<Venda> vendas2015 = transactions .stream() .filter( venda -> venda.getAno() ==

    2015 ) .sorted( comparing( Venda::getValor ) ) .collect( toList() ); vendas2015.forEach(System.out::println); Venda{vendedor=Vendedor{nome='Eder', cidade='Campinas'}, ano=2015, valor=100} Venda{vendedor=Vendedor{nome='Pedro', cidade='Apucarana'}, ano=2015, valor=300} Venda{vendedor=Vendedor{nome='Luciano', cidade='Piracicaba'}, ano=2015, valor=400} Venda{vendedor=Vendedor{nome='Luciano', cidade='Piracicaba'}, ano=2015, valor=500}
  12. Campinas Apucarana Piracicaba Londrina List<String> cidadesAtendidas = vendas.stream() .map( venda

    ->venda.getVendedor().getCidade() ) .distinct() .collect( toList() );
  13. {Vendedor{nome='Junior', cidade='Londrina'}=[Venda{vendedor=Vendedor{nome='Junior', cidade='Londrina'}, ano=2016, valor=500}], Vendedor{nome='Eder', cidade='Campinas'}=[Venda{vendedor=Vendedor{nome='Eder', cidade='Campinas'}, ano=2015, valor=100},

    Venda{vendedor=Vendedor{nome='Eder', cidade='Campinas'}, ano=2016, valor=200}], Vendedor{nome='Pedro', cidade='Apucarana'}=[Venda{vendedor=Vendedor{nome='Pedro', cidade='Apucarana'}, ano=2015, valor=300}], Vendedor{nome='Luciano', cidade='Piracicaba'} =[Venda{vendedor=Vendedor{nome='Luciano', cidade='Piracicaba'}, ano=2015, valor=400}, Venda{vendedor=Vendedor{nome='Luciano', cidade='Piracicaba'}, ano=2015, valor=500}]} Map<Vendedor, List<Venda>> vendedorPorVendas = vendas.stream() .sorted( comparing( Venda::getValor ) ) .collect( groupingBy( Venda::getVendedor ) );
  14. public class Client { private String name; private String email;

    private Company company; public Client( String name, String email, Company company ) { this.name = name; this.email = email; this.company = company; } public Client( String name ) { this.name = name; } public Client( String name, String email ) { this.name = name; this.email = email; } … }
  15. public class ClientRepositoryTest { private ClientRepository repo; @Before public void

    setup() { Company empresa = new Company( "RedHat" ); Client completo1 = new Client( "Completo1", "[email protected]", empresa ); Client completo2 = new Client( "Completo2", "[email protected]", empresa ); Client semEmpresa = new Client( "SemEmpresa", "[email protected]" ); Client somenteNome = new Client( "SomenteNome" ); repo = new ClientRepository( Arrays.asList( completo1, semEmpresa, completo2, somenteNome ) ); } @Test public void getClientEmailsWithCompanyTest() { List<String> clientMails = repo.getClientMails(); assertEquals( 2, clientMails.size() ); assertTrue( clientMails.contains( "[email protected]" ) ); assertTrue( clientMails.contains( "[email protected]" ) ); assertTrue( !clientMails.contains( "[email protected]" ) ); } }
  16. public List<String> getClientMails() { ArrayList<String> emails = new ArrayList<>(); for

    ( Client client : clients ) { if ( client.getCompany() != null ) { String email = client.getEmail(); if ( email != null ){ emails.add( email ); } } } return emails; }
  17. public List<String> getClientMails() { ArrayList<String> emails = new ArrayList<>(); List<Client>

    pipeline = clients; for ( Client client : pipeline ) { if ( client.getCompany() != null ) { String email = client.getEmail(); if ( email != null ){ emails.add( email ); } } } return emails; } } Extract Variable
  18. public List<String> getClientMails() { ArrayList<String> emails = new ArrayList<>(); List<Client>

    pipeline = clients .stream() .filter( c -> c.getCompany() != null ) .collect( Collectors.toList() ); for ( Client client : pipeline ) { if ( client.getCompany() != null ) { String email = client.getEmail(); if ( email != null ) { emails.add( email ); } } } return emails; } } Filter Operation
  19. public List<String> getClientMails() { ArrayList<String> emails = new ArrayList<>(); List<String>

    pipeline = clients .stream() .filter( c -> c.getCompany() != null ) .map( c -> c.getEmail() ) .collect( Collectors.toList() ); for ( String mail : pipeline ) { String email = client.getEmail(); if ( mail != null ) { emails.add( mail ); } } return emails; } Map Operation
  20. Filter Operation public List<String> getClientMails() { ArrayList<String> emails = new

    ArrayList<>(); List<String> pipeline = clients .stream() .filter( c -> c.getCompany() != null ) .map( c -> c.getEmail() ) .filter( m -> m != null ) .collect( Collectors.toList() ); for ( String mail : pipeline ) { if ( mail != null ) { emails.add( mail ); } } return emails; }
  21. Pipeline public List<String> getClientMails() { ArrayList<String> emails = new ArrayList<>();

    return clients .stream() .filter( c -> c.getCompany() != null ) .map( c -> c.getEmail() ) .filter( m -> m != null ) .collect( Collectors.toList() ); for ( String mail : pipeline ) { if ( mail != null ) { emails.add( mail ); } } return emails; }
  22. public List<String> getClientMails() { return clients .stream() .filter( c ->

    c.getCompany() != null ) .map( c -> c.getEmail() ) .filter( m -> m != null ) .collect( Collectors.toList() ); }
  23. Lazy Streams List<Dog> dogs = Arrays.asList( new Dog( "Dora", 10,

    Dog.BREED.PUG ), new Dog( "Bento", 13, Dog.BREED.PUG ), new Dog( "Rex", 8, Dog.BREED.SRD ), new Dog( "Tetezinha", 6, Dog.BREED.SRD ), new Dog( "Banze", 7, Dog.BREED.SRD ), new Dog( "Rufus", 15, Dog.BREED.BULLDOG ) );
  24. String nomePrimeiroSRDMaiorDoQue5Kg = dogs.stream() .filter( dog -> { return dog.getBreed().equals(

    Dog.BREED.SRD ) && dog.getWeight() > 5; } ) .map( dog -> { return dog.getName(); } ) .findFirst() .get();
  25. Eager Streams Dora Bento Rex Teté Banzé Rin Tin tin

    —> SRD e peso> 5 filter map Rex Teté Banzé —> Nome "Rex" “Teté" “Banzé" —> —> Nome findFirst “Rex" —> —>
  26. Lazy Stream Dora Bento Rex Teté Banzé Rin Tin tin

    —> SRD e peso> 5 filter map Rex —> Nome “Rex" —> —> first() findFirst “Rex" —> —>
  27. String nomePrimeiroSRDMaiorDoQue5Kg = dogs.stream() .filter( dog -> { return dog.getBreed().equals(

    Dog.BREED.SRD ) && dog.getWeight() > 5; } ) .map( dog -> { return dog.getName(); } ) .findFirst() .get(); List<Dog> dogs = Arrays.asList( new Dog( "Dora", 10, Dog.BREED.PUG ), new Dog( "Bento", 13, Dog.BREED.PUG ), new Dog( "Rex", 8, Dog.BREED.SRD ), new Dog( "Tetezinha", 6, Dog.BREED.SRD ), new Dog( "Banze", 7, Dog.BREED.SRD ), new Dog( "Rufus", 15, Dog.BREED.BULLDOG ) ); filter - Dora filter - Bento filter - Rex map - Rex Rex
  28. public static boolean isPrime( final int number ) { return

    number > 1 && IntStream.rangeClosed( 2, ( int ) Math.sqrt( number ) ) .noneMatch( divisor -> number % divisor == 0 ); } public static int primeAfter( final int number ) { if ( isPrime( number + 1 ) ) { return number + 1; } else { return primeAfter( number + 1 ); } }
  29. public static IntStream primesInfinityStream( int fromNumber) { return IntStream.iterate( primeAfter(

    fromNumber - 1 ), Primes::primeAfter ); } primesInfinityStream( 1 ) .limit( 10 ) .forEach( i -> System.out.print( i+ ", " ) ); primesInfinityStream( 1000 ) .limit( 5 ) .forEach( i -> System.out.print( i+ ", " ) ); 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 1009, 1013, 1019, 1021, 1031
  30. Developer eder = new Developer(); eder.bestBooks( "Java 8 in Action",

    "SICP", "The Little Schemer" ); Developer dora = new Developer(); dora.bestBooks( "Effective Java", "Pragmatic Programmer", "SICP" ); List<Developer> devs = Arrays.asList( eder, dora ); List<String> booksNames = devs .stream() .map( dev -> dev.getBooks() ) //Stream<Set<String>> .flatMap( books -> books.stream() )//Stream<String> .distinct() .collect( Collectors.toList() ); booksNames.forEach( System.out::println );
  31. IntStream.of( 1, 2, 3 ); // > 1, 2, 3

    IntStream.range( 1, 3 ); // > 1, 2
  32. dogs.stream() .filter( dog -> dog.getBreed().equals( Dog.BREED.PUG ) ) .map( Dog::getWeight

    ) .filter( weight -> weight > 10 ) .mapToInt( weight -> weight ) .sum(); 0.185s
  33. dogs.stream() //Stream<Dog> .filter( dog -> dog.getBreed().equals( Dog.BREED.PUG ) )//Stream<Dog> .map(

    Dog::getWeight )//Stream<Integer> boxing :( .filter( weight -> weight > 10 )//Stream<Integer> boxing reboxing .mapToInt( weight -> weight ) //IntStream .sum(); 0.185s
  34. dogs.stream()//Stream<Dog> .filter( dog -> dog.getBreed().equals( Dog.BREED.PUG ) )//Stream<Dog> .mapToInt( Dog::getWeight

    ) //IntStream .filter( weight -> weight > 10 ) //IntStream .summaryStatistics(); IntSummaryStatistics{count=224, sum=4490, min=11, average=20.044643, max=30}
  35. seq paralel ArrayList 8.33 ms 6.33 ms LinkedList 12.74 ms

    19.57 ms HashSet 20.76 ms 16.01 ms TreeSet 19.79 ms 15.49 ms
  36. public static String query( String question ) { List<String> engines

    = new ArrayList<>(); engines.add( "https://www.google.com/?q=" ); engines.add( "https://duckduckgo.com/?q=" ); engines.add( "https://www.bing.com/search?q=" ); // get element as soon as it is available Optional<String> result = engines.stream() .parallel().map( ( base ) -> { String url = base + question; // open connection and fetch the result return Util.read( url ); } ).findAny(); return result.get(); }
  37. public static String query( String question ) { List<String> engines

    = new ArrayList<>(); engines.add( "https://www.google.com/?q=" ); engines.add( "https://duckduckgo.com/?q=" ); engines.add( "https://www.bing.com/search?q=" ); // get element as soon as it is available Optional<String> result = engines.stream() .parallel().map( ( base ) -> { String url = base + question; // open connection and fetch the result return Util.read( url ); } ).findAny(); return result.get(); }
  38. public List<String> getClientMails() { return clients .stream() .filter( c ->

    c.getCompany() != null ) .map( c -> c.getEmail() ) .filter( m -> m != null ) .collect( Collectors.toList() ); }