Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Programação funcional com java 8

694 views

Published on

Slides da Apresentação realizada 24/09/2015 na Trilha de Java do The Developers Conference.

Resumo:
Programadores Java estão acostumados a desenvolver preocupando-se não somente com o que deveria ser feito, mas também em como fazer. Um simples código para buscar os dois maiores valores de uma lista pode levar tempo precioso de desenvolvimento. Para solucionar esse e outros problemas, o Java 8 traz uma série de melhorias buscando trazer para o Java muito da programação funcional que víamos em outras linguagens. Expressões lambda, streams entre outras novidades do Java serão apresentadas nessa palestra de forma simples e direto ao ponto.

http://www.thedevelopersconference.com.br/tdc/2015/portoalegre/trilha-java

Published in: Technology
  • Be the first to comment

Programação funcional com java 8

  1. 1. Programação Funcional com Java 8 #TheDevConf 2015 POA
  2. 2. Leonardo Alves Neuwald twitter.com/leoneuwald neogrid.com
  3. 3. Cristian R. Silva about.me/ocristian @o_cristian_ github.com/ocristian slideshare.net/ocristian speakerdeck.com/ocristian adp.com/careers/brazilcareers
  4. 4. “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.”
  5. 5. O que realmente muda no nosso dia-a-dia usando programação funcional com Java 8?
  6. 6. Ordenando e exibindo uma lista for (Jogador jogador : listaJogadores) { if (Posicao.ATACANTE.equals(jogador.getPosicao())) { listaAtacantes.add(jogador); } } Collections.sort(listaAtacantes, new Comparator<Atletas>() { @Override public int compare(Jogador j1, Jogador j2) { return j1.getNome().compareTo(j2.getNome()); } }); for (Jogador jogador : listaAtacantes) { System.out.println(jogador); } 6
  7. 7. 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
  8. 8. // Java 8 listaJogadores.sort((j1, j2) -> j1.getNome().compareTo(j2.getNome())); Collections.sort(listaAtacantes, new Comparator<Jogador>() { @Override public int compare(Jogador j1, Jogador j2) { return j1.getNome().compareTo(j2.getNome()); } }); 8
  9. 9. // Java 8 listaJogadores.sort((j1, j2) -> j1.getNome().compareTo(j2.getNome())); Collections.sort(listaAtacantes, new Comparator<Jogador>() { @Override public int compare(Jogador j1, Jogador j2) { return j1.getNome().compareTo(j2.getNome()); } }); 9
  10. 10. // Java 8 listaJogadores.sort((j1, j2) -> j1.getNome().compareTo(j2.getNome())); Collections.sort(listaAtacantes, new Comparator<Jogador>() { @Override public int compare(Jogador j1, Jogador j2) { return j1.getNome().compareTo(j2.getNome()); } }); 10
  11. 11. // Java 8 listaJogadores.removeIf(jogador -> !Posicao.ATACANTE.equals(jogador.getPosicao())); for (Jogador jogador : listaJogadores) { if (Posicao.ATACANTE.equals(jogador.getPosicao())) { listaAtacantes.add(jogador); } } 11
  12. 12. // Java 8 listaJogadores.forEach(System.out::println); for (Jogador jogador : listaAtacantes) { System.out.println(jogador); } 12
  13. 13. listaJogadores .stream() .filter(jogador -> Posicao.ATACANTE.equals(jogador.getPosicao())) .sorted(Comparator.comparing(Jogador::getNome)) .forEach(System.out::println); 13
  14. 14. listaJogadores .parallelStream() .filter(jogador -> Posicao.ATACANTE.equals(jogador.getPosicao())) .sorted(Comparator.comparing(Jogador::getNome)) .forEach(System.out::println); 14
  15. 15. 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
  16. 16. O que vamos ver então? Lambda Functional interfaces Method reference Default methods Collections API Streams 16
  17. 17. ● 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
  18. 18. Anonymous class: Collections.sort(listaAtacantes, new Comparator<Jogador>() { @Override public 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
  19. 19. Lambda Expression ( parametros ) -> { corpo da expressão lambda } 19
  20. 20. Lambda Expression ( parametros ) -> { corpo da expressão lambda } 20
  21. 21. Lambda Expression () -> System.out.println("Lambda em uma linha") 21
  22. 22. Lambda Expression x -> x + 10 22
  23. 23. Lambda Expression (String a, String b) -> { if ( a.length() > b.length() ) return a; return b; }; 23
  24. 24. 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
  25. 25. ● Interface com 1 único método abstrato ○ Default Methods ● @FunctionalInterface Functional Interfaces 25
  26. 26. package java.util.function; import java.util.Objects; @FunctionalInterface public 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
  27. 27. Function<Jogador, Integer> idadeAnos = (Jogador jogador) -> { return Period.between(jogador.getDataNascimento(), LocalDate.now()) .getYears(); }; System.out.println(idadeAnos.apply(jogador)); //Imprime 30 Function 27
  28. 28. 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>
  29. 29. // Sem Type Inference Comparator<Jogador> c1 = (Jogador a1, Jogador a2) -> a1.getNome().compareTo(a2.getNome()); // Com Type Inference Comparator<Jogador> c1 = (a1, a2) -> a1.getNome().compareTo(a2.getNome()); Type inference 29
  30. 30. 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. 31. 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. 32. 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);
  33. 33. 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"; @Override public int compare(Jogador o1, Jogador o2) { System.out.println(this.scope); return o1.getNome().compareTo(o2.getNome()); } }); This Scope Imprime: class Imprime: anonymous 33
  34. 34. 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
  35. 35. private String readTwoLine() throws IOException { try (BufferedReader br = new BufferedReader( new InputStreamReader(getClass().getClassLoader() .getResourceAsStream("document.txt")))) { return br.readLine() + br.readLine(); } } 35
  36. 36. @FunctionalInterface public interface BufferedReaderProcessor { String process(BufferedReader br) throws IOException; } 36
  37. 37. 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
  38. 38. Compose Lambdas Predicate<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
  39. 39. 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
  40. 40. 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
  41. 41. 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
  42. 42. Usando Method References listaJogadores.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
  43. 43. java.util.Stream Streams API
  44. 44. iterando coleções
  45. 45. List<String> times = brasileirao.getClassificacao().stream() .map(c -> c.getEquipe().getNomePopular()) .distinct() .collect(Collectors.toList()); times.forEach(System.out::println); 45
  46. 46. o que é um Stream
  47. 47. Stream Operations
  48. 48. Source Intermediate Operation Intermediate Operation Terminal Operation Stream Pipeline 49
  49. 49. Source Intermediate Operations Intermediate Operations Terminal Operations Stream Pipeline 50
  50. 50. Arrays Collection<E> Files Random BufferedReader Stream Source Stream 51
  51. 51. Source Intermediate Operation Intermediate Operation Terminal Operation Stream Pipeline 52
  52. 52. Source Intermediate Operations Intermediate Operations Terminal Operation Stream Pipeline 53
  53. 53. List<Artilharia> atacantes = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) Intermediate Operation .filter( Predicate p ) 54
  54. 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
  55. 55. Intermediate Operation .flatMap( Function f ) map map 1 - to - 1 map map 1 - to - n Map FlatMap 56
  56. 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
  57. 57. List<String> nomesDosAtacantes = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .distinct( ) .collect( Collectors.toList() ); Intermediate Operation .distinct( ) 58
  58. 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
  59. 59. List<String> nomesDosAtacantes = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .skip( 10 ) .collect( Collectors.toList() ); Intermediate Operation .skip( long n ) 60
  60. 60. List<String> nomesDosAtacantes = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .limit( 10 ) .collect( Collectors.toList() ); Intermediate Operation .limit( long n ) 61
  61. 61. Source Intermediate Operation Intermediate Operation Terminal Operation Stream Pipeline 62
  62. 62. Source Intermediate Operations Intermediate Operations Terminal Operations Stream Pipeline 63
  63. 63. List<String> nomesDosAtacantes = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .collect( Collectors.toList() ); Terminal Operation .collect( Collector c ) 64
  64. 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
  65. 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
  66. 66. artilharia.stream() .filter( j -> "Atacantes".equals( j.getJogadorPosicao() ) ) .forEach( j -> System.out.println( j.getJogadorNome() + " - " + j.getTotalGols() ) ); Terminal Operation .forEach( Consumer c ) 67
  67. 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
  68. 68. OptionalLong numeroDeGols = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .mapToLong( Artilharia::getTotalGols ) .min(); Terminal Operation .min( Comparator c ) 69
  69. 69. OptionalLong numeroDeGols = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .mapToLong( Artilharia::getTotalGols ) .max(); Terminal Operation .max( Comparator c ) 70
  70. 70. long numeroDeAtacantes = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .count(); Terminal Operation .count( ) 71
  71. 71. long totalDeGolsDeAtacantes = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .mapToLong( Artilharia::getTotalGols ) .sum(); Terminal Operation .sum( ) 72
  72. 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
  73. 73. long reduce = LongStream.of(1, 2, 3, 4).reduce(0, (a, b) -> a + b); Terminal Operation .reduce( BinaryOperator b ) 74
  74. 74. Optional<Artilharia> primeiroAtacanteArtilheiro = artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .findFirst(); Terminal Operation .findFirst( ) 75
  75. 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
  76. 76. map: ALPHA filter: ALPHA forEach: ALPHA map: BRAVO filter: BRAVO map: CHARLIE filter: CHARLIE map: DELTA filter: DELTA map: ECHO filter: ECHO map: FOXTROT filter: FOXTROT Cuidado com a ordem das operações! 6 x map 77
  77. 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
  78. 78. filter: alpha map: ALPHA forEach: ALPHA filter: bravo filter: charlie filter: delta filter: echo filter: foxtrot Cuidado com a ordem das operações! 1 x map 79
  79. 79. operações Lazy Stream.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
  80. 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
  81. 81. Parallel Stream
  82. 82. artilharia.stream() .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .sorted( Comparator.comparing(Artilharia::getTotalGols).reversed() ) .collect( Collectors.toList() ); 83
  83. 83. artilharia .filter( j -> "Atacante".equals( j.getJogadorPosicao() ) ) .sorted( Comparator.comparing(Artilharia::getTotalGols).reversed() ) .collect( Collectors.toList() ); .parallelStream() 84
  84. 84. fork-join framework 85
  85. 85. quando usar parallelStream() 86
  86. 86. Estrutura de dados ArrayList<E> HashSet, TreeSet LinkedList Tamanho da Coleção Operações filter() map() sorted() distinct() 87
  87. 87. N = tamanho da coleção Q = custo por elemento no pipeline da stream N 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
  88. 88. Referências Java 8 in Action Lambdas, streams, and functional-style programming Functional Programming in Java Introducing Java 8 A Quick-Start Guide to Lambdas and Streams Java 8 Prático Lambdas, Streams e os novos recursos da linguagem
  89. 89. Obrigado! Leonardo Neuwald twitter.com/leoneuwald Cristian R. Silva about.me/ocristian

×