Programação funcional com java 8

90
Programação Funcional com Java 8 #TheDevConf 2015 POA

Transcript of Programação funcional com java 8

Page 1: Programação funcional com java 8

Programação Funcional com Java 8

#TheDevConf 2015 POA

Page 4: Programação funcional com java 8

“The functional style is not counter to object-oriented programming (OOP). The real

paradigm shift is from the imperative to the declarative style of programming. With

Java 8, we can now intermix functional and OO styles of programming quite effectively. We can continue to use the OOP

style to model domain entities, their states, and their relationships. In addition, we can model the behavior

or state transformations, business workflows, and data processing as a series of functions to form a

function composition.”

Page 5: Programação funcional com java 8

O que realmente muda no nosso dia-a-dia usando programação

funcional com Java 8?

Page 6: Programação funcional com java 8

Ordenando e exibindo uma listafor (Jogador jogador : listaJogadores) {

if (Posicao.ATACANTE.equals(jogador.getPosicao())) {listaAtacantes.add(jogador);

}}Collections.sort(listaAtacantes, new Comparator<Atletas>() {

@Overridepublic int compare(Jogador j1, Jogador j2) {

return j1.getNome().compareTo(j2.getNome());}

});for (Jogador jogador : listaAtacantes) {

System.out.println(jogador);} 6

Page 7: Programação funcional com java 8

Ordenando e exibindo uma lista

listaJogadores.removeIf(jogador -> !Posicao.ATACANTE.equals(jogador.getPosicao()));

listaJogadores.sort((a1, a2) -> a1.getNome().compareTo(a2.getNome()));

listaJogadores.forEach(System.out::println);

7

Page 8: Programação funcional com java 8

// Java 8listaJogadores.sort((j1, j2) -> j1.getNome().compareTo(j2.getNome()));

Collections.sort(listaAtacantes, new Comparator<Jogador>() {@Overridepublic int compare(Jogador j1, Jogador j2) {

return j1.getNome().compareTo(j2.getNome());}

});

8

Page 9: Programação funcional com java 8

// Java 8listaJogadores.sort((j1, j2) -> j1.getNome().compareTo(j2.getNome()));

Collections.sort(listaAtacantes, new Comparator<Jogador>() {@Overridepublic int compare(Jogador j1, Jogador j2) {

return j1.getNome().compareTo(j2.getNome());}

});

9

Page 10: Programação funcional com java 8

// Java 8listaJogadores.sort((j1, j2) -> j1.getNome().compareTo(j2.getNome()));

Collections.sort(listaAtacantes, new Comparator<Jogador>() {@Overridepublic int compare(Jogador j1, Jogador j2) {

return j1.getNome().compareTo(j2.getNome());}

});

10

Page 11: Programação funcional com java 8

// Java 8listaJogadores.removeIf(jogador -> !Posicao.ATACANTE.equals(jogador.getPosicao()));

for (Jogador jogador : listaJogadores) {if (Posicao.ATACANTE.equals(jogador.getPosicao())) {

listaAtacantes.add(jogador);}

}

11

Page 12: Programação funcional com java 8

// Java 8listaJogadores.forEach(System.out::println);

for (Jogador jogador : listaAtacantes) {System.out.println(jogador);

}

12

Page 13: Programação funcional com java 8

listaJogadores.stream().filter(jogador -> Posicao.ATACANTE.equals(jogador.getPosicao())).sorted(Comparator.comparing(Jogador::getNome)).forEach(System.out::println);

13

Page 14: Programação funcional com java 8

listaJogadores.parallelStream().filter(jogador -> Posicao.ATACANTE.equals(jogador.getPosicao())).sorted(Comparator.comparing(Jogador::getNome)).forEach(System.out::println);

14

Page 15: Programação funcional com java 8

15

+ legibilidade de código+ foco no negócio+ código mais expressivo+ facilidade de paralelizar o código- probabilidade de erro- código imperativo- mutabilidade

Page 16: Programação funcional com java 8

O que vamos ver então?Lambda

Functional interfacesMethod reference

Default methodsCollections APIStreams

16

Page 17: Programação funcional com java 8

● Anonima○ não possui nome

● Função○ não é vinculada a classe

● Concisa○ não possui código boilerplate

● Pode ser repassada○ como argumento ou variável

Lambda Expression

17

Page 18: Programação funcional com java 8

Anonymous class:Collections.sort(listaAtacantes, new Comparator<Jogador>() {

@Overridepublic int compare(Jogador j1, Jogador j2) {

return j1.getNome().compareTo(j2.getNome());}

});

Lambda:listaJogadores.sort((j1, j2) -> j1.getNome().compareTo(j2.getNome()));

Lambda Expression

18

Page 19: Programação funcional com java 8

Lambda Expression

( parametros ) -> { corpo da expressão lambda }

19

Page 20: Programação funcional com java 8

Lambda Expression

( parametros ) -> { corpo da expressão lambda }

20

Page 21: Programação funcional com java 8

Lambda Expression

() -> System.out.println("Lambda em uma linha")

21

Page 22: Programação funcional com java 8

Lambda Expression

x -> x + 10

22

Page 23: Programação funcional com java 8

Lambda Expression

(String a, String b) -> {if ( a.length() > b.length() )

return a;return b;

};

23

Page 24: Programação funcional com java 8

Comparator<Jogador> c1 = (Jogador j1, Jogador j2) ->a1.getNome().compareTo(a2.getNome());

Predicate<Jogador> pre = (Jogador j1) -> a1.getNome().startsWith("N");

Object o = (Jogador a1, Jogador a2) ->a1.getNome().compareTo(a2.getNome());

Atribuindo Lambda para variável

//The target type of this expression must be a functional interface

24

Page 25: Programação funcional com java 8

● Interface com 1 único método abstrato○ Default Methods

● @FunctionalInterface

Functional Interfaces

25

Page 26: Programação funcional com java 8

package java.util.function;import java.util.Objects;

@FunctionalInterfacepublic interface Function<T, R> {

R apply(T t);

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);return (V v) -> apply(before.apply(v));

}// … more default and static methods

}26

Page 27: Programação funcional com java 8

Function<Jogador, Integer> idadeAnos = (Jogador jogador) -> {return Period.between(jogador.getDataNascimento(), LocalDate.now())

.getYears();};

System.out.println(idadeAnos.apply(jogador)); //Imprime 30

Function

27

Page 28: Programação funcional com java 8

java.util.function.BiConsumer<T,U>

java.util.function.BiFunction<T,U,R>

java.util.function.BinaryOperator<T>

java.util.function.BiPredicate<T,U>

java.util.function.BooleanSupplier

java.util.function.Consumer<T>

java.util.function.DoubleBinaryOperator

java.util.function.DoubleConsumer

java.util.function.DoubleFunction<R>

java.util.function.DoublePredicate

java.util.function.DoubleSupplier

java.util.function.DoubleToIntFunction

java.util.function.DoubleToLongFunction

java.util.function.DoubleUnaryOperator

Package java.util.function

28

java.util.function.Function<T,R>

java.util.function.UnaryOperator<T>

java.util.function.IntBinaryOperator

java.util.function.IntConsumer

java.util.function.IntFunction<R>

java.util.function.IntPredicate

java.util.function.IntSupplier

java.util.function.IntToDoubleFunction

java.util.function.IntToLongFunction

java.util.function.IntUnaryOperator

java.util.function.LongBinaryOperator

java.util.function.LongConsumer

java.util.function.LongFunction<R>

java.util.function.LongPredicate

java.util.function.LongSupplier

java.util.function.LongToDoubleFunction

java.util.function.LongToIntFunction

java.util.function.LongUnaryOperator

java.util.function.ObjDoubleConsumer<T>

java.util.function.ObjIntConsumer<T>

java.util.function.ObjLongConsumer<T>

java.util.function.Predicate<T>

java.util.function.Supplier<T>

java.util.function.ToDoubleBiFunction<T,U>

java.util.function.ToDoubleFunction<T>

java.util.function.ToIntBiFunction<T,U>

java.util.function.ToIntFunction<T>

java.util.function.ToLongBiFunction<T,U>

java.util.function.ToLongFunction<T>

Page 29: Programação funcional com java 8

// Sem Type InferenceComparator<Jogador> c1 = (Jogador a1, Jogador a2) ->

a1.getNome().compareTo(a2.getNome());

// Com Type InferenceComparator<Jogador> c1 = (a1, a2) -> a1.getNome().compareTo(a2.getNome());

Type inference

29

Page 30: Programação funcional com java 8

Mesma Lambda, diferentes Functional Interfaces

30

● Mesma Lambda, duas Functional Interface diferentes

Comparator<Jogador> c = (a1, a2) -> a1.getNome().compareTo(a2.getNome());

BiFunction<Jogador, Jogador, Integer> c = (a1, a2) -> a1.getNome().compareTo(a2.getNome());

Page 31: Programação funcional com java 8

31

Dois métodos com mesmo nome, recebendo diferentes Functional Interfaces, porém que aceitam a mesma Lambda

private void testTypeChecking(BiFunction<Jogador, Jogador, Integer> lambda)

private void testTypeChecking(Comparator<Jogador> lambda)

Ao chamar o método

testTypeChecking((a1, a2) -> a1.getNome().compareTo(a2.getNome()));

o compilador apresenta o erro: The method testTypeChecking(Comparator<Jogador>) is ambiguous for the type class ...

Page 32: Programação funcional com java 8

32

● … porém se passarmos o objeto comp o compilador sabe qual método chamar

Comparator<Jogador> comp = (a1, a2) -> a1.getNome().compareTo(a2.getNome());

testTypeChecking(comp);

Page 33: Programação funcional com java 8

private String scope = "class";

Comparator<Jogador> c1 = (a1, a2) -> {String scope = "lambda";System.out.println(this.scope);return a1.getNome().compareTo(a2.getNome());

};

listaJogadores.sort(new Comparator<Jogador>() {String scope = "anonymous";@Overridepublic int compare(Jogador o1, Jogador o2) {

System.out.println(this.scope);return o1.getNome().compareTo(o2.getNome());

}});

This Scope

Imprime: class

Imprime: anonymous

33

Page 34: Programação funcional com java 8

private String readOneLine() throws IOException {

try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getClassLoader()

.getResourceAsStream("document.txt")))) {return br.readLine();

}}

34

passando comportamento por paramentro

Page 35: Programação funcional com java 8

private String readTwoLine() throws IOException {

try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getClassLoader()

.getResourceAsStream("document.txt")))) {return br.readLine() + br.readLine();

}}

35

Page 36: Programação funcional com java 8

@FunctionalInterfacepublic interface BufferedReaderProcessor {

String process(BufferedReader br) throws IOException;}

36

Page 37: Programação funcional com java 8

private String readLine(BufferedReaderProcessor p) throws IOException {try (BufferedReader br = new BufferedReader(

new InputStreamReader(getClass().getClassLoader().getResourceAsStream("document.txt")))) {

return p.process(br);}

}

//main...readLine((br) -> br.readLine());readLine((br) -> br.readLine() + br.readLine());readLine((br) -> br.readLine() + br.readLine());….

37

Page 38: Programação funcional com java 8

Compose LambdasPredicate<Jogador> filter = //...

filter.and((Jogador j) -> Posicao.ATACANTE.equals(j.getPosicao())).or((Jogador j) -> Posicao.MEIO_CAMPO.equals(j.getPosicao())).and((Jogador j) -> j.getNome().startsWith("C"));

//Predicate do Java...public interface Predicate<T> {

boolean test(T t);

default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) && other.test(t);

}38

Page 39: Programação funcional com java 8

Method References● Permite referenciar métodos ou construtores usando ::● Como se fosse uma abreviação de uma lambda, chamando somente um

método

Lambda:Consumer<String> consumer = (String s) -> System.out.println(s)

Method Reference:Consumer<String> consumer = System.out::println

39

Page 40: Programação funcional com java 8

Método BinaryOperator<String> ct = String::concat; String result = ct.apply("Lam", "bda"); System.out.println(result);// Imprime Lambda

Lambda:BinaryOperator<String> ct = (String str2, String str1) -> str1.concat(str2);

40

Page 41: Programação funcional com java 8

Construtor

BiFunction<String, String, Equipe> build = Equipe::new;Equipe barcelona = build.apply("Futbol Club Barcelona", "Barcelona");

Lambda:BiFunction<String, String, Equipe> build =

(nomeCompleto, nome) -> new Equipe(nomeCompleto, nome);

41

Page 42: Programação funcional com java 8

Usando Method ReferenceslistaJogadores.sort(Comparator.comparing(Jogador::getNome)

.thenComparing(Jogador::getPosicao)

.thenComparing(Jogador::getDataNascimento));

artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ).collect(Collectors.groupingBy(

Artilharia::getEquipeNome, Collectors.counting()));

42

Page 43: Programação funcional com java 8

java.util.Stream

Streams API

Page 44: Programação funcional com java 8

iterando coleções

Page 45: Programação funcional com java 8

List<String> times = brasileirao.getClassificacao().stream().map(c -> c.getEquipe().getNomePopular()).distinct().collect(Collectors.toList());

times.forEach(System.out::println);

45

Page 46: Programação funcional com java 8

o que é um Stream

Page 47: Programação funcional com java 8
Page 48: Programação funcional com java 8

Stream Operations

Page 49: Programação funcional com java 8

Source Intermediate Operation

Intermediate Operation

Terminal Operation

Stream Pipeline

49

Page 50: Programação funcional com java 8

Source Intermediate Operations

Intermediate Operations

Terminal Operations

Stream Pipeline

50

Page 51: Programação funcional com java 8

ArraysCollection<E>FilesRandomBufferedReaderStream

Source

Stream

51

Page 52: Programação funcional com java 8

Source Intermediate Operation

Intermediate Operation

Terminal Operation

Stream Pipeline

52

Page 53: Programação funcional com java 8

Source Intermediate Operations

Intermediate Operations

Terminal Operation

Stream Pipeline

53

Page 54: Programação funcional com java 8

List<Artilharia> atacantes = artilharia.stream()

.filter( j -> "Atacante".equals( j.getJogadorPosicao() )

Intermediate Operation

.filter( Predicate p )

54

Page 55: Programação funcional com java 8

List<String> nomesDosAtacantes = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.map( j -> j.getJogadorNome().toUpperCase() )

.collect( Collectors.toList() );

Intermediate Operation

.map( Function f )

55

Page 56: Programação funcional com java 8

Intermediate Operation

.flatMap( Function f )

map map

1 - to - 1

map map

1 - to - n

Map

FlatMap

56

Page 57: Programação funcional com java 8

List<String> nomesDosAtacantes = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.sorted( Comparator.comparing( Artilharia::getTotalGols ) )

.collect( Collectors.toList() );

Intermediate Operation

.sorted( Comparator c )

57

Page 58: Programação funcional com java 8

List<String> nomesDosAtacantes = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.distinct( )

.collect( Collectors.toList() );

Intermediate Operation

.distinct( )

58

Page 59: Programação funcional com java 8

List<String> nomesDosAtacantes = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.peek( j -> System.out.println( j.getJogadorNome() ))

.distinct()

.collect( Collectors.toList() );

Intermediate Operation

.peek( Consumer c )

59

Page 60: Programação funcional com java 8

List<String> nomesDosAtacantes = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.skip( 10 )

.collect( Collectors.toList() );

Intermediate Operation

.skip( long n )

60

Page 61: Programação funcional com java 8

List<String> nomesDosAtacantes = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.limit( 10 )

.collect( Collectors.toList() );

Intermediate Operation

.limit( long n )

61

Page 62: Programação funcional com java 8

Source Intermediate Operation

Intermediate Operation

Terminal Operation

Stream Pipeline

62

Page 63: Programação funcional com java 8

Source Intermediate Operations

Intermediate Operations

Terminal Operations

Stream Pipeline

63

Page 64: Programação funcional com java 8

List<String> nomesDosAtacantes = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.collect( Collectors.toList() );

Terminal Operation

.collect( Collector c )

64

Page 65: Programação funcional com java 8

Map<String, Integer> atacanteETotalDeGols = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.collect( Collectors.toMap( j -> j.getJogadorNome(), j -> j.getTotalGols() ) );

Terminal Operation

.collect( Collector c )

65

Page 66: Programação funcional com java 8

Map<String, Long> atacantesPorTime = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.collect(Collectors.groupingBy(

Artilharia::getEquipeNome, Collectors.counting() ) );

Terminal Operation

.collect( Collector c )

66

Page 67: Programação funcional com java 8

artilharia.stream().filter( j -> "Atacantes".equals( j.getJogadorPosicao() ) )

.forEach( j ->

System.out.println( j.getJogadorNome() + " - " + j.getTotalGols() ) );

Terminal Operation

.forEach( Consumer c )

67

Page 68: Programação funcional com java 8

List<String> nomesDosAtacantes = artilharia.stream().filter( j -> "Atacantes".equals( j.getJogadorPosicao() ) ).collect( Collectors.toList() );

nomesDosAtacantes.forEach( System.out::println );

Terminal Operation

.forEach( Consumer c )

68

Page 69: Programação funcional com java 8

OptionalLong numeroDeGols = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ).mapToLong( Artilharia::getTotalGols )

.min();

Terminal Operation

.min( Comparator c )

69

Page 70: Programação funcional com java 8

OptionalLong numeroDeGols = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ).mapToLong( Artilharia::getTotalGols )

.max();

Terminal Operation

.max( Comparator c )

70

Page 71: Programação funcional com java 8

long numeroDeAtacantes = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.count();

Terminal Operation

.count( )

71

Page 72: Programação funcional com java 8

long totalDeGolsDeAtacantes = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ).mapToLong( Artilharia::getTotalGols )

.sum();

Terminal Operation

.sum( )

72

Page 73: Programação funcional com java 8

long totalDePartidas = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ).mapToLong( Artilharia::getTotalPartidas )

.reduce(0, (a, b) -> a + b);

Terminal Operation

.reduce( BinaryOperator b )

73

Page 74: Programação funcional com java 8

long reduce = LongStream.of(1, 2, 3, 4).reduce(0, (a, b) -> a + b);

Terminal Operation

.reduce( BinaryOperator b )

74

Page 75: Programação funcional com java 8

Optional<Artilharia> primeiroAtacanteArtilheiro = artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.findFirst();

Terminal Operation

.findFirst( )

75

Page 76: Programação funcional com java 8

Cuidado com a ordem das operações!

Stream().of("alpha", "bravo", "charlie", "delta", "echo", "foxtrot").map( j -> {

System.out.println("map: " + j.toUpperCase() );return j.toUpperCase();

} ).filter( j -> {

System.out.println("filter: " + j );return j.startsWith("A");

} ).forEach( j -> {

System.out.println("forEach: " + j );});

76

Page 77: Programação funcional com java 8

map: ALPHAfilter: ALPHAforEach: ALPHAmap: BRAVOfilter: BRAVOmap: CHARLIEfilter: CHARLIEmap: DELTAfilter: DELTAmap: ECHOfilter: ECHOmap: FOXTROTfilter: FOXTROT

Cuidado com a ordem das operações!

6 x map

77

Page 78: Programação funcional com java 8

Cuidado com a ordem das operações!Stream().of("alpha", "bravo", "charlie", "delta", "echo", "foxtrot")

.filter( j -> {System.out.println("filter: " + j );return j.startsWith("a");

} ).map( j -> {

System.out.println("map: " + j.toUpperCase() );return j.toUpperCase();

} ).forEach( j -> {

System.out.println("forEach: " + j );});

78

Page 79: Programação funcional com java 8

filter: alpha

map: ALPHA

forEach: ALPHAfilter: bravofilter: charliefilter: deltafilter: echofilter: foxtrot

Cuidado com a ordem das operações!

1 x map

79

Page 80: Programação funcional com java 8

operações LazyStream.of(

"Whatever", "it", "takes", "to", "break", "Gotta", "do", "it", "From", "the", "burning", "lake", "or", "the", "eastern", "gate", "You'll", "get", "through", "it" ).filter( j -> j.startsWith("t") ).map( j -> j.toUpperCase() ).findFirst();

"Whatever" "it", "takes""to""break""Gotta""do""it"

startsWith("t") toUpperCase() findFirst()"takes" "TAKES"

80

Page 81: Programação funcional com java 8

List<Artilharia> atacantes = artilharia.stream()

.filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.sorted( Comparator.comparing(Artilharia::getTotalGols).reversed() )

.collect( Collectors.toList() );

o que como

81

Page 82: Programação funcional com java 8

Parallel Stream

Page 83: Programação funcional com java 8

artilharia.stream().filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.sorted( Comparator.comparing(Artilharia::getTotalGols).reversed() )

.collect( Collectors.toList() );

83

Page 84: Programação funcional com java 8

artilharia

.filter( j -> "Atacante".equals( j.getJogadorPosicao() ) )

.sorted( Comparator.comparing(Artilharia::getTotalGols).reversed() )

.collect( Collectors.toList() );

.parallelStream()

84

Page 85: Programação funcional com java 8

fork-join framework

85

Page 86: Programação funcional com java 8

quando usar parallelStream()

86

Page 87: Programação funcional com java 8

Estrutura de dados

ArrayList<E>HashSet, TreeSetLinkedList

Tamanho da Coleção

Operações

filter()map()

sorted()distinct()

87

Page 88: Programação funcional com java 8

N = tamanho da coleçãoQ = custo por elemento no pipeline da streamN x Q = custo total do pipeline

quanto maior N x Q melhor será a execução em paralelo

88

Simon Ritter Oracle Java Technology Evangelist

Page 90: Programação funcional com java 8

Obrigado!

Leonardo Neuwaldtwitter.com/leoneuwald

Cristian R. Silvaabout.me/ocristian