CodeGym /Cursos /JAVA 25 SELF /Method References (::): referencias a métodos

Method References (::): referencias a métodos

JAVA 25 SELF
Nivel 21, Lección 1
Disponible

1. Introducción

Method reference (o, en español, referencia a método) es una sintaxis especial en Java que permite pasar un método ya existente (o un constructor) como implementación de una interfaz funcional. Se puede «pasar» un método allí donde se espera una expresión lambda, si las firmas coinciden.

Sintaxis:

Clase::método
objeto::método
Clase::new

Si una lambda es una mini función «al vuelo», entonces una method reference es simplemente «pasa un método ya existente». Es parecido a, en lugar de copiar una receta, dar el enlace a la página con la receta.

Ejemplo sencillo

En lugar de esto:

list.forEach(s -> System.out.println(s));

Así:

list.forEach(System.out::println);

Se ve conciso, ¿verdad?

2. Tipos de method references

Las referencias a métodos tienen cuatro formas principales. Son estas — y no necesitas nada más.

Referencia a un método estático

Sintaxis: Clase::métodoEstático

Ejemplo:

Function<Integer, String> intToString = String::valueOf;
System.out.println(intToString.apply(123)); // "123"

Lo mismo con una lambda:

Function<Integer, String> intToString = i -> String.valueOf(i);

Referencia a un método no estático de un objeto

Sintaxis: objeto::método

Ejemplo:

PrintStream printer = System.out;
Consumer<String> consumer = printer::println;
consumer.accept("¡Hola, mundo!");

Equivalente a una lambda:

Consumer<String> consumer = s -> printer.println(s);

Referencia a un método no estático de la clase

Sintaxis: Clase::método

Aquí, el primer parámetro de la interfaz funcional se convierte en el objeto sobre el que se invoca el método.

Ejemplo:

Function<String, Integer> stringLength = String::length;
System.out.println(stringLength.apply("Java")); // 4

Aquí String::length se convierte en la función: (String s) -> s.length()

Referencia a un constructor

Sintaxis: Clase::new

Ejemplo:

Supplier<ArrayList<String>> listSupplier = ArrayList::new;
ArrayList<String> list = listSupplier.get();

Equivalente a una lambda:

Supplier<ArrayList<String>> listSupplier = () -> new ArrayList<>();

3. ¿Cuándo usar method reference?

Es útil usar method reference cuando la lambda solo llama a un método existente sin lógica adicional — así el código se vuelve más corto y legible.

Ejemplo: ordenar una lista

En lugar de esto:

List<String> names = Arrays.asList("Iván", "Pedro", "Ana");
names.sort((a, b) -> a.compareToIgnoreCase(b));

Así:

names.sort(String::compareToIgnoreCase);

Ejemplo: procesar colecciones

En lugar de:

list.forEach(s -> System.out.println(s));

Se puede aún más corto:

list.forEach(System.out::println);

Ejemplo: transformar elementos

En lugar de:

List<String> numbers = Arrays.asList("1", "2", "3");
List<Integer> ints = numbers.stream()
    .map(s -> Integer.parseInt(s))
    .collect(Collectors.toList());

Se puede:

List<Integer> ints = numbers.stream()
    .map(Integer::parseInt)
    .collect(Collectors.toList());

Más detalles sobre el Stream API y la clase de utilidades Collectors los verás en el nivel 30 :P

4. Comparación entre method reference y expresiones lambda

Equivalencia

Method reference y una expresión lambda suelen ser intercambiables. Ambas implementan una interfaz funcional si las firmas coinciden.

Ejemplo:

Consumer<String> c1 = s -> System.out.println(s);
Consumer<String> c2 = System.out::println;

¿Cuándo es mejor usar method reference?

  • Cuando la lambda solo llama a un método existente sin lógica adicional.
  • Para mejorar la legibilidad, especialmente en cadenas de llamadas largas.
  • Cuando quieres dejar claro: «aquí solo hay una llamada al método».

¿Cuándo no conviene method reference?

  • Si se necesita lógica adicional (validación, condiciones, gestión de errores).
  • Si hay que transformar los parámetros antes de invocar el método.

Ejemplo:

list.forEach(s -> {
    if (s != null) System.out.println(s);
});
// Aquí no sirve method reference; solo una lambda.

5. Práctica: reescribimos expresiones lambda usando method references

Ejemplo 1: imprimimos nombres de animales

List<String> animals = Arrays.asList("Gato", "Perro", "Loro");
animals.forEach(animal -> System.out.println(animal));

Se convierte en:

animals.forEach(System.out::println);

Ejemplo 2: convertimos cadenas en números

List<String> numbers = Arrays.asList("10", "20", "30");
List<Integer> ints = numbers.stream()
    .map(s -> Integer.parseInt(s))
    .collect(Collectors.toList());

Se convierte en:

List<Integer> ints = numbers.stream()
    .map(Integer::parseInt)
    .collect(Collectors.toList());

Ejemplo 3: ordenar objetos por nombre

List<Animal> animalList = ...;
animalList.sort((a, b) -> a.getName().compareTo(b.getName()));

Se convierte en:

animalList.sort(Comparator.comparing(Animal::getName));

Aquí Animal::getName es una referencia a un método no estático de la clase.

Ejemplo 4: crear objetos a través del constructor

Supplier<Dog> dogFactory = () -> new Dog();
Dog dog = dogFactory.get();

Se convierte en:

Supplier<Dog> dogFactory = Dog::new;
Dog dog = dogFactory.get();

6. Cómo funciona la correspondencia de firmas

Una method reference solo se puede usar cuando la firma del método coincide con el método abstracto de la interfaz funcional.

@FunctionalInterface
interface IntToString {
    String convert(int value);
}

public class Demo {
    public static String intToHex(int value) {
        return Integer.toHexString(value);
    }

    public static void main(String[] args) {
        IntToString converter = Demo::intToHex;
        System.out.println(converter.convert(255)); // ff
    }
}

Aquí Demo::intToHex encaja porque recibe un int y devuelve un String.

7. Method reference y constructores con parámetros

Si el constructor recibe parámetros, se puede seguir usando una method reference — siempre que las firmas coincidan.

@FunctionalInterface
interface AnimalFactory {
    Animal create(String name);
}

class Animal {
    private String name;
    public Animal(String name) { this.name = name; }
    public String getName() { return name; }
}

AnimalFactory factory = Animal::new;
Animal cat = factory.create("Kitty");
System.out.println(cat.getName()); // Kitty

8. Errores típicos al usar method references

Error n.º 1: Incompatibilidad de firmas.
Si la firma del método no coincide con el método abstracto de la interfaz, el compilador dará error. Por ejemplo, la interfaz espera dos parámetros, pero la referencia apunta a un método con un solo parámetro.

Error n.º 2: Intentar usar una referencia a un método no estático de clase sin un objeto.
Cuando se usa la forma Clase::método, el primer parámetro de la interfaz se convierte en el objeto de la llamada. Si confundes la cantidad o el orden de los parámetros, obtendrás un error de correspondencia.

Error n.º 3: Usar una method reference donde se necesita lógica adicional.
Si se requiere una condición, registro (logging) u otra gestión de excepciones, usa una lambda, no una referencia a método.

Error n.º 4: Referencias a métodos sobrecargados.
Si una clase tiene varios métodos con el mismo nombre, el compilador puede no saber cuál elegir. A veces ayuda indicar explícitamente el tipo de la interfaz funcional.

Error n.º 5: Usar una referencia a un método no estático sin un objeto.
Por ejemplo, String::toUpperCase funciona correctamente en map, porque el primer parámetro es el propio objeto String. Pero fuera de un contexto adecuado donde se espera un método estático, esto llevará a un error.

1
Tarea
JAVA 25 SELF, nivel 21, lección 1
Bloqueada
Convertidor de identificadores de dispositivos 📟
Convertidor de identificadores de dispositivos 📟
1
Tarea
JAVA 25 SELF, nivel 21, lección 1
Bloqueada
Sistema de registro personalizado 📝
Sistema de registro personalizado 📝
1
Tarea
JAVA 25 SELF, nivel 21, lección 1
Bloqueada
Organización del inventario en el almacén 🍎🍌🍐
Organización del inventario en el almacén 🍎🍌🍐
1
Tarea
JAVA 25 SELF, nivel 21, lección 1
Bloqueada
Fábrica de mascotas virtuales 🐾
Fábrica de mascotas virtuales 🐾
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION