Cdigo funcional em Java: Superando o hype Eder Ignatowicz @ederign - - PowerPoint PPT Presentation

c digo funcional em java superando o hype
SMART_READER_LITE
LIVE PREVIEW

Cdigo funcional em Java: Superando o hype Eder Ignatowicz @ederign - - PowerPoint PPT Presentation

Cdigo funcional em Java: Superando o hype Eder Ignatowicz @ederign Lambda Expressions 101 Dora Bento <3 Jesse "Pinkman" public Pug( String nome, String color, Integer size ) { this.nome = nome; this.color = color;


slide-1
SLIDE 1

Código funcional em Java: Superando o hype

Eder Ignatowicz @ederign

slide-2
SLIDE 2
slide-3
SLIDE 3
slide-4
SLIDE 4

Lambda Expressions 101

slide-5
SLIDE 5

Dora

slide-6
SLIDE 6

Bento

slide-7
SLIDE 7

<3

slide-8
SLIDE 8

Jesse "Pinkman"

slide-9
SLIDE 9

public Pug( String nome, String color, Integer size ) { this.nome = nome; this.color = color; this.weight = size; } 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

Requisito: Filtrar todos os pugs de cor “abricot" da lista

slide-11
SLIDE 11

Filtrar todos os pugs de cor “abricot" da lista

private static List<Pug> filterAbricotPugs( List<Pug> pugs ) { List<Pug> abricots = new ArrayList<>(); for ( Pug pug : pugs ) { if ( pug.getColor().equals( "abricot" ) ) { abricots.add( pug ); } } return abricots; }

List<Pug> pugs = Arrays.asList( dora, bento, jesse ); List<Pug> abricot = filterAbricotPugs( pugs );

Pug{nome='Dora', color='abricot', weight=10} Pug{nome='Bento', color='abricot', weight=13}

slide-12
SLIDE 12

Novo Requisito: :) Filtrar todos os pugs de cor “black" da lista

slide-13
SLIDE 13

private static List<Pug> filterAbricotPugs( List<Pug> pugs ) { List<Pug> abricots = new ArrayList<>(); for ( Pug pug : pugs ) { if ( pug.getColor().equals( "abricot" ) ) { abricots.add( pug ); } } return abricots; }

private static List<Pug> filterBlackPugs( List<Pug> pugs ) { List<Pug> abricots = new ArrayList<>(); for ( Pug pug : pugs ) { if ( pug.getColor().equals( "black" ) ) { abricots.add( pug ); } } return abricots; }

slide-14
SLIDE 14

Filtrar todos os pugs de cor “black" da lista

private static List<Pug> filterPugByColor( List<Pug> pugs, String color ) { List<Pug> coloured = new ArrayList<>(); for ( Pug pug : pugs ) { if ( pug.getColor().equals( color ) ) { coloured.add( pug ); } } return coloured; }

List<Pug> black = filterPugByColor( pugs, "black" ); black.forEach( System.out::println );

Pug{nome='Jesse', color='black', weight=9}

slide-15
SLIDE 15

Novo Requisito: :) Filtrar todos os pugs com sobrepeso (>10 kg)

slide-16
SLIDE 16

Filtrar todos os pugs com sobrepeso (>10 kg)

private static List<Pug> filterPugBySize( List<Pug> pugs, int size ) { List<Pug> fat = new ArrayList<>(); for ( Pug pug : pugs ) { if ( pug.getWeight() > size ) { fat.add( pug ); } } return fat; }

List<Pug> fat = filterPugBySize( pugs, 10 ); fat.forEach( System.out::println ); Pug{nome='Bento', color='abricot', weight=13}

slide-17
SLIDE 17

private static List<Pug> filterPugs( List<Pug> pugs, String color, int weight, boolean flag ) { List<Pug> result = new ArrayList<>(); for ( Pug pug : pugs ) { if ( ( flag && pug.getColor().equals( color ) ) || ( !flag && pug.getWeight() > weight ) ) { result.add( pug ); } } return result; }

Refatorador :D

slide-18
SLIDE 18

List<Pug> result = filterPugs(pugs, "black", 0, true); List<Pug> result1 = filterPugs(pugs, "", 10, false);

slide-19
SLIDE 19

Behavior Parametrization

slide-20
SLIDE 20

Behavior Parametrization

public interface PugPredicate { boolean test(Pug pug); } class BlackPugPredicate implements PugPredicate{ @Override public boolean test( Pug pug ) { return pug.getColor().equals( "black" ); } } class FatPugPredicate implements PugPredicate{ @Override public boolean test( Pug pug ) { return pug.getWeight()>10; } }

slide-21
SLIDE 21

Predicate

List<Pug> black = filterPug( pugs, new BlackPugPredicate() ); List<Pug> fat = filterPug( pugs, new FatPugPredicate() ); fat.forEach( System.out::println ); Pug{nome='Bento', color='abricot', weight=13}

slide-22
SLIDE 22

Problemas?

slide-23
SLIDE 23

Classes anônimas <3

slide-24
SLIDE 24

List<Pug> abricotsNotFat = filterPug( pugs, new PugPredicate() { @Override public boolean test( Pug pug ) { return pug.getColor().equals( "abricot" ) && pug.getWeight() <= 10; } } ); abricotsNotFat.forEach( System.out::println );

Pug{nome='Dora', color='abricot', weight=10}

slide-25
SLIDE 25

Expressões Lambda <3

slide-26
SLIDE 26

(Pug p1,Pug p2) -> p1.getWeight().compareTo(p2.getWeight())

Parâmetros do Lambda

"Arrow" Corpo do Lambda

slide-27
SLIDE 27

class BlackPugPredicate implements PugPredicate{ @Override public boolean test( Pug pug ) { return "black".equals( pug.getColor() ) ); } } blacks = filterPug( pugs, new BlackPugPredicate() ); blacks = filterPug( pugs, (Pug pug) ->"black".equals( pug.getColor() ) );

slide-28
SLIDE 28

Posso modificar mais um pouco?

slide-29
SLIDE 29

public interface Predicate<T>{ boolean test(T t); } public static <T> List<T> filter (List<T> list, Predicate<T> p){ List<T> result = new ArrayList<>();
 for(T e: list){ if(p.test(e)){ result.add(e); } } return result; }

slide-30
SLIDE 30

List<Pug> blacks = filter( pugs, (Pug pug) ->"black".equals( pug.getColor() ) ); List<String> pares = filter(numbers, (Integer i) -> i % 2 == 0);

Predicate<Pug> fatPredicate = d -> d.getWeight() > 9; Predicate<Pug> abricotPredicate1 = d -> d.getColor().equalsIgnoreCase( "abricot" ); Predicate<Pug> abricotAndFat = abricotPredicate.and( fatPredicate );

slide-31
SLIDE 31 @FunctionalInterface public interface Predicate<T>{ boolean test(T t); } public static <T> List<T> filter(List<T> list, Predicate<T> p) { List<T> results = new ArrayList<>(); for(T s: list){ if(p.test(s)){ results.add(s); } } return results; } Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty(); List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

Predicate

slide-32
SLIDE 32

@FunctionalInterface public interface Function<T, R>{ R apply(T t); } public static <T, R> List<R> map(List<T> list, Function<T, R> f) { List<R> result = new ArrayList<>(); for(T s: list){ result.add(f.apply(s)); } return result; } List<Integer> l = map( Arrays.asList("qcon","em","sampa"), (String s) -> s.length() ); // [4, 2, 5]

Function

slide-33
SLIDE 33
  • Etc. etc. etc.
BiConsumer BiFunction BinaryOperator BiPredicate BooleanSupplier Consumer DoubleBinaryOperator DoubleConsumer DoubleFunction DoublePredicate DoubleSupplier DoubleToIntFunction DoubleToLongFunction DoubleUnaryOperator Function IntBinaryOperator IntConsumer IntFunction IntPredicate IntSupplier IntToDoubleFunction IntToLongFunction IntUnaryOperator LongBinaryOperator LongConsumer LongFunction LongPredicate LongSupplier LongToDoubleFunction LongToIntFunction LongUnaryOperator ObjDoubleConsumer ObjIntConsumer ObjLongConsumer Predicate Supplier ToDoubleBiFunction ToDoubleFunction ToIntBiFunction ToIntFunction ToLongBiFunction ToLongFunction UnaryOperator
slide-34
SLIDE 34

(Pug p1,Pug p2) -> "black".equals( pug.getColor() )

Parâmetros do Lambda

"Arrow" Corpo do Lambda

slide-35
SLIDE 35

Código funcional em Java: Superando o hype

Eder Ignatowicz

slide-36
SLIDE 36

Streams API

slide-37
SLIDE 37

Streams:

Manipula coleções de forma declarativa

Quais são os nomes dos Pugs com peso maior do que 9 quilos?

slide-38
SLIDE 38

Streams:

Manipula coleções de forma declarativa

SELECT nome FROM pugs WHERE weight < 9 order by peso.

slide-39
SLIDE 39

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

slide-40
SLIDE 40
slide-41
SLIDE 41

Java 8

Streams API

slide-42
SLIDE 42

Em Java

List<String> gordinhosNome = pugs.stream() .filter( d -> d.getWeight() > 9 ) .sorted( comparing( Pug::getWeight ) ) .map( Pug::getNome ) .collect( toList() );

Seleciona > 9 kg Ordena por peso Extrai o nome Armazena em uma lista

slide-43
SLIDE 43

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

slide-44
SLIDE 44

Em Java

List<String> gordinhosNome = pugs.parallelStream() .filter( d -> d.getWeight() > 9 ) .sorted( comparing( Pug::getWeight ) ) .map( Pug::getNome ) .collect( toList() );

Seleciona > 9 kg Ordena por peso Extrai o nome Armazena em uma lista

slide-45
SLIDE 45

(

slide-46
SLIDE 46

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

slide-47
SLIDE 47

)

slide-48
SLIDE 48

Stream Pipelines

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

slide-49
SLIDE 49

Código: Declarativo Componentizável Paralelizável

Streams API

slide-50
SLIDE 50

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

Streams

slide-51
SLIDE 51

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

Streams

slide-52
SLIDE 52

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

Streams

slide-53
SLIDE 53

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

Streams

slide-54
SLIDE 54

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-55
SLIDE 55

Vamos a prática

slide-56
SLIDE 56

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-57
SLIDE 57

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, 2014, 100 ), new Venda( eder, 2013, 200 ), new Venda( pedro, 2014, 300 ), new Venda( luciano, 2012, 500 ), new Venda( luciano, 2012, 400 ), new Venda( junior, 2012, 500 ));

slide-58
SLIDE 58

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

slide-59
SLIDE 59

List<Venda> vendas2014 = transactions .stream()

slide-60
SLIDE 60

List<Venda> vendas2014 = transactions .stream() .filter( venda -> venda.getAno() == 2014 )

slide-61
SLIDE 61

List<Venda> vendas2014 = transactions .stream() .filter( venda -> venda.getAno() == 2014 ) .sorted( comparing( Venda::getValor ) )

slide-62
SLIDE 62

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

slide-63
SLIDE 63

List<Venda> vendas2014 = transactions .stream() .filter( venda -> venda.getAno() == 2014 ) .sorted( comparing( Venda::getValor ) ) .collect( toList() ); vendas2014.forEach(System.out::println);

Venda{vendedor=Vendedor{nome='Eder', cidade='Campinas'}, ano=2014, valor=100} Venda{vendedor=Vendedor{nome='Pedro', cidade='Apucarana'}, ano=2014, valor=300}

slide-64
SLIDE 64

Em que cidades temos vendedores?

slide-65
SLIDE 65

List<String> cidadesAtendidas = vendas.stream() .map( venda -> venda.getVendedor().getCidade() ) .distinct() .collect( toList() );

Campinas Apucarana Piracicaba Londrina

slide-66
SLIDE 66

Qual foi a maior venda?

slide-67
SLIDE 67

Optional<Integer> maiorVenda = vendas.stream() .map(Venda::getValor) .reduce( Integer::max ); maiorVenda.ifPresent( i -> System.out.println(i));

500

slide-68
SLIDE 68

Total de vendas?

slide-69
SLIDE 69

Optional<Integer> totalVendas = vendas.stream() .map(Venda::getValor) .reduce( Integer::sum ); totalVendas.ifPresent( i -> System.out.println(i));

2000

slide-70
SLIDE 70

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

slide-71
SLIDE 71

Map<Vendedor, List<Venda>> vendedorPorVendas = vendas.stream() .sorted( comparing( Venda::getValor ) ) .collect( groupingBy( Venda::getVendedor ) ); System.out.println(vendedorPorVendas);

{Vendedor{nome='Junior', cidade='Londrina'}=[Venda{vendedor=Vendedor{nome='Junior', cidade='Londrina'}, ano=2012, valor=500}], Vendedor{nome='Pedro', cidade='Apucarana'}=[Venda{vendedor=Vendedor{nome='Pedro', cidade='Apucarana'}, ano=2014, valor=300}], Vendedor{nome='Luciano', cidade='Piracicaba'} =[Venda{vendedor=Vendedor{nome='Luciano', cidade='Piracicaba'}, ano=2012, valor=400}, Venda{vendedor=Vendedor{nome='Luciano', cidade='Piracicaba'}, ano=2012, valor=500}], Vendedor{nome='Eder', cidade='Campinas'}=[Venda{vendedor=Vendedor{nome='Eder', cidade='Campinas'}, ano=2014, valor=100}, Venda{vendedor=Vendedor{nome='Eder', cidade='Campinas'}, ano=2013, valor=200}]}
slide-72
SLIDE 72
slide-73
SLIDE 73
slide-74
SLIDE 74
slide-75
SLIDE 75

Streams são lazy

slide-76
SLIDE 76

Stream Pipelines

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

slide-77
SLIDE 77

Stream Pipelines

intermediate pugs -> —> —> findFirst lambda lambda intermediate

slide-78
SLIDE 78

Lazy Streams

List<Dog> dogs = Arrays.asList( new Dog( "Dora", true, 10, Dog.RACA.PUG ), new Dog( "Bento", true, 13, Dog.RACA.PUG ), new Dog( "Rex", false, 8, Dog.RACA.SRD ), new Dog( "Teté", false, 6, Dog.RACA.SRD ), new Dog( "Banzé", true, 7, Dog.RACA.SRD ), new Dog( "Rin-Tin-Tin", false, 15, Dog.RACA.PASTOR ) );

slide-79
SLIDE 79

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

slide-80
SLIDE 80

String nomePrimeiroSRDMaiorDoQue5Kg = dogs.stream() .filter( dog -> { System.out.println( "filter - " + dog.getNome() ); return dog.getRaca().equals( Dog.RACA.SRD) && dog.getPeso() > 5; }) .map( dog -> { System.out.println( "map - " + dog.getNome() ); return dog.getNome(); }) .findFirst() .get();

slide-81
SLIDE 81

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-82
SLIDE 82

Lazy Stream

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

slide-83
SLIDE 83

String nomePrimeiroSRDMaiorDoQue5Kg = dogs.stream() .filter( dog -> { System.out.println( "filter - " + dog.getNome() ); return dog.getRaca().equals( Dog.RACA.SRD) && dog.getPeso() > 5; }) .map( dog -> { System.out.println( "map - " + dog.getNome() ); return dog.getNome(); }) .findFirst() .get();

filter - Dora filter - Bento filter - Rex map - Rex Rex

List<Dog> dogs = Arrays.asList( new Dog( "Dora", true, 10, Dog.RACA.PUG ), new Dog( "Bento", true, 13, Dog.RACA.PUG ), new Dog( "Rex", false, 8, Dog.RACA.SRD ), new Dog( "Teté", false, 6, Dog.RACA.SRD ), new Dog( "Banzé", true, 7, Dog.RACA.SRD ), new Dog( "Rin-Tin-Tin", false, 15, Dog.RACA.PASTOR ) );
slide-84
SLIDE 84

Streams "infinitos"

slide-85
SLIDE 85

Criar uma lista de números primos infinita

slide-86
SLIDE 86 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-87
SLIDE 87

Coleções "infinitas"

slide-88
SLIDE 88

public static List<Integer> primes(final int fromNumber, final int count) { return Stream.iterate(primeAfter(fromNumber - 1), Primes::primeAfter) .limit(count) .collect(Collectors.<Integer>toList()); }

slide-89
SLIDE 89

public static List<Integer> primes(final int fromNumber, final int count) { return Stream.iterate(primeAfter(fromNumber - 1), Primes::primeAfter) .limit(count) .collect(Collectors.<Integer>toList()); }

System.out.println("10 primos do 1: " + primes( 1, 10 )); System.out.println("10 primos do 1000: " + primes( 1000, 10 )); 10 primos do 1: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] 10 primos do 1000: [1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061]

slide-90
SLIDE 90

Recursões

slide-91
SLIDE 91

Fibonacci

slide-92
SLIDE 92

public static Long fib( int n ) { if ( n < 2 ) { return new Long( n ); } else { return fib( n - 1 ) + fib( n - 2 ); } }

slide-93
SLIDE 93
slide-94
SLIDE 94
slide-95
SLIDE 95

Memoization

slide-96
SLIDE 96

Pure Functions

In computer programming, a function may be described as a pure function if both these statements about the function hold: 1-) The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change as program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices (usually—see below. 2-) Evaluation of the result does not cause any semantically

  • bservable side effect or output, such as mutation of mutable
  • bjects or output to I/O devices (usually—see below)
slide-97
SLIDE 97

Manual

slide-98
SLIDE 98

Integer doubleValue(Integer x) { return x * 2; } Integer doubleValue(Integer x) { if (cache.containsKey(x)) { return cache.get(x); } else { Integer result = x * 2; cache.put(x, result) ; return result; } }

slide-99
SLIDE 99

private Map<Integer, Integer> cache = new ConcurrentHashMap<>();

public Integer fib(int n) { if (n == 0 || n == 1) return n; Integer result = cache.get( n ); if (result == null) { synchronized (cache) { result = cache.get(n); if (result == null) { result = fib(n - 2) + fib(n - 1); cache.put(n, result); } } } return result; }

slide-100
SLIDE 100

Java 8 to the rescue

slide-101
SLIDE 101

public class Fibonacci { private Map<Integer, Integer> cache = new ConcurrentHashMap<>(); public Long fib(int n) { if (n == 0 || n == 1) return n; return cache.computeIfAbsent(n, (k) -> fib(k - 2) + fib(k - 1)); } }

slide-102
SLIDE 102

DEMO

slide-103
SLIDE 103

Automática

slide-104
SLIDE 104

Function<Integer, Integer> f = x -> x * 2; Function<Integer, Integer> g = Memoizer.memoize(f);

slide-105
SLIDE 105

public class Memoizer { public static <T, R> Function<T, R> memoize( Function<T, R> fn ) { Map<T, R> map = new ConcurrentHashMap<T, R>(); return ( t ) -> map.computeIfAbsent( t, fn ); } }

slide-106
SLIDE 106

static Integer longCalculation(Integer x) { try { Thread.sleep(1_000); } catch (InterruptedException ignored) { } return x * 2; } static Function<Integer, Integer> loooongCalc = Memoizer::longCalculation; static Function<Integer, Integer> loooongCalcMemo =

Memoizer.memoize(loooongCalc);

loooongCalcMemo.apply( 30 ); 1005ms loooongCalcMemo.apply( 30 ); 0 ms

slide-107
SLIDE 107

static Function<Integer, Long> fibonacci = Fibonacci::calc; static Function<Integer, Long> memoFib =

Memoizer.memoize( fibonacci );

memoFib.apply( 30 ); 832040 56ms memoFib.apply( 30 ); 832040 0 ms

slide-108
SLIDE 108

E agora?

slide-109
SLIDE 109

Programar funcional em Java é uma mudança de paradigma

slide-110
SLIDE 110

Java é multi-paradigma Imperativo, OO e Funcional

slide-111
SLIDE 111

Escolha o melhor deles para o seu problema

slide-112
SLIDE 112

Java 8, Lambdas e Streams trouxeram uma nova vida para o Java

slide-113
SLIDE 113

DIVIRTA-SE!

slide-114
SLIDE 114

Obrigado!!! @ederign