Upload
leonardo-neuwald
View
461
Download
1
Embed Size (px)
Citation preview
Programação Funcional com Java 8
#TheDevConf 2015 POA
Leonardo Alves Neuwaldtwitter.com/leoneuwald
neogrid.com
Cristian R. Silvaabout.me/ocristian@o_cristian_github.com/ocristianslideshare.net/ocristianspeakerdeck.com/ocristian
adp.com/careers/brazilcareers
“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
ReferênciasJava 8 in ActionLambdas, streams, and functional-style programming
Functional Programming in Java
Introducing Java 8A Quick-Start Guide to Lambdas and Streams
Java 8 PráticoLambdas, Streams e os novos recursos da linguagem
Obrigado!
Leonardo Neuwaldtwitter.com/leoneuwald
Cristian R. Silvaabout.me/ocristian