Slide 1

Slide 1 text

Código funcional em Java: Superando o hype Eder Ignatowicz Sr. Software Engineer JBoss by Red Hat

Slide 2

Slide 2 text

Lambda Expressions 101

Slide 3

Slide 3 text

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 4

Slide 4 text

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

Slide 5

Slide 5 text

Filtrar todos os pugs de cor “abricot" da lista private static List filterAbricotPugs( List pugs ) { List abricots = new ArrayList<>(); for ( Pug pug : pugs ) { if ( pug.getColor().equals( "abricot" ) ) { abricots.add( pug ); } } return abricots; } List pugs = Arrays.asList( dora, bento, jesse ); List abricot = filterAbricotPugs( pugs ); Pug{nome='Dora', color='abricot', weight=10} Pug{nome='Bento', color='abricot', weight=13}

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

Filtrar todos os pugs de cor “black" da lista private static List filterPugByColor( List pugs, String color ) { List coloured = new ArrayList<>(); for ( Pug pug : pugs ) { if ( pug.getColor().equals( color ) ) { coloured.add( pug ); } } return coloured; } List black = filterPugByColor( pugs, "black" ); black.forEach( System.out::println ); Pug{nome='Jesse', color='black', weight=9}

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Filtrar todos os pugs com sobrepeso (>10 kg) private static List filterPugBySize( List pugs, int size ) { List fat = new ArrayList<>(); for ( Pug pug : pugs ) { if ( pug.getWeight() > size ) { fat.add( pug ); } } return fat; } List fat = filterPugBySize( pugs, 10 ); fat.forEach( System.out::println ); Pug{nome='Bento', color='abricot', weight=13}

Slide 11

Slide 11 text

private static List filterPugs( List pugs, String color, int weight, boolean flag ) { List 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 12

Slide 12 text

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

Slide 13

Slide 13 text

Behavior Parametrization

Slide 14

Slide 14 text

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 15

Slide 15 text

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

Slide 16

Slide 16 text

Classes anônimas <3

Slide 17

Slide 17 text

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

Slide 18 text

Expressões Lambda <3

Slide 19

Slide 19 text

(Pug p1,Pug p2) -> p1.getWeight().compareTo(p2.getWeight()) Parâmetros do Lambda "Arrow" Corpo do Lambda

Slide 20

Slide 20 text

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 21

Slide 21 text

Posso modificar mais um pouco?

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

List blacks = filter( pugs, (Pug pug) ->"black".equals( pug.getColor() ) ); List pares = filter(numbers, i -> i % 2 == 0); Predicate fatPredicate = d -> d.getWeight() > 9; Predicate abricotPredicate1 = d -> d.getColor().equalsIgnoreCase( "abricot" ); Predicate abricotAndFat = abricotPredicate.and( fatPredicate );

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

Consumer

Slide 26

Slide 26 text

public class ShoppingCartTest { ShoppingCart cart; @Before public void setup() { Item item1 = new Item( 10 ); Item item2 = new Item( 20 ); cart = new ShoppingCart( Arrays.asList( item1, item2 ) ); } @Test public void totalTest() { cart.pay( ShoppingCart.PaymentMethod.CREDIT ) ); } }

Slide 27

Slide 27 text

public class ShoppingCart { private List items; public ShoppingCart( List items ) { this.items = items; } public void pay( PaymentMethod method ) { int total = cartTotal(); if ( method == PaymentMethod.CREDIT ) { System.out.println( “Pay with credit “ + total ); } else if ( method == PaymentMethod.MONEY ) { System.out.println( “Pay with money “ + total ); } } private int cartTotal() { return items .stream() .mapToInt( Item::getValue ) .sum(); } … }

Slide 28

Slide 28 text

public interface Payment { public void pay(int amount); } public class CreditCard implements Payment { @Override public void pay( int amount ) { System.out.println( "Pay with Credit: “+ amount); } } public class Money implements Payment { @Override public void pay( int amount ) { System.out.println( "Pay with Money: “+ amount); }

Slide 29

Slide 29 text

public class ShoppingCart { … public void pay( Payment method ) { int total = cartTotal(); method.pay( total ); } private int cartTotal() { return items .stream() .mapToInt( Item::getValue ) .sum(); } }

Slide 30

Slide 30 text

Strategy “Definir uma família de algoritmos, encapsular cada uma delas e torná-las intercambiáveis. Strategy permite que o algoritmo varie independentemente dos clientes que o utilizam” GAMMA, Erich et al.

Slide 31

Slide 31 text

public interface Payment { public void pay(int amount); } public class CreditCard implements Payment { @Override public void pay( int amount ) { System.out.println( "make credit payment logic" ); } } public class Money implements Payment { @Override public void pay( int amount ) { System.out.println( "make money payment logic" ); } } public class DebitCard implements Payment { @Override public void pay( int amount ) { System.out.println( "make debit } } public void totalTest() { assertEquals( 30, cart.pay( new CreditCard() ) ); assertEquals( 30, cart.pay( new Money() ) ); assertEquals( 30, cart.pay( new DebitCard() ) ); } }

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

public class ShoppingCart { … public void pay( Consumer method ) { int total = cartTotal(); method.accept( total ); } … } public void pay( Payment method ) { int total = cartTotal(); method.pay( total ); }

Slide 34

Slide 34 text

public class ShoppingCart { … public void pay( Consumer method ) { int total = cartTotal(); method.accept( total ); } … } public void totalTest() { cart.pay( amount -> System.out.println( "Pay with Credit: " + amount ) ); cart.pay( amount -> System.out.println( "Pay with Money: " + amount ) ); cart.pay( amount -> System.out.println( "Pay with Debit: " + amount ) ); }

Slide 35

Slide 35 text

public class PaymentTypes { public static void money( int amount ) { System.out.println( "Pay with Money: " + amount ); } public static void debit( int amount ) { System.out.println( "Pay with Debit: " + amount ); } public static void credit( int amount ) { System.out.println( "Pay with Credit: " + amount ); } } public void totalTest() { cart.pay( PaymentTypes::credit ); cart.pay( PaymentTypes::debit ); cart.pay( PaymentTypes::money ); }

Slide 36

Slide 36 text

public class ShoppingCart { … public void pay( Consumer method ) { int total = cartTotal(); method.accept( total ); } … } Strategy

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

Functions

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

List pugs = Arrays.asList( dora, bento, jesse ); Function extractName = pug -> pug.getName(); List nomes = pugs.stream() .map( extractName ) .collect( Collectors.toList() ); print( nomes ); Dora Bento Jesse

Slide 41

Slide 41 text

List pugs = Arrays.asList( dora, bento, jesse ); Function extractName = pug -> pug.getName(); List nomes = pugs.stream() .map( extractName ) .collect( Collectors.toList() ); print( nomes ); UnaryOperator upper = s -> s.toUpperCase();

Slide 42

Slide 42 text

List pugs = Arrays.asList( dora, bento, jesse ); Function extractName = pug -> pug.getName(); List nomes = pugs.stream() .map( extractName ) .collect( Collectors.toList() ); print( nomes ); UnaryOperator upper = s -> s.toUpperCase(); List nomesUpper = pugs.stream() .map( extractName.andThen( upper ) ) .collect( Collectors.toList() ); print( nomesUpper );

Slide 43

Slide 43 text

public class Item { private int price; public Item( int price ) { this.price = price; } public int getPrice() { return price; } } Extras Envio Impostos Embalagem

Slide 44

Slide 44 text

public interface Item { int getPrice(); } public class Book implements Item { private int price; public Book( int price ) { this.price = price; } @Override public int getPrice() { return price; } }

Slide 45

Slide 45 text

public abstract class ItemExtras implements Item { private Item item; public ItemExtras( Item item ) { this.item = item; } @Override public int getPrice() { return item.getPrice(); } }

Slide 46

Slide 46 text

public class InternationalDelivery extends ItemExtras { public InternationalDelivery( Item item ) { super( item ); } @Override public int getPrice() { return 5 + super.getPrice(); } }

Slide 47

Slide 47 text

public class GiftPacking extends ItemExtras { public GiftPacking( Item item ) { super( item ); } @Override public int getPrice() { return 15 + super.getPrice(); } }

Slide 48

Slide 48 text

public static void main( String[] args ) { Item book = new Book( 10 ); book.getPrice(); //10 Item international = new InternationalDelivery( book ); international.getPrice(); //15 }

Slide 49

Slide 49 text

public static void main( String[] args ) { Item book = new Book( 10 ); book.getPrice(); //10 Item internationalGift = new GiftPacking( new InternationalDelivery( book ) ); internationalGift.getPrice(); //30 }

Slide 50

Slide 50 text

public static void main( String[] args ) { Item book = new Book( 10 ); book.getPrice(); //10 Item internationalGiftWithTaxes = new InternacionalTaxes( new GiftPacking( new InternationalDelivery( book ); internationalGiftWithTaxes.getPrice(); //80 } }

Slide 51

Slide 51 text

Decorator “Dinamicamente, agregar responsabilidades adicionais a objetos. Os Decorators fornecem uma alternativa flexível ao uso de subclasses para extensão de funcionalidades.” GAMMA, Erich et al.

Slide 52

Slide 52 text

new BufferedReader(new FileReader(new File("some.file")));

Slide 53

Slide 53 text

public static void main( String[] args ) { Item book = new Item( 10 ); book.getPrice(); //10 Function giftPacking = value -> value + 15; giftPacking.apply( book.getPrice() ); //25 }

Slide 54

Slide 54 text

public static void main( String[] args ) { Item book = new Item( 10 ); book.getPrice(); //10 Function giftPacking = value -> value + 15; giftPacking.apply( book.getPrice() ); //25 Function intTaxes = value -> value + 50; intTaxes.apply( book.getPrice() ); //60 }

Slide 55

Slide 55 text

public static void main( String[] args ) { Item book = new Item( 10 ); book.getPrice(); //10 Function giftPacking = value -> value + 15; giftPacking.apply( book.getPrice() ); //25 Function intTaxes = value -> value + 50; intTaxes.apply( book.getPrice() ); //60 giftPacking.andThen( intTaxes ).apply( book.getPrice() ); //75 }

Slide 56

Slide 56 text

public class Item { private int price; private Function[] itemExtras = new Function[]{}; public Item( int price ) { this.price = price; } public Item( int price, Function... itemExtras) { this.price = price; this.itemExtras = itemExtras; } public int getPrice() { int priceWithExtras = price; for ( Function itemExtra : itemExtras ) { priceWithExtras = itemExtra.apply( priceWithExtras ); } return priceWithExtras; } public void setItemExtras( Function... itemExtras ) { this.itemExtras = itemExtras; } }

Slide 57

Slide 57 text

public static void main( String[] args ) { Item book = new Item( 10 ); Function giftPacking = value -> value + 15; Function intTaxes = value -> value + 50; book.setItemExtras( giftPacking, intTaxes ); book.getPrice(); //75 }

Slide 58

Slide 58 text

public static void main( String[] args ) { Item book = new Item( 10 ); Function giftPacking = value -> value + 15; Function intTaxes = value -> value + 50; book.setItemExtras( giftPacking, intTaxes ); book.getPrice(); //75 }

Slide 59

Slide 59 text

public class Packing { public static Integer giftPacking( Integer value ) { return value + 15; } //other packing options here } public class Taxes { public static Integer internacional( Integer value ) { return value + 50; } //other taxes here }

Slide 60

Slide 60 text

public static void main( String[] args ) { Item book = new Item( 10, Packing::giftPacking, Taxes::internacional ); book.getPrice(); //75 }

Slide 61

Slide 61 text

public class Item { private int price; private Function[] itemExtras = new Function[]{}; public Item( int price ) { this.price = price; } public Item( int price, Function... itemExtras) { this.price = price; this.itemExtras = itemExtras; } public int getPrice() { int priceWithExtras = price; for ( Function itemExtra : itemExtras ) { priceWithExtras = itemExtra.apply( priceWithExtras ); } return priceWithExtras; } public void setItemExtras( Function... itemExtras ) { this.itemExtras = itemExtras; } }

Slide 62

Slide 62 text

public class Item { private int price; private Function[] itemExtras = new Function[]{}; public Item( int price ) { this.price = price; } public Item( int price, Function... itemExtras ) { this.price = price; this.itemExtras = itemExtras; } public int getPrice() { Function extras = Stream.of( itemExtras ) .reduce( Function.identity(), Function::andThen ); return extras.apply( price ); } public void setItemExtras( Function... itemExtras ) { this.itemExtras = itemExtras; } }

Slide 63

Slide 63 text

Streams API

Slide 64

Slide 64 text

List fatName = pugs.stream() .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 65

Slide 65 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 66

Slide 66 text

(

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

)

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

Streams são lazy

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

Stream Pipelines intermediate dogs -> —> —> terminal lambda lambda intermediate

Slide 74

Slide 74 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 75

Slide 75 text

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

Slide 76

Slide 76 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 77

Slide 77 text

Eager Streams Dora Bento Rex Teté Banzé Rufus —> SRD e peso> 5 filter map Rex Teté Banzé —> Nome "Rex" “Teté" “Banzé" —> —> Nome findFirst “Rex" —> —>

Slide 78

Slide 78 text

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

Slide 79

Slide 79 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 Re

Slide 80

Slide 80 text

Recursões

Slide 81

Slide 81 text

Fibonacci

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

Memoization

Slide 86

Slide 86 text

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 observable side effect or output, such as mutation of mutable objects or output to I/O devices (usually—see below)

Slide 87

Slide 87 text

Manual

Slide 88

Slide 88 text

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 89

Slide 89 text

private Map 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 90

Slide 90 text

Java + FP to the rescue

Slide 91

Slide 91 text

private static Map memo = new HashMap<>(); static { memo.put( 0, 0L ); //fibonacci(0) memo.put( 1, 1L ); //fibonacci(1) } public static long fibonacci( int x ) { return memo. computeIfAbsent( x, n -> fibonacci( n - 1 ) + fibonacci( n - 2 ) ); }

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

Currying

Slide 94

Slide 94 text

f(x,y) = y/x

Slide 95

Slide 95 text

f(2,3) f(x,y) = y/x

Slide 96

Slide 96 text

f(2, y) = y / 2 g(y) = f(2,y) = y/2

Slide 97

Slide 97 text

g(y) = f(2,y) = y/2 g(3) = f(2,3) = 3/2

Slide 98

Slide 98 text

CtoF(x) = x * 9/5 + 32

Slide 99

Slide 99 text

static double converter( double x, double f, double b ) { return x * f + b; } public static void main( String[] args ) { Double celsius = 15.0; Double fahrenheit = converter( celsius, 9.0 / 5, 32 ); //59 F }

Slide 100

Slide 100 text

static double converter( double x, double f, double b ) { return x * f + b; } static DoubleUnaryOperator curriedConverter( double f, double b ) { return x -> x * f + b; }

Slide 101

Slide 101 text

static DoubleUnaryOperator curriedConverter( double f, double b ) { return x -> x * f + b; } public static void main( String[] args ) { DoubleUnaryOperator convertCtoF = curriedConverter( 9.0 / 5, 32 ); convertCtoF.applyAsDouble( 35 ); //95 F convertCtoF.applyAsDouble( 15 ); //59 F }

Slide 102

Slide 102 text

static DoubleUnaryOperator curriedConverter( double f, double b ) { return x -> x * f + b; } public static void main( String[] args ) { DoubleUnaryOperator convertCtoF = curriedConverter( 9.0 / 5, 32 ); convertCtoF.applyAsDouble( 35 ); //95 F DoubleUnaryOperator convertKmToMi = curriedConverter( 0.6214, 0 ); convertKmToMi.applyAsDouble( 804.672 ); //500milhas }

Slide 103

Slide 103 text

DoubleUnaryOperator convertBRLtoUSD = curriedConverter( 0.27, 0 ); double usd = convertBRLtoUSD.applyAsDouble( 100 );//27 USD DoubleUnaryOperator convertUSDtoEUR = curriedConverter( 0.89, 0 ); convertUSDtoEUR.applyAsDouble( usd ); //24.03 EUR convertBRLtoUSD.andThen( convertUSDtoEUR ).applyAsDouble( 100 ); //24.03 EUR

Slide 104

Slide 104 text

E agora?

Slide 105

Slide 105 text

Programar funcional em Java é uma mudança de paradigma

Slide 106

Slide 106 text

Java é multi-paradigma Imperativo, OO e Funcional

Slide 107

Slide 107 text

Escolha o melhor deles para o seu problema

Slide 108

Slide 108 text

Programação Funcional trouxe uma nova vida para o Java

Slide 109

Slide 109 text

DIVIRTA-SE!

Slide 110

Slide 110 text

Obrigado!!! @ederign