Java

Tutorial Java: Funciones lambda

Java funciones lambda: uso y ejemplos. Aprende a usar funciones lambda en Java con ejemplos prácticos y detallados.

Java SE, como lenguaje de programación, siempre ha sido conocido por su orientación a objetos. Sin embargo, con la introducción de Java 8, se agregaron varios conceptos de programación funcional, incluidas las funciones lambda. Las funciones lambda son una adición significativa que permite un nuevo estilo de programación en Java.

Introducción a las Funciones Lambda

Las funciones lambda, también conocidas como cierres, son una característica importante de la programación funcional y se introdujeron en Java en su versión 8. Permiten definir métodos anónimos, es decir, métodos sin nombre que pueden ser utilizados para implementar una interfaz funcional, una interfaz con un solo método abstracto.

La sintaxis de una función lambda en Java es la siguiente:

(parametro1, parametro2, ...) -> { cuerpo de la funcion }

Donde:

  • Los parámetros se escriben entre paréntesis y separados por comas.
  • La flecha -> separa los parámetros del cuerpo de la función.
  • El cuerpo de la función puede contener cualquier cantidad de sentencias y se encierra entre llaves.

Por ejemplo, se puede definir una función lambda para implementar una interfaz funcional Runnable de la siguiente manera:

Runnable r = () -> System.out.println("Hola mundo!");

¿Por qué se necesitan las funciones lambda?

Las funciones lambda ayudan a simplificar el código y facilitan la programación funcional en Java. A menudo se utilizan para implementar interfaces funcionales de una manera más concisa y legible que las clases anónimas. Además, las funciones lambda se pueden pasar como argumentos a métodos o almacenar en variables, lo que permite tratar la funcionalidad como si fuera un tipo de dato.

Por ejemplo, considere la interfaz Comparator de Java que tiene un único método compare. Sin las funciones lambda, tendríamos que implementar la interfaz utilizando una clase anónima de la siguiente manera:

Comparator<String> comparator = new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }
};

Con las funciones lambda, la implementación se simplifica considerablemente:

Comparator<String> comparator = (s1, s2) -> Integer.compare(s1.length(), s2.length());

Las funciones lambda son especialmente útiles en el contexto de las nuevas Streams API y las operaciones de colección paralela en Java 8, ya que permiten definir de manera concisa el comportamiento de las operaciones a realizar.

Tipos de Funciones Lambda

Las funciones lambda en Java pueden ser de diferentes tipos, dependiendo de sus parámetros y su valor de retorno.

  1. Funciones lambda sin parámetros y sin retorno: Estas son funciones que no aceptan ningún parámetro y no devuelven ningún valor. Corresponden a las interfaces funcionales que tienen un método que no toma argumentos y tiene un tipo de retorno void.

    Ejemplo:

    Runnable r = () -> System.out.println("Función lambda sin parámetros y sin retorno.");
    r.run();
    
  2. Funciones lambda con parámetros y sin retorno: Estas funciones aceptan uno o más parámetros, pero no devuelven ningún valor. Corresponden a las interfaces funcionales que tienen un método que toma uno o más argumentos y tiene un tipo de retorno void.

    Ejemplo:

    Consumer<String> c = (s) -> System.out.println("Hola " + s);
    c.accept("mundo");
    
  3. Funciones lambda sin parámetros y con retorno: Estas funciones no aceptan ningún parámetro pero devuelven un valor. Corresponden a las interfaces funcionales que tienen un método que no toma argumentos pero devuelve un valor.

    Ejemplo:

    Supplier<String> s = () -> "Función lambda sin parámetros y con retorno.";
    System.out.println(s.get());
    
  4. Funciones lambda con parámetros y con retorno: Estas funciones aceptan uno o más parámetros y devuelven un valor. Corresponden a las interfaces funcionales que tienen un método que toma uno o más argumentos y devuelve un valor.

    Ejemplo:

    Function<String, Integer> f = (s) -> s.length();
    System.out.println(f.apply("Hola mundo"));
    

Interfaces Funcionales

Las funciones lambda en Java están estrechamente vinculadas a las interfaces funcionales. Una interfaz funcional es una interfaz que tiene exactamente un método abstracto. Aunque puede tener cualquier número de métodos predeterminados o estáticos. Java 8 introdujo varias interfaces funcionales en el paquete java.util.function, como Predicate, Function, Consumer, Supplier, etc.

Las interfaces funcionales se pueden implementar utilizando funciones lambda, lo que permite una mayor flexibilidad y expresividad en la programación.

La interfaz Consumer

La interfaz Consumer representa una operación que acepta un solo argumento de entrada y no devuelve ningún resultado. Su método abstracto es void accept(T t).

Por ejemplo, para imprimir todos los elementos de una lista, podríamos usar una función lambda para implementar un Consumer de la siguiente manera:

List<String> lista = Arrays.asList("Hola", "mundo", "lambda");
Consumer<String> c = (s) -> System.out.println(s);
lista.forEach(c);

La interfaz Predicate

La interfaz Predicate representa una condición (o predicado) que un objeto dado de tipo T puede cumplir. Su método abstracto es boolean test(T t).

Por ejemplo, para filtrar todos los números pares de una lista, podríamos usar una función lambda para implementar un Predicate de la siguiente manera:

List<Integer> lista = Arrays.asList(1, 2, 3, 4, 5, 6);
Predicate<Integer> p = (i) -> i % 2 == 0;
lista.stream().filter(p).forEach(System.out::println);

La interfaz Function

La interfaz Function representa una función que acepta un argumento y produce un resultado. Su método abstracto es R apply(T t).

Por ejemplo, para convertir todos los elementos de una lista en mayúsculas, podríamos usar una función lambda para implementar una Function de la siguiente manera:

List<String> lista = Arrays.asList("hola", "mundo", "lambda");
Function<String, String> f = (s) -> s.toUpperCase();
lista.stream().map(f).forEach(System.out::println);

La interfaz Supplier

La interfaz Supplier representa una operación que no toma ningún argumento pero produce un resultado. Su método abstracto es `T get

()`.

Por ejemplo, para generar una serie de números aleatorios, podríamos usar una función lambda para implementar un Supplier de la siguiente manera:

Supplier<Double> s = () -> Math.random();
Stream.generate(s).limit(5).forEach(System.out::println);

Conclusiones

Las funciones lambda y las interfaces funcionales han traído a Java la capacidad de escribir código de una manera más funcional y declarativa. No solo simplifican el código, sino que también facilitan la programación concurrente y paralela, lo que es fundamental en el mundo de hoy con sus aplicaciones cada vez más demandantes en términos de rendimiento.

Las funciones lambda se utilizan ampliamente en la Streams API, que es una de las principales adiciones a Java 8 para facilitar el procesamiento de conjuntos de datos de manera eficiente y paralela.

Aunque las funciones lambda pueden hacer que el código sea más conciso y fácil de leer, también pueden dificultar el seguimiento del flujo de control si se abusa de ellas. Por lo tanto, siempre es importante usarlas con moderación y mantener en mente las mejores prácticas de programación.

Certifícate en Java con CertiDevs PLUS

Ejercicios de esta lección Funciones lambda

Evalúa tus conocimientos de esta lección Funciones lambda con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Gestión de errores y excepciones

Código

Datos primitivos

Puzzle

Streams: min max

Puzzle

Clases abstractas

Test

Polimorfismo de tiempo de ejecución

Puzzle

Streams: map()

Puzzle

Interfaz funcional Predicate

Puzzle

Llamada y sobrecarga de funciones

Puzzle

ArrayList

Test

Representación de Fecha

Puzzle

Operadores lógicos

Test

OOP en Java

Proyecto

Estructuras de iteración

Puzzle

Objetos

Puzzle

Streams: sorted()

Test

Polimorfismo de tiempo de compilación

Test

Streams: filter()

Puzzle

Métodos referenciados

Test

Métodos de la clase String

Código

Streams: flatMap()

Test

Operadores aritméticos

Puzzle

Streams: match

Test

Interfaz funcional Consumer

Test

Operaciones de Streams

Puzzle

Clases y objetos

Código

API java.nio 2

Puzzle

CRUD en Java de modelo Customer sobre un ArrayList

Proyecto

Interfaces

Código

Streams: distinct()

Puzzle

Representación de Hora

Test

Tipos de variables

Puzzle

Herencia básica

Test

Datos de referencia

Test

Creación de Streams

Test

Interfaz funcional Function

Test

Métodos básicos de la clase String

Test

HashMap

Puzzle

Funciones lambda

Test

Uso de API Optional

Puzzle

Streams: count()

Test

Streams: forEach()

Test

Métodos avanzados de la clase String

Puzzle

Excepciones

Puzzle

Herencia avanzada

Puzzle

Estructuras de selección

Test

Uso de interfaces

Test

Sobrecarga de métodos

Test

API Optional

Test

Tipos de datos

Código

Streams: reduce()

Test

HashSet

Test

Uso de variables

Test

Objeto Scanner

Test

Interfaces funcionales

Puzzle

Configuración de entorno

Test

Clases

Test

Uso de Scanner

Puzzle

Interfaz funcional Supplier

Puzzle

CRUD en Java de modelo Customer sobre un HashMap

Proyecto

Streams: collect()

Puzzle

Instalación

Test

Funciones

Código

Encapsulación

Test

Estructuras de control

Código

Herencia de clases

Código

Funciones y encapsulamiento

Test

Todas las lecciones de Java

Accede a todas las lecciones de Java y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Javascript

JavaScript

Sintaxis

Tipos De Datos

JavaScript

Sintaxis

Variables

JavaScript

Sintaxis

Operadores

JavaScript

Sintaxis

Estructuras De Control

JavaScript

Sintaxis

Funciones

JavaScript

Sintaxis

Funciones Cierre (Closure)

JavaScript

Sintaxis

Funciones Flecha

JavaScript

Programación Funcional

Filtrado Con Filter() Y Find()

JavaScript

Programación Funcional

Transformación Con Map()

JavaScript

Programación Funcional

Reducción Con Reduce()

JavaScript

Programación Funcional

Clases Y Objetos

JavaScript

Programación Orientada A Objetos

Excepciones

JavaScript

Programación Orientada A Objetos

Encapsulación

JavaScript

Programación Orientada A Objetos

Herencia

JavaScript

Programación Orientada A Objetos

Polimorfismo

JavaScript

Programación Orientada A Objetos

Array

JavaScript

Estructuras De Datos

Conjuntos Con Set

JavaScript

Estructuras De Datos

Mapas Con Map

JavaScript

Estructuras De Datos

Manipulación Dom

JavaScript

Dom

Selección De Elementos Dom

JavaScript

Dom

Modificación De Elementos Dom

JavaScript

Dom

Eventos Del Dom

JavaScript

Dom

Callbacks

JavaScript

Programación Asíncrona

Promises

JavaScript

Programación Asíncrona

Async / Await

JavaScript

Programación Asíncrona

Instalación De Java

Introducción Y Entorno

Configuración De Entorno Java

Introducción Y Entorno

Tipos De Datos

Sintaxis

Variables

Sintaxis

Operadores

Sintaxis

Estructuras De Control

Sintaxis

Funciones

Sintaxis

Excepciones

Programación Orientada A Objetos

Clases Y Objetos

Programación Orientada A Objetos

Encapsulación

Programación Orientada A Objetos

Herencia

Programación Orientada A Objetos

Clases Abstractas

Programación Orientada A Objetos

Interfaces

Programación Orientada A Objetos

Sobrecarga De Métodos

Programación Orientada A Objetos

Polimorfismo

Programación Orientada A Objetos

La Clase Scanner

Programación Orientada A Objetos

Métodos De La Clase String

Programación Orientada A Objetos

Funciones Lambda

Programación Funcional

Interfaz Funcional Consumer

Programación Funcional

Interfaz Funcional Predicate

Programación Funcional

Interfaz Funcional Function

Programación Funcional

Interfaz Funcional Supplier

Programación Funcional

Métodos Referenciados

Programación Funcional

Creación De Streams

Programación Funcional

Operaciones Intermedias Con Streams: Map()

Programación Funcional

Operaciones Intermedias Con Streams: Filter()

Programación Funcional

Operaciones Intermedias Con Streams: Flatmap()

Programación Funcional

Operaciones Intermedias Con Streams: Sorted()

Programación Funcional

Operaciones Intermedias Con Streams: Distinct()

Programación Funcional

Operaciones Finales Con Streams: Reduce()

Programación Funcional

Operaciones Finales Con Streams: Collect()

Programación Funcional

Operaciones Finales Con Streams: Foreach()

Programación Funcional

Operaciones Finales Con Streams: Count()

Programación Funcional

Operaciones Finales Con Streams: Min Max

Programación Funcional

Operaciones Finales Con Streams: Match

Programación Funcional

Api Optional

Programación Funcional

Listas

Framework Collections

Conjuntos

Framework Collections

Mapas

Framework Collections

Api Java.nio 2

Entrada Y Salida (Io)

Api Java.time

Api Java.time

Certificados de superación de Java

Supera todos los ejercicios de programación del curso de Java y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender la definición y sintaxis de las funciones lambda en Java.
  2. Aprender a implementar funciones lambda de diferentes tipos.
  3. Conocer la relación entre las funciones lambda y las interfaces funcionales.
  4. Aprender a usar las funciones lambda con las interfaces funcionales estándar de Java: Consumer, Predicate, Function y Supplier.
  5. Entender el uso y beneficios de las funciones lambda en el contexto de la Streams API y la programación paralela.