Slide 1

Slide 1 text

Java Streams Deep Dive Eder Ignatowicz Sr. Software Engineer JBoss by Red Hat

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

FP <3

Slide 4

Slide 4 text

Linguagens de Programação <3

Slide 5

Slide 5 text

Java <3

Slide 6

Slide 6 text

Pugs <3

Slide 7

Slide 7 text

Dora

Slide 8

Slide 8 text

Bento

Slide 9

Slide 9 text

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 );

Slide 10

Slide 10 text

Streams API

Slide 11

Slide 11 text

Streams: Manipula coleções de forma declarativa Quais são os nomes dos Pugs com peso maior do que 9 quilos?

Slide 12

Slide 12 text

Streams: Manipula coleções de forma declarativa SELECT nome FROM pugs WHERE weight < 9 order by peso.

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Java 8 Streams API

Slide 16

Slide 16 text

List 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

Slide 17

Slide 17 text

List 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

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

(

Slide 20

Slide 20 text

Parallel streams não são mágica!

Slide 21

Slide 21 text

)

Slide 22

Slide 22 text

Stream Pipelines filter pugs -> —> sorted —> map —> collect lambda lambda lambda

Slide 23

Slide 23 text

Código: Declarativo Componentizável Paralelizável Streams API

Slide 24

Slide 24 text

Sequência de elementos de uma fonte que suporta operações de processamento em seus dados Streams

Slide 25

Slide 25 text

Sequência de elementos de uma fonte que suporta operações de processamento em seus dados Streams

Slide 26

Slide 26 text

Sequência de elementos de uma fonte que suporta operações de processamento em seus dados Streams

Slide 27

Slide 27 text

Streams Uma fonte de dados para a query Uma cadeia de operações intermediárias (pipeline) Uma operação terminal que gera o resultado

Slide 28

Slide 28 text

Vamos a prática

Slide 29

Slide 29 text

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; }

Slide 30

Slide 30 text

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 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 ));

Slide 31

Slide 31 text

Quais são as vendas que fizemos em 2015? Ordenadas?

Slide 32

Slide 32 text

List vendas2015 = transactions .stream()

Slide 33

Slide 33 text

List vendas2015 = transactions .stream() .filter( venda -> venda.getAno() == 2015 )

Slide 34

Slide 34 text

List vendas2015 = transactions .stream() .filter( venda -> venda.getAno() == 2015 ) .sorted( comparing( Venda::getValor ) )

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

List 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}

Slide 37

Slide 37 text

Em que cidades temos vendedores?

Slide 38

Slide 38 text

Campinas Apucarana Piracicaba Londrina List cidadesAtendidas = vendas.stream() .map( venda ->venda.getVendedor().getCidade() ) .distinct() .collect( toList() );

Slide 39

Slide 39 text

Qual foi a maior venda?

Slide 40

Slide 40 text

500 OptionalInt maiorVenda = vendas.stream() .mapToInt(Venda::getValor) .reduce( Integer::max ); maiorVenda.ifPresent( i -> System.out.println(i));

Slide 41

Slide 41 text

Total de vendas?

Slide 42

Slide 42 text

2000 OptionalInt total = vendas.stream() .mapToInt(Venda::getValor) .reduce( Integer::sum ); total.ifPresent( i -> System.out.println(i));

Slide 43

Slide 43 text

Quais são as vendas de cada vendedor? Ordenadas?

Slide 44

Slide 44 text

Map> vendedorPorVendas = vendas.stream() .sorted( comparing( Venda::getValor ) ) .collect( groupingBy( Venda::getVendedor ) );

Slide 45

Slide 45 text

{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> vendedorPorVendas = vendas.stream() .sorted( comparing( Venda::getValor ) ) .collect( groupingBy( Venda::getVendedor ) );

Slide 46

Slide 46 text

Refactoring Loops to Collection Pipelines

Slide 47

Slide 47 text

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; } … }

Slide 48

Slide 48 text

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 clientMails = repo.getClientMails(); assertEquals( 2, clientMails.size() ); assertTrue( clientMails.contains( "[email protected]" ) ); assertTrue( clientMails.contains( "[email protected]" ) ); assertTrue( !clientMails.contains( "[email protected]" ) ); } }

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

public List getClientMails() { ArrayList emails = new ArrayList<>(); List 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

Slide 52

Slide 52 text

public List getClientMails() { ArrayList emails = new ArrayList<>(); List 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

Slide 53

Slide 53 text

Filter Operation public List getClientMails() { ArrayList emails = new ArrayList<>(); List 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; }

Slide 54

Slide 54 text

Pipeline public List getClientMails() { ArrayList 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; }

Slide 55

Slide 55 text

public List getClientMails() { return clients .stream() .filter( c -> c.getCompany() != null ) .map( c -> c.getEmail() ) .filter( m -> m != null ) .collect( Collectors.toList() ); }

Slide 56

Slide 56 text

No content

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

Streams são lazy

Slide 59

Slide 59 text

Stream Pipelines filter pugs -> —> map —> collect lambda lambda

Slide 60

Slide 60 text

Stream Pipelines intermediate pugs -> —> —> findFirst lambda lambda intermediate

Slide 61

Slide 61 text

Lazy Streams List 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 ) );

Slide 62

Slide 62 text

Qual o nome do primeiro SRD que pesa mais do que 5kg?

Slide 63

Slide 63 text

String nomePrimeiroSRDMaiorDoQue5Kg = dogs.stream() .filter( dog -> { return dog.getBreed().equals( Dog.BREED.SRD ) && dog.getWeight() > 5; } ) .map( dog -> { return dog.getName(); } ) .findFirst() .get();

Slide 64

Slide 64 text

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" —> —>

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

String nomePrimeiroSRDMaiorDoQue5Kg = dogs.stream() .filter( dog -> { return dog.getBreed().equals( Dog.BREED.SRD ) && dog.getWeight() > 5; } ) .map( dog -> { return dog.getName(); } ) .findFirst() .get(); List 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

Slide 67

Slide 67 text

Streams "infinitos"

Slide 68

Slide 68 text

Criar uma lista de números primos infinita

Slide 69

Slide 69 text

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 ); } }

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

FlatMap

Slide 72

Slide 72 text

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 devs = Arrays.asList( eder, dora ); List booksNames = devs .stream() .map( dev -> dev.getBooks() ) //Stream> .flatMap( books -> books.stream() )//Stream .distinct() .collect( Collectors.toList() ); booksNames.forEach( System.out::println );

Slide 73

Slide 73 text

IntStream DoubleStream, LongStream…

Slide 74

Slide 74 text

IntStream.of( 1, 2, 3 ); // > 1, 2, 3 IntStream.range( 1, 3 ); // > 1, 2

Slide 75

Slide 75 text

dogs.stream() .filter( dog -> dog.getBreed().equals( Dog.BREED.PUG ) ) .map( Dog::getWeight ) .filter( weight -> weight > 10 ) .mapToInt( weight -> weight ) .sum(); 0.185s

Slide 76

Slide 76 text

dogs.stream() .filter( dog -> dog.getBreed().equals( Dog.BREED.PUG ) ) .mapToInt( Dog::getWeight ) .filter( weight -> weight > 10 ) .sum(); 0.004s

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

dogs.stream()//Stream .filter( dog -> dog.getBreed().equals( Dog.BREED.PUG ) )//Stream .mapToInt( Dog::getWeight ) //IntStream .filter( weight -> weight > 10 ) //IntStream .sum(); 0.004s

Slide 79

Slide 79 text

dogs.stream()//Stream .filter( dog -> dog.getBreed().equals( Dog.BREED.PUG ) )//Stream .mapToInt( Dog::getWeight ) //IntStream .filter( weight -> weight > 10 ) //IntStream .max(); 0.004s

Slide 80

Slide 80 text

dogs.stream()//Stream .filter( dog -> dog.getBreed().equals( Dog.BREED.PUG ) )//Stream .mapToInt( Dog::getWeight ) //IntStream .filter( weight -> weight > 10 ) //IntStream .summaryStatistics(); IntSummaryStatistics{count=224, sum=4490, min=11, average=20.044643, max=30}

Slide 81

Slide 81 text

ParallelStreams

Slide 82

Slide 82 text

dogs.stream()//Stream .mapToInt( Dog::getWeight ) //IntStream .filter( weight -> weight > 10 ) //IntStream .sum(); 0.129s

Slide 83

Slide 83 text

dogs.parallelStream()//Stream .mapToInt( Dog::getWeight ) //IntStream .filter( weight -> weight > 10 ) //IntStream .sum(); 0.017s

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

No content

Slide 86

Slide 86 text

dogs.parallelStream() .mapToInt( Dog::getWeight ) .reduce( Math::max ) .ifPresent( p -> System.out.println( "Maior peso: " + p ) );

Slide 87

Slide 87 text

java.util.Spliterator java.util.concurrent.ForkJoinPool.commonPool()

Slide 88

Slide 88 text

java.util.Spliterator

Slide 89

Slide 89 text

Spliterator = splitter + iterator

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

java.util.concurrent.ForkJoinPool.commonPool()

Slide 92

Slide 92 text

Fork Join Framework

Slide 93

Slide 93 text

Task Child Task fork() fork() join() join() … … … … Child Task

Slide 94

Slide 94 text

CommonPool Singleton fork-join pool instance

Slide 95

Slide 95 text

public static String query( String question ) { List 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 result = engines.stream() .parallel().map( ( base ) -> { String url = base + question; // open connection and fetch the result return Util.read( url ); } ).findAny(); return result.get(); }

Slide 96

Slide 96 text

public static String query( String question ) { List 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 result = engines.stream() .parallel().map( ( base ) -> { String url = base + question; // open connection and fetch the result return Util.read( url ); } ).findAny(); return result.get(); }

Slide 97

Slide 97 text

dogs.parallelStream() .mapToInt( Dog::getWeight ) .reduce( Math::max ) .ifPresent( p -> System.out.println( "Maior peso: " + p ) );

Slide 98

Slide 98 text

No content

Slide 99

Slide 99 text

No content

Slide 100

Slide 100 text

public List getClientMails() { return clients .stream() .filter( c -> c.getCompany() != null ) .map( c -> c.getEmail() ) .filter( m -> m != null ) .collect( Collectors.toList() ); }

Slide 101

Slide 101 text

No content

Slide 102

Slide 102 text

Obrigado!!! @ederign