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.
Loading in …3
×
1 of 60

Java 8: Expresiones Lambdas y API Stream BarCamp RD 2016

0

Share

Download to read offline

Expresiones Lambdas y la API Stream son una combinación muy poderosa que requiere un cambio de paradigma de la forma en la que hemos escrito código Java hasta el momento. En esta charla vamos a mostrar a los interesados las bondades de utilizar expresiones Lambdas en combinación con la API Stream, haciendo énfasis en situaciones que se presentan en proyectos reales.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

Java 8: Expresiones Lambdas y API Stream BarCamp RD 2016

  1. 1. Java 8: Expresiones Lambdas y API Stream en la Práctica Eudris Cabrera Noviembre 19, 2016 #BarCampRD2016
  2. 2. Eudris Cabrera Graduado de Ingeniería Telemática en la PUCMM. Entusiasta de la tecnología y el software libre, desarrollador Java, instructor ocasional (Java / Linux), aficionado del béisbol/sóftbol y los bailes latinos. En el tiempo libre, escribe artículos, realiza charlas, participa en eventos tecnológicos y ayuda en la revisión de documentación técnica en el mundo Java y el código abierto.
  3. 3. Breve Reseña sobre Java 8 Expresiones Lambda Introducción al Stream API Conceptos Avanzados sobre Lambda y API Stream Consejos Prácticos Agenda
  4. 4. Java SE 8 Liberado en marzo del 2014, es la plataforma que incluye la actualización más grande para el modelo de programación Java desde el lanzamiento de la plataforma en 1996. Incluye nuevas funcionalidades e incorpora las características de los lenguaje funcionales.
  5. 5. Funciones como entidades de primer nivel La programación funcional establece que las funciones (métodos) sean definidas como entidades de primer nivel ¿Qué significa eso? Qué las funciones pueden ser usada de la misma forma que usamos enteros (integers) o cadenas de caracteres(strings). Se pueden pasar funciones como parámetros a otras funciones y pueden ser retornada como resultado de otras funciones.
  6. 6. Ejemplo Funciones como entidades de primer nivel public void printTeamsWithPredicate(List<Team> teams, Predicate<Team> tester){ for (Team t : teams) { if(tester.test(t)){ System.out.println(""+ t.toString()); } } } Predicate<Team> hasNotWonWS = new Predicate<Team>() { @Override public boolean test(Team t) { return !t.isHasWonWoldSeries(); } }; printTeamsWithPredicate(teams, hasNotWonWS);
  7. 7. Ejemplo Ejemplo anterior usando expresiones lambdas. printTeamsWithPredicate(teams, (Team t) -> !t.isHasWonWoldSeries());
  8. 8. Expresiones lambdas Una expresión lambda representa una función anónima. λx → x+x Función anónima que toma un número x y devuelve el resultado x + x.
  9. 9. Sintaxis () -> System.out.println("Hello Lambda") x -> x + 10 (int x, int y) -> { return x + y; } (String x, String y) -> x.length() – y.length() (int a, int b) --> a + b (int a) --> a + 1 (int a, int b) --> { System.out.println(a + b); return a + b; } () --> new ArrayList();
  10. 10. Una expresión lambda se compone de un conjunto de parámetros, un operador lambda (->) y un cuerpo de la función.
  11. 11. ¿Por qué Java necesita Expresiones Lambda?
  12. 12. ● Java necesitaba cambios para simplificar la codificación paralela. ● Es muy útil para evitar tener que escribir métodos que sólo utilizamos una vez. ● Simplifica cómo pasar comportamiento como un parámetro (podemos pasar expresiones lambda a métodos como argumentos).
  13. 13. Interfaces Funcionales En Java, una interfaz funcional es, básicamente, una interfaz con un único método abstracto. Este tipo de interfaces también son conocidos como tipos SAM (Single Abstract Method). @FunctionalInterface public interface Runnable { public abstract void run(); } Runnable r = () -> System.out.println("Hello Lambda");
  14. 14. Metodos Predeterminados("Default") ● Tradicionalmente, las interfaces no pueden tener definiciones de método (sólo declaraciones). ● Métodos predeterminados (Default) permite realizar implementaciones por defecto dentro de una interfaz. public interface A { default void foo() { System.out.println("Calling A.foo()"); } } public class Clazz implements A { }
  15. 15. java.util.function ● Predicate<T> - Recibe un argumento tipo T y retorna un booleano. ● Consumer<T> - una acción que se realiza sobre un objeto ● Function<T,R> - a funcion que transforma un valor T a R ● Supplier<T> - provee una instancia de T (como un factory). ● UnaryOperator<T> - Forma especializada de Function. Recibe un valor T como argumento y retorna del un valor del mismo tipo T. ● BinaryOperator<T> - Forma especializada de BiFunction. Recibe dos argumentos y retorna un resultado, todos del mismo tipo.
  16. 16. Introducción al API Stream Stream: ● Representa una abstracción para especificar cálculos agregados (acumulativos). ● Simplifica la descripción de los cálculos agregados (laziness,paralelismo).
  17. 17. Elementos de un Stream Un Stream se compone de 3 elementos: ● Un origen ● Cero o más operaciones intermedias ● Una operación final (salida o un resultado)
  18. 18. Ejemplo long totalEquipos = teams.stream() .filter(t -> t.isHasWonWoldSeries()) .mapToInt(Team::getLastTimeWonWorldSeries) .count(); Source Intermediate operations Terminal operation
  19. 19. java.util.stream filter/map/reduce para Java
  20. 20. java.util.stream List<MLBTeam> teams = ..; // sequential version Stream stream = students.stream(); //parallel version Stream parallelStream = students.parallelStream();
  21. 21. java.util.stream Stream Sources (Origen) ● Collections ● Generadores (Generators) ● Otros Streams
  22. 22. Ejemplo Antes de Java 8 Collection<Team> worldSeriesWinners = new ArrayList<>(); for (Team team : teams) { if (team.isHasWonWoldSeries()) { worldSeriesWinners.add(team); } } Java 8 Collection<Team> worldSeriesWinners = teams .stream() .filter(p -> p.isHasWonWoldSeries()) .collect(Collectors.toList());
  23. 23. Ejemplo Procesar la siguiente lista para que solamente contenga cadena de caracteres impares y en letra minúscula. List<String> list = Arrays.asList("BarCamp", "MongoDB", "10Gen", "TokuMX", "Nagios", "PUCMM", "Ruby", "JSON", "JSON"); Solución usando clase anónima List<String> newList = list .stream() .filter(new Predicate<String>() { @Override public boolean test(String t) { return (t.length() % 2)==1; } }).map(String::toLowerCase) .collect(Collectors.toList());
  24. 24. Ejemplo Procesar la siguiente lista para que solamente contenga cadena de caracteres impares y en letra minúscula. List<String> list = Arrays.asList("BarCamp", "MongoDB", "10Gen", "TokuMX", "Nagios", "PUCMM", "Ruby", "JSON", "JSON"); Solución usando expresiones lambdas List<String> newList = list .stream() .filter(s -> (s.length() % 2)==1) .map(String::toLowerCase) .collect(Collectors.toList());
  25. 25. Ejemplo Usando Generadores (Generators) OptionalInt one = IntStream.generate(() -> 1) .limit(10) .distinct() .findFirst();
  26. 26. Method References Nos permiten utilizar un método como una expresión lambda. Formato: target_reference::method_name class Person { private String name; private int age; public int getAge() {return this.age;} public String getName() {return this.name;} } Person[] people = ...; Comparator<Person> byName = Comparator.comparing(Person::getName); Arrays.sort(people, byName);
  27. 27. Method References (Tipos) ● Método estático (ClassName::methName) ● Un método de instancia de un objeto particular (instanceRef::methName) ● Un método super de un objeto particular (super::methName) ● Un método de instancia de un objeto arbitrario de un tipo particular (ClassName::methName) ● Un constructor de una clase (ClassName::new) ● Un constructor de un arreglo (TypeName[]::new)
  28. 28. java.util.stream Operaciones Intermedias ● .filter ● .map ● .flatMap ● .peek ● .distinct ● .sorted ● .limit ● .substream
  29. 29. Ejemplo a) filter(Predicate predicate) OptionalInt oldestYear = teams.stream() .filter(t -> t.isHasWonWoldSeries()) .mapToInt(Team::getLastTimeWonWorldSeries) .min(); b) map(Function<? super T, ? extends R> mapper) List<String> list = Arrays.asList("BarCamp", "MongoDB", "10Gen", "TokuMX", "Nagios", "PUCMM", "Ruby", "JSON", "JSON"); List<String> newList = list .stream() .filter(s -> (s.length() % 2)==1) .map(String::toLowerCase) .collect(Collectors.toList()); OptionalInt one = IntStream .generate(() -> 1) .limit(10) .distinct() .findFirst(); limit(long maxSize) distinct()
  30. 30. Ejemplo a) flatMap(Function<T, Stream<R>):Stream<R> Permite transformar cada elemento del Stream en otro Stream y al final concatenarlos todos en uno solo. Es un poco confuso, pero pensemos que cuando tengamos un Stream<Stream<R>>, este método nos permitirá transformarlo en Stream<R>. List<String> lista = Arrays.asList("BarcampRD", "BarcampRD Lambdas y API Stream"); Stream stream = lista.stream() .map(s -> s.split(" ")) // Stream<String[]> .flatMap(Arrays::stream) // Stream<String> .distinct(); // Stream<String> de 5 elementos
  31. 31. java.util.stream Operaciones Finales (Terminal Operations) ● reducers like reduce(), count(), findAny(), findFirst() ● collectors (collect()) ● forEach ● iterators
  32. 32. Ejemplo Creación de un Stream vacío Stream<String> emptyStream = Stream.empty(); long val = emptyStream.count(); Suma de arreglo de enteros int[] numbers = {1, 2, 3, 4, 5, 6, 7}; int sum = Arrays.stream(numbers).sum(); Convertir Stream a List List<String> abc = Stream.of("a", "b", "c") .collect(Collectors.toList()); Usando operación count long count = Stream.of("one").count();
  33. 33. Ejemplo Usando operación noneMatch boolean noElementEqualTo5 = IntStream.of(1, 2, 3) .noneMatch(p -> p == 5); Usando operación allMatch List<String> teams = Lists.newArrayList("St. Louis Cardinals Team", "NY Mets Team", "LA Angels Team", "Washington Nationals Team", "LA Dodgers Team"); boolean containsAL = teams.stream().allMatch(p -> p.contains("Team"));
  34. 34. Ejemplo Usando forEach(Consumer c) List<Team> teams = new ArrayList<>(); teams.add(new Team("STL", "St. Louis Cardinals", true, 2011)); teams.add(new Team("NYM", "NY Mets", true, 1986)); teams.add(new Team("LAA", "LA Angels", true, 2002)); teams.add(new Team("WSN", "Washington Nationals", false, 0)); teams.add(new Team("LAD", "LA Dodgers", false, 0)); teams.forEach(p -> System.out.println(p));
  35. 35. Streams de objetos y tipos primitivos ● Java tiene valores primitivos, así como tipos de objetos. ● Para mejorar la eficiencia de Stream tenemos tres Stream de tipos primitivos ○ IntStream, DoubleStream, LongStream ● Pueden usarse junto a los métodos mapToInt(), mapToDouble(), mapToLong()
  36. 36. Ejemplo Trabajando con mapToInt(ToIntFunction<T>) int highScore = students.stream() .filter(s -> s.graduationYear() == 2015) .mapToInt(s -> s.getScore()) .max(); OptionalInt oldestYear = teams.stream() .filter(t -> t.isHasWonWoldSeries()) .mapToInt(Team::getLastTimeWonWorldSeries) .min(); Method References
  37. 37. Ejemplo Trabajando con mapToInt(ToIntFunction<T>) long totalEquipos = teams.stream() .filter(t -> t.isHasWonWoldSeries()) .mapToInt(Team::getLastTimeWonWorldSeries) .count(); Trabajando con mapToDouble(ToDoubleFunction<T>) List<Transaccion> trxs = ... //Stream de decimales cuyos elementos son el valor de las transacciones DoubleStream stream = trxs.stream().mapToDouble(Transaccion::getValor); Method References
  38. 38. Nuevos métodos útiles en Java 8 que pueden utilizar Lambdas Iterable Iterable.forEach(Consumer c) Collection Collection.removeIf(Predicate p) List List.replaceAll(UnaryOperator o) List.sort(Comparator c) Reemplaza "Collections.sort(List l, Comparator c)"
  39. 39. Ejemplo Usando Collection.removeIf(Predicate p) List<Person> personList = new ArrayList<>(); personList.add(new Person("Wilson",35)); personList.add(new Person("Peter",25)); personList.add(new Person("Jones",27)); Usando Predicate como una clase anónima personList.removeIf(new Predicate<Person>() { @Override public boolean test(Person person) { return "Jones".equals(person.getName()); } });
  40. 40. Ejemplo Usando Collection.removeIf(Predicate p) List<Person> personList = new ArrayList<>(); personList.add(new Person("Wilson",35)); personList.add(new Person("Peter",25)); personList.add(new Person("Jones",27)); Usando Predicate como expresion Lambda. 1. personList.removeIf((Person person) -> "Jones".equals(person.getName())); 2. personList.removeIf(person -> "Jones".equals(person.getName()));
  41. 41. Ejemplo Procesar la siguiente lista para que solamente contenga cadena con letra mayúscula. Antes de Java 8 List<String> list = Arrays.asList("Alfa", "Bravo", "Charlie", "Delta", "Echo", "Golf"); List<String> listUC=Lists.newArrayList(); for (ListIterator<String> it = list.listIterator(); it.hasNext();) { listUC.add(it.next().toUpperCase()); } Usando List.replaceAll(UnaryOperator o) list.replaceAll(String::toUpperCase); Method References
  42. 42. Ejemplo Ordenar la siguiente lista por nombre de personas. List<Person> personList = new ArrayList<>(); personList.add(new Person("Wilson",35)); personList.add(new Person("Peter",25)); personList.add(new Person("Jones",27)); Antes de Java 8 Collections.sort(personList, new ComparePersonsByName()); class ComparePersonsByName implements Comparator<Person> { @Override public int compare(Person p1, Person p2) { return p1.getName().compareTo(p2.getName()); } }
  43. 43. Ejemplo Ordenar la siguiente lista por nombre de personas. List<Person> personList = new ArrayList<>(); personList.add(new Person("Wilson",35)); personList.add(new Person("Peter",25)); personList.add(new Person("Jones",27)); Java 8 Collections.sort(personList, (Person p1, Person p2) -> p1.getName().compareTo(p2.getName()));
  44. 44. Ejemplo Ordenar la siguiente lista por nombre de personas. List<Person> personList = new ArrayList<>(); personList.add(new Person("Wilson",35)); personList.add(new Person("Peter",25)); personList.add(new Person("Jones",27)); Java 8 Usando el método por defecto Comparator.comparing 1. personList.sort(Comparator.comparing((Person p) -> p.getName())); 2. personList.sort(Comparator.comparing(p -> p.getName()));
  45. 45. Ejemplo Ordenar la siguiente lista por nombre de personas. List<Person> personList = new ArrayList<>(); personList.add(new Person("Wilson",35)); personList.add(new Person("Peter",25)); personList.add(new Person("Jones",27)); Java 8 Usando el método por defecto Comparator.comparing y methods references personList.sort(Comparator.comparing(Person::getName)); Usando import estático personList.sort(comparing(Person::getName));
  46. 46. Ejemplo Ordenar la siguiente lista por nombre de personas. List<Person> personList = new ArrayList<>(); personList.add(new Person("Wilson",35)); personList.add(new Person("Peter",25)); personList.add(new Person("Jones",27)); Java 8 Comparación de dos niveles personList.sort(Comparator.comparing(Person::getAge).thenComparing(Person::getName)); Usando import estático personList.sort(comparing(Person::getAge).thenComparing(Person::getName)); methods references
  47. 47. Usando colectores (collectors) List<String> teamsWithNull = Lists.newArrayList(null, "NY Mets", null, "Washington Nationals", "LA Angels", null); List<String> filterStrings = teamsWithNull .stream() .filter(p -> p != null) .collect(Collectors.toList()); Convertir a un List sin valores nulos
  48. 48. Usando colectores (collectors) Antes de Java 8 Map<String, Team> mappedTeams = new HashMap<>(); for (Team team : teams) { mappedTeams.put(team.getTeamId(), team); } Java 8 Map<String, Team> mappedTeams = teams .stream() .collect(Collectors.toMap(Team::getTeamId, (p) -> p)); Convertir un List a un Map
  49. 49. Usando colectores (collectors) Antes de Java 8 List<RutasPuntos> puntos = ModeloRutas.getInstancia().getPuntoPorRutas(ruta.getIdruta()); Set<Waypoint> waypoints = new HashSet<Waypoint>(); for (RutasPuntos rutasPuntos : puntos) { searchCriteria.setNameEquals(rutasPuntos.getSector().getDescripcion()); searchCriteria.setMaxRows(1); ToponymSearchResult searchResult = WebService.search(searchCriteria); for (Toponym toponym : searchResult.getToponyms()) { waypoints.add(new Waypoint(toponym.getLatitude(), toponym.getLongitude())); } WaypointPainter painter = new WaypointPainter(); painter.setWaypoints(waypoints); }
  50. 50. Usando colectores (collectors) Java 8 clase anónima List<RutasPuntos> puntos = ModeloRutas.getInstancia().getPuntoPorRutas(ruta.getIdruta()); Set<Waypoint> waypoints; for (RutasPuntos rutasPuntos : puntos) { searchCriteria.setNameEquals(rutasPuntos.getSector().getDescripcion()); searchCriteria.setMaxRows(1); ToponymSearchResult searchResult = WebService.search(searchCriteria); waypoints = searchResult.getToponyms() .stream() .map(new Function<Toponym, Waypoint>() { @Override public Waypoint apply(Toponym toponym) { return new Waypoint(toponym.getLatitude(), toponym.getLongitude()); } }) .collect(Collectors.toSet()); }
  51. 51. Usando colectores (collectors) Java 8 expresiones lambdas List<RutasPuntos> puntos = ModeloRutas.getInstancia().getPuntoPorRutas(ruta.getIdruta()); Set<Waypoint> waypoints; for (RutasPuntos rutasPuntos : puntos) { searchCriteria.setNameEquals(rutasPuntos.getSector().getDescripcion()); searchCriteria.setMaxRows(1); ToponymSearchResult searchResult = WebService.search(searchCriteria); waypoints = searchResult.getToponyms().stream() .map((Toponym toponym) -> new Waypoint(toponym.getLatitude(), toponym.getLongitude())) .collect(Collectors.toSet()); }
  52. 52. Depuración (Debugging) Una forma de hacer depuración de aplicaciones que usen lambas y Streams es usando el método +peek(Consumer<T>):Stream<T> , el cuál es una operación intermedia y por lo tanto no interrumpe el procesamiento del Stream. List<String> newList1 = list .stream() .filter(s -> (s.length() % 2)==1) .map(String::toLowerCase) .peek(System.out::println) .collect(Collectors.toList()); Colocar un breakpoint list .stream() .filter(s -> (s.length() % 2)==1) .map(String::toLowerCase) .peek(s -> s.toString()) .collect(Collectors.toList());
  53. 53. Depuración(Debugging) Algunas veces hacer debugging con expresiones lambdas resulta ser un poco tedioso. Las expresiones lambdas no se compilan como las clases anónimas, sino que son compiladas con llamadas a invokedynamic y su implementación se hace en tiempo de ejecución. Una solución alternativa a estos casos es la siguiente: - Extraer el código de una expresión Lambda en un método separado. - Sustituir la expresión Lambda con method reference por un nuevo método. - Establecer puntos de interrupción en las sentencias en el nuevo método. - Examinar el estado del programa utilizando depurador.
  54. 54. Consejos Prácticos ● Streams pueden ser infinitos, así como finitos. No existe el concepto de "ruptura" de un Stream. Utilice la operación final (terminal) correspondiente para detener el procesamiento O utilice el Stream de forma infinita. ● Evite forEach (excepto en casos especiales) ● Necesitas pensar en programación funcional más que programación imperativa (trate de dejar de pensar en los bucles). ● Piense en la forma de abordar los problemas utilizando recursividad.
  55. 55. ¿Preguntas?
  56. 56. ¡Gracias por Acompañarnos!
  57. 57. Referencias Libros: Functional Programming in Java (Dr. Venkat Subramaniam) Enlaces: http://slidedeck.io/DDuarte/java8-slides http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html https://dzone.com/articles/java-lambda-expressions-basics http://www.oracle.com/technetwork/es/articles/java/expresiones-lambda-api-stream-java-2633852-esa.html http://www.oracle.com/technetwork/es/articles/java/expresiones-lambda-api-stream-java-2737544-esa.html http://www.infoq.com/presentations/java-8-lambda-streams http://www.infoq.com/articles/Java-8-Lambdas-A-Peek-Under-the-Hood
  58. 58. https://github.com/ecabrerar/java-8-mas-alla-de-las-expresiones-lambda Código fuente de los ejemplos en GitHub
  59. 59. Asuntos Legales Todas las marcas registradas, así como todos los logotipos, imágenes, fotografías, audio y vídeos mostrados en esta presentación son propiedad de sus respectivos propietarios y/o representantes. Su utilización es solamente para fines ilustrativos.
  60. 60. @eudriscabrera @eudris @ecabrerar @eudriscabrera Eudris Cabrera Rodríguez Ingeniero Telemático Desarrollador de Software / Consultor Informático eudris@gmail.com https://www.linkedin.com/in/eudriscabrera http://www.slideshare.net/eudris https://twitter.com/eudriscabrera https://github.com/ecabrerar

×