Código fuente articulo:
https://www.dropbox.com/s/pzw44ot0ji2metl/Lambda.zip?dl=0
Una nueva funcionalidad introducida desde la versión 8 de JAVA son las Lambda expressions, estas son expresiones que simplifican la escritura de código haciendo mas concisa la implementación de algunos métodos. Piensa en clases anónimas pero aun mas simples, el problema es que al simplificar se agregan nuevos símbolos, un par de clases de utilidad y se deben tener en cuenta reglas como el numero de métodos que debe especificar la interfaz a implementar.
Para iniciar diremos que para usar una expresión Lambda se necesita definir una interfaz
interface VerificarPersona {
boolean verificar(Persona p);
}
Esta interfaz es llamada interfaz funcional porque solo tiene una función, se decir si le agregas otra función la arruinas de forma miserable, porque el compilador no sabría cual de las dos funciones estarías implementando con la expresión Lambda.
Para ilustrar esto de la función lambda vamos a imitar un ejemplo del JAVA TUTORIAL. este ejemplo lo que busca es crear una función capas de filtrar personas según criterios variables. La clase Persona luce así.
public class Persona{
public enum Sexo {
MASCULINO,
FEMENINO
}
String nombre;
Integer edad;
Sexo genero;
}
Para el filtro se define un método imprimirPersonas que imprime los nombre de ciertas personas que cumplen con un criterio de búsqueda, el método se ve así
public static void imprimirPersonas(
List<Persona> grupo, VerificarPersona filtro) {
for (Persona p : grupo) {
if (filtro.verificar(p)) {
System.out.println(p.nombre);
}
}
}
Para cumplir con su tarea este método recibe; una lista de personas y un filtro que utilizara para imprimir a aquellas personas que cumplan con el criterio, el filtro que es donde vamos a utilizar una función Lambda. Si te fijas el filtro es de tipo VerificarPersona y esta interface tiene un método verificar que regresa un valor entero, por consiguiente nuestra implementación sera la de una expresión lógica que regrese un valor falso o verdadero.
la primer expresión que vamos a construir filtrara a los hombres, mayores de 18 años y se vera así
(Persona p) -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18
ahora una que filtre a las mujeres menores de 16 años
(Persona p) -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16
ahora debemos pasarle estas expresiones al método así;
para el caso uno
imprimirPersonas(
listaPersonas,
(Persona p) -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18
);
imprimirPersonas(
listaPersonas,
(Persona p) -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16
);
Ahora si miras la interface VerificarPersona es bastante desabrida y cumple un rol muy genérico, para no tener que crear estas interfaces huecas JAVA ofrece una interface mas genérica llamada Predicate<T>, un predicado es una función que regresa un valor falso o verdadero, como se quiere poder utilizar con cualquier clase Predicate<T> tiene un valor genérico para el definir el tipo de objeto que vamos a utilizar para obtener el valor falso o verdadero. La nueva función imprimir se llamara imprimirPersonasPredicado y se vera así.
public static void imprimirPersonasPredicado (
List<Persona> grupo, Predicate<Persona> filtro) {
for (Persona p : grupo) {
if (filtro.test(p)) {
System.out.println(p.nombre);
}
}
}
Si te fijas el Predicate<Persona> remplazo a VerificarPersona y la funciona verificar por la función test. Todo lo demás sigue igual y lo mejor la implementacion de los filtros no cambio mira ahora como quedan
para el caso uno
imprimirPersonasPredicado (
listaPersonas,
(Persona p) -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18
);
imprimirPersonasPredicado (
listaPersonas,
(Persona p) -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16
);
Ahora supón que quieres en adición a la funcionalidad de filtro quieres llamar un método diferente para imprimir el nombre según el filtro aplicado. Para este fin se puede utilizar la clase Consumer<T>, Consumer es un comodín que se puede remplazar por cualquier método de la clase definido en <T> . Supongamos que tenemos dos nuevos métodos en la clase persona.
public void imprimirHombre() {
System.out.println("Sr. "+nombre);
}
public void imprimirMujer() {
System.out.println("Sra. "+nombre);
}
Y los queremos invocar según sea el caso para esto debemos modificar el método de filtro para que acepte un Consumer<T>, en nuestro caso un Consumer<Persona>.
public static void procesarPersonas(
List<Persona> grupo,
Predicate<Persona> filtro,
Consumer<Persona> bloque) {
for (Persona p : grupo) {
if (filtro.test(p)) {
bloque.accept(p);
}
}
}
ahora nuestros filtros implementados se verán así;
procesarPersonas(
listaPersonas,
p -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18,
p -> p.imprimirHombre()
);
procesarPersonas(
listaPersonas,
p -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16,
p -> p.imprimirMujer()
);
Ahora extendamos un poco mas, supón que quieres recuperar el genero para imprimirlo, pero te das cuenta que Consumer<T>, no regresa ningún valor :'( , por lo que vas a necesitar otro comodín que te ayude a recuperar el valor del genero, para esto existe Function<X,Y> esta clase te permite especificar que vas a llamar un método de la clase X y que esperas recibir en respuesta un objeto de la clase Y.
para esto le agregaremos un nuevo método a persona;
public String nombreGenero(){
return this.genero.name();
}
Ahora agregaremos un método que soporte la nueva funcionalidad.
public static void procesarPersonasConFunciones(
List<Persona> grupo,
Predicate<Persona> filtro,
Function<Persona, String> mapper,
Consumer<String> bloque
) {
for (Persona p : grupo) {
if (filtro.test(p)) {
String data = mapper.apply(p);
bloque.accept(data);
}
}
}
y lo pondremos en uso
procesarPersonasConFunciones(listaPersonas,
p -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16,
p -> p.nombreGenero(),
genero -> System.out.println(genero));
}
esta seria la versión final del ejemplo
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public class FiltroLambda {
interface VerificarPersona {
boolean verificar(Persona p);
}
public static void imprimirPersonas(
List<Persona> grupo, VerificarPersona filtro) {
for (Persona p : grupo) {
if (filtro.verificar(p)) {
System.out.println(p.nombre);
}
}
}
public static void imprimirPersonasPredicado (
List<Persona> grupo, Predicate<Persona> filtro) {
for (Persona p : grupo) {
if (filtro.test(p)) {
System.out.println(p.nombre);
}
}
}
public static void procesarPersonas(
List<Persona> grupo,
Predicate<Persona> filtro,
Consumer<Persona> bloque) {
for (Persona p : grupo) {
if (filtro.test(p)) {
bloque.accept(p);
}
}
}
public static void procesarPersonasConFunciones(
List<Persona> grupo,
Predicate<Persona> filtro,
Function<Persona, String> mapper,
Consumer<String> bloque
) {
for (Persona p : grupo) {
if (filtro.test(p)) {
String data = mapper.apply(p);
bloque.accept(data);
}
}
}
public static void main(String[] args) {
List<Persona> listaPersonas= new ArrayList<>();
listaPersonas.add(new Persona("Juan", 12, Persona.Sexo.MASCULINO));
listaPersonas.add(new Persona("Maria", 14, Persona.Sexo.FEMENINO));
listaPersonas.add(new Persona("Pedro", 45, Persona.Sexo.MASCULINO));
listaPersonas.add(new Persona("Martin", 21, Persona.Sexo.MASCULINO));
listaPersonas.add(new Persona("Adriana", 16, Persona.Sexo.FEMENINO));
listaPersonas.add(new Persona("Natalia", 27, Persona.Sexo.FEMENINO));
imprimirPersonas(
listaPersonas,
(Persona p) -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18
);
imprimirPersonas(
listaPersonas,
(Persona p) -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16
);
imprimirPersonasPredicado (
listaPersonas,
p -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18
);
imprimirPersonasPredicado (
listaPersonas,
p -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16
);
procesarPersonas(
listaPersonas,
p -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18,
p -> p.imprimirHombre()
);
procesarPersonas(
listaPersonas,
p -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16,
p -> p.imprimirMujer()
);
procesarPersonasConFunciones(listaPersonas,
p -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16,
p -> p.nombreGenero(),
genero -> System.out.println(genero));
}
}
class Persona{
enum Sexo {
MASCULINO,
FEMENINO
}
String nombre;
Integer edad;
Sexo genero;
public Persona(String nombre, Integer edad, Sexo genero) {
super();
this.nombre = nombre;
this.edad = edad;
this.genero = genero;
}
public void imprimirHombre() {
System.out.println("Sr. "+nombre);
}
public String nombreGenero(){
return this.genero.name();
}
public void imprimirMujer() {
System.out.println("Sra. "+nombre);
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public Integer getEdad() {
return edad;
}
public void setEdad(Integer edad) {
this.edad = edad;
}
public Sexo getGenero() {
return genero;
}
public void setGenero(Sexo genero) {
this.genero = genero;
}
}
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
public class FiltroLambda {
interface VerificarPersona {
boolean verificar(Persona p);
}
public static void imprimirPersonas(
List<Persona> grupo, VerificarPersona filtro) {
for (Persona p : grupo) {
if (filtro.verificar(p)) {
System.out.println(p.nombre);
}
}
}
public static void imprimirPersonasPredicado (
List<Persona> grupo, Predicate<Persona> filtro) {
for (Persona p : grupo) {
if (filtro.test(p)) {
System.out.println(p.nombre);
}
}
}
public static void procesarPersonas(
List<Persona> grupo,
Predicate<Persona> filtro,
Consumer<Persona> bloque) {
for (Persona p : grupo) {
if (filtro.test(p)) {
bloque.accept(p);
}
}
}
public static void procesarPersonasConFunciones(
List<Persona> grupo,
Predicate<Persona> filtro,
Function<Persona, String> mapper,
Consumer<String> bloque
) {
for (Persona p : grupo) {
if (filtro.test(p)) {
String data = mapper.apply(p);
bloque.accept(data);
}
}
}
public static void main(String[] args) {
List<Persona> listaPersonas= new ArrayList<>();
listaPersonas.add(new Persona("Juan", 12, Persona.Sexo.MASCULINO));
listaPersonas.add(new Persona("Maria", 14, Persona.Sexo.FEMENINO));
listaPersonas.add(new Persona("Pedro", 45, Persona.Sexo.MASCULINO));
listaPersonas.add(new Persona("Martin", 21, Persona.Sexo.MASCULINO));
listaPersonas.add(new Persona("Adriana", 16, Persona.Sexo.FEMENINO));
listaPersonas.add(new Persona("Natalia", 27, Persona.Sexo.FEMENINO));
imprimirPersonas(
listaPersonas,
(Persona p) -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18
);
imprimirPersonas(
listaPersonas,
(Persona p) -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16
);
imprimirPersonasPredicado (
listaPersonas,
p -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18
);
imprimirPersonasPredicado (
listaPersonas,
p -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16
);
procesarPersonas(
listaPersonas,
p -> p.getGenero() == Persona.Sexo.MASCULINO
&& p.getEdad() >= 18,
p -> p.imprimirHombre()
);
procesarPersonas(
listaPersonas,
p -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16,
p -> p.imprimirMujer()
);
procesarPersonasConFunciones(listaPersonas,
p -> p.getGenero() == Persona.Sexo.FEMENINO
&& p.getEdad() <16,
p -> p.nombreGenero(),
genero -> System.out.println(genero));
}
}
class Persona{
enum Sexo {
MASCULINO,
FEMENINO
}
String nombre;
Integer edad;
Sexo genero;
public Persona(String nombre, Integer edad, Sexo genero) {
super();
this.nombre = nombre;
this.edad = edad;
this.genero = genero;
}
public void imprimirHombre() {
System.out.println("Sr. "+nombre);
}
public String nombreGenero(){
return this.genero.name();
}
public void imprimirMujer() {
System.out.println("Sra. "+nombre);
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public Integer getEdad() {
return edad;
}
public void setEdad(Integer edad) {
this.edad = edad;
}
public Sexo getGenero() {
return genero;
}
public void setGenero(Sexo genero) {
this.genero = genero;
}
}
Este es el primer paso con expresiones Lambda, mas adelante seguiré publicando ejemplos mas avanzados, mientras tanto, cuéntanos en los comentarios que te gustaría hacer con expresiones Lambda
Comentarios
Publicar un comentario