Programação funcional com java 8

Post on 20-Feb-2017

460 views 1 download

Transcript of Programação funcional com java 8

Programação Funcional com Java 8

#TheDevConf 2015 POA

“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.”

O que realmente muda no nosso dia-a-dia usando 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

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

// 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

// 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

// 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

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

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

listaAtacantes.add(jogador);}

}

11

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

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

}

12

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

13

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

14

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

O que vamos ver então?Lambda

Functional interfacesMethod reference

Default methodsCollections APIStreams

16

● 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

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

Lambda Expression

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

19

Lambda Expression

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

20

Lambda Expression

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

21

Lambda Expression

x -> x + 10

22

Lambda Expression

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

return a;return b;

};

23

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

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

● @FunctionalInterface

Functional Interfaces

25

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

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

.getYears();};

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

Function

27

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>

// 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

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

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 ...

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

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

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

private String readTwoLine() throws IOException {

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

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

}}

35

@FunctionalInterfacepublic interface BufferedReaderProcessor {

String process(BufferedReader br) throws IOException;}

36

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

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

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

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

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

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

java.util.Stream

Streams API

iterando coleções

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

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

45

o que é um Stream

Stream Operations

Source Intermediate Operation

Intermediate Operation

Terminal Operation

Stream Pipeline

49

Source Intermediate Operations

Intermediate Operations

Terminal Operations

Stream Pipeline

50

ArraysCollection<E>FilesRandomBufferedReaderStream

Source

Stream

51

Source Intermediate Operation

Intermediate Operation

Terminal Operation

Stream Pipeline

52

Source Intermediate Operations

Intermediate Operations

Terminal Operation

Stream Pipeline

53

List<Artilharia> atacantes = artilharia.stream()

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

Intermediate Operation

.filter( Predicate p )

54

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

Intermediate Operation

.flatMap( Function f )

map map

1 - to - 1

map map

1 - to - n

Map

FlatMap

56

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

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

.distinct( )

.collect( Collectors.toList() );

Intermediate Operation

.distinct( )

58

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

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

.skip( 10 )

.collect( Collectors.toList() );

Intermediate Operation

.skip( long n )

60

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

.limit( 10 )

.collect( Collectors.toList() );

Intermediate Operation

.limit( long n )

61

Source Intermediate Operation

Intermediate Operation

Terminal Operation

Stream Pipeline

62

Source Intermediate Operations

Intermediate Operations

Terminal Operations

Stream Pipeline

63

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

.collect( Collectors.toList() );

Terminal Operation

.collect( Collector c )

64

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

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

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

.forEach( j ->

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

Terminal Operation

.forEach( Consumer c )

67

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

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

.min();

Terminal Operation

.min( Comparator c )

69

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

.max();

Terminal Operation

.max( Comparator c )

70

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

.count();

Terminal Operation

.count( )

71

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

.sum();

Terminal Operation

.sum( )

72

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

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

Terminal Operation

.reduce( BinaryOperator b )

74

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

.findFirst();

Terminal Operation

.findFirst( )

75

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

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

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

filter: alpha

map: ALPHA

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

Cuidado com a ordem das operações!

1 x map

79

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

List<Artilharia> atacantes = artilharia.stream()

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

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

.collect( Collectors.toList() );

o que como

81

Parallel Stream

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

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

.collect( Collectors.toList() );

83

artilharia

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

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

.collect( Collectors.toList() );

.parallelStream()

84

fork-join framework

85

quando usar parallelStream()

86

Estrutura de dados

ArrayList<E>HashSet, TreeSetLinkedList

Tamanho da Coleção

Operações

filter()map()

sorted()distinct()

87

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

Obrigado!

Leonardo Neuwaldtwitter.com/leoneuwald

Cristian R. Silvaabout.me/ocristian