Este documento presenta una introducción a las expresiones lambda y conceptos básicos de programación funcional en Java 8. La agenda incluye una breve reseña sobre Java, Java 8, expresiones lambda, conceptos básicos de programación funcional, procesamiento de datos con streams y el nuevo API de fechas. El orador es Eudris Cabrera, ingeniero telemático y desarrollador de software.
1. #BarCampRD2015
28 Noviembre 2015, PUCMM, Santiago de los caballeros, R. D.
EUDRIS CABRERA
@eudriscabrera
Más allá de las
Expresiones
Lambda
2. @ecabrerar
@eudriscabrera
BarCampRD Java Dominicano CodeCamp SDQ 4.0
● Ingeniero Telemático (PUCMM).
○ Desarrollador Informático / PAFI - Ministerio de
Hacienda, R. D.
○ Entusiasta de la tecnología y el software libre.
○ Ganador de la beca Linux Training Scholarship
2014 categoría Developer Do-Gooder.
● Eventos
Eudris Cabrera
3. AGENDA
● Breve Reseña sobre Java
● Java 8
● Expresiones Lambda
● Conceptos Básicos (sobre Programación Funcional)
● Procesando Data con Streams
● Nuevo API de fechas
4. ● Java fue inventado como un lenguaje orientado a
objeto.
● Utiliza una máquina virtual para su ejecución (JVM)
● La plataforma java está dividida en Java SE, Java
EE, Java ME y Javafx
● ~ 2005 con Java 5 se introducen cambios
significativos.
○ Genéricos
○ Loop Mejorado
○ Anotaciones
○ Enumeraciones
○ Mejora para la concurrencia (AtomicInteger)
Breve Reseña sobre Java
James Gosling
Creador de Java
en los años 90's
5. Popularidad del Lenguaje Java
TIOBE Index lo sitúa en el primer lugar para el mes de Noviembre del 2015.
http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
Githut Info* lo sitúa en el segundo lugar para el mes de Noviembre del 2015,
muy cercano a Javascript, quien ocupa el primer lugar.
http://githut.info
*Githut Info es un espacio que muestra el uso de los lenguajes de programación dentro de la
plataforma GitHub.
6. 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.
7. 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.
8. Desarrolló en los años 30's
el "Cálculo lambda", un
sistema formal en lógica
matemática diseñado para
investigar la definición de
función, la noción de
aplicación de funciones y la
recursión.
Alonzo Church
9. Una expresión lambda se compone de un conjunto de
parámetros, un operador lambda (->) y un cuerpo de la
función.
10. Sintaxis
() -> System.out.println("Hello Lambda")
x -> x + 10
(int x, int y) -> { return x + y; }
(String x, String y) -> x.length() – y.length()
(String x) -> {
listA.add(x);
listB.remove(x);
return listB.size();
}
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. 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. 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.
15. 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);
16. 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)
17. 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)"
18. 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 {
}
20. Programación Funcional
Un paradigma de programación donde las funciones son
entidades de primera clase.
¿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.
21. Programación Funcional
El primer lenguaje ampliamente utilizado para
programación funcional fue Lisp diseñado por John
McCarthy en los años 50's
En las universidades frecuentemente se usa Haskell
para la enseñanza.
Puedes empezar con JavaScript, Python, Scala o Java 8
Logo
de Haskell
22. ¿Por qué utilizar programación funcional?
● Ley de Moore
● Programación Concurrente
● Inmutabilidad -> El estado no cambia
● Facilidad para programar concurrentemente
● Las funciones siempre devuelven el mismo resultado para cada entrada
● Reducción de la cantidad de líneas de código.
● Código más fácil de testear.
23. Programación Funcional vs Programación Imperativa
❏ Programación imperativa y programación funcional son dos enfoques muy diferentes.
❏ Imperativo.
❏ Se utilizan cambios de estado.
❏ Orden de ejecución se define como un contrato.
❏ La repetición (loop) es explícito y externo.
❏ Efectos de lado.
❏ Mutabilidad.
❏ Funcional.
❏ Se utilizan funciones aritméticas.
❏ Orden de ejecución no se define.
❏ La repetición es a través del uso de la recursión.
❏ No hay efectos de lado.
❏ Inmutabilidad.
25. La programación funcional no va a resolver
todos sus problemas de programación.
Es sólo otra herramienta en su arsenal.
Algunos problemas son más fáciles de
resolver utilizando técnicas de
programación funcional.
Otros son más adecuados a la
programación lógica.
Otros se hacen mejor usando programación
orientada a objetos.
26. Introducción al Stream API
Stream:
● Representa una abstracción para
especificar cálculos agregados
(acumulativos).
● Simplifica la descripción de los cálculos
agregados (laziness,paralelismo).
27. Elementos de un Stream
Un Stream se compone de 3 elementos:
● Un origen
● Cero o más operaciones intermedias
● Una operación final (da salida a un resultado)
34. 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();
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"));
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()
37. Clase Optional
Ayuda a eliminar los problemas de NullPointerException
Optional<T>
Contenedor para una referencia de objet (nulo, o objeto real).
Piensa en Optional como un stream 0 ó 1 elemento.
Garantiza que la referencia de Optional no retornará nulo.
38. Ejemplo
Usando Optional con Stream
Optional<String> val = Stream.of("one", "two").findAny();
Optional<String> val = Stream.of("one", "two").findFirst();
Optional<Team> opt = teams.stream().findFirst();
Otros métodos útiles en la clase Optional
opt.isPresent(); //true
Optional<Team> opt = Optional.empty();
opt.orElse(new Team("TOR", "Toronto Blue Jays", true, 1992)).isHasWonWoldSeries();
40. java.time
Tiempo Actual
Clock clockUTC = Clock.systemUTC();
Clock clockDefault = Clock.systemDefaultZone();
Zona Horaria
ZoneId zone = ZoneId.systemDefault();
ZoneId zoneAmerica = ZoneId.of("America/Santo_Domingo");
Clock clock = Clock.system(zoneAmerica);
41. java.time
LocalDate : Fecha más fácil de interpretar.
LocalDate date = LocalDate.now();
System.out.printf("%s-%s-%s", date.getYear(), date.getMonthValue(), date.getDayOfMonth());
Determinar si una fecha es festiva usando TemporalQuery
LocalDate date = LocalDate.of(2016, Month.JANUARY, 26);
Boolean isHoliday = date.query(new DiasFestivosRD());
Conocer la cantidad de un día que tiene un mes usando lengthOfMonth
LocalDate date = LocalDate.of(2015, Month.MARCH, 01);
int length2 = date.lengthOfMonth();
42. java.time
Haciendo Calculo de fechas
LocalDate sinceJava8Launch = LocalDate.of(2014, Month.MARCH, 18);
LocalDate today = LocalDate.now();
today.isAfter(sinceJava8Launch); //true
Calcular diferencia entre dos fecha usando period
LocalDate sinceBarCamp2013 = LocalDate.of(2013, Month.NOVEMBER, 16);
LocalDate currentDate = LocalDate.of(2015, Month.NOVEMBER, 28);
Period betweenDates = Period.between(sinceBarCamp2013, currentDate);
int diffInDays = betweenDates.getDays();
int diffInMonths = betweenDates.getMonths();
int diffInYears = betweenDates.getYears();
43. 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.
48. 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.