0Pricing
Java Academy · Lección

Referencias a métodos de instancia arbitraria

Haga referencia a un método de instancia sin especificar el receptor, un uso muy habitual en operaciones de Stream.

Referencias a métodos de instancia arbitraria es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.

¿Qué son las referencias a instancias arbitrarias?

Una referencia a un método de una instancia arbitraria usa ClassName::instanceMethod. En este caso, el primer argumento de la interfaz funcional actúa como receptor: cada elemento se convierte en el objeto sobre el que se invoca el método.

import java.util.*;
import java.util.stream.*;

List<String> names = List.of("alice","bob","carol");

// String::toUpperCase — receiver is each list element
List<String> upper = names.stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());
System.out.println(upper); // [ALICE, BOB, CAROL]

Cómo se resuelve el receptor

En una referencia a una instancia arbitraria Type::method, el primer parámetro de la interfaz funcional se convierte en this (el receptor):

// String::length matches Function<String, Integer>
// Equivalent to: s -> s.length()
Function<String, Integer> len = String::length;
System.out.println(len.apply("Java")); // 4

// String::isEmpty matches Predicate<String>
// Equivalent to: s -> s.isEmpty()
Predicate<String> isEmpty = String::isEmpty;
System.out.println(isEmpty.test(""));   // true

Uso frecuente con operaciones de flujo

Las referencias a instancias arbitrarias son el tipo más común en las canalizaciones de flujos:

List<String> words = List.of("Hello","","World","","Java");

// filter with String::isEmpty
long empty = words.stream().filter(String::isEmpty).count();
System.out.println(empty); // 2

// map with String::toLowerCase
words.stream()
     .filter(s -> !s.isEmpty())
     .map(String::toLowerCase)
     .forEach(System.out::println);

Estilo BiFunction con métodos de dos argumentos

Un método de dos argumentos de un tipo coincide con BiFunction<T, U, R>, donde T es el receptor y U es el argumento:

import java.util.function.*;

// String::startsWith → BiPredicate<String, String>
// receiver=first arg, argument=second arg
BiPredicate<String, String> starts = String::startsWith;
System.out.println(starts.test("JavaStream", "Java")); // true
System.out.println(starts.test("Python", "Java"));      // false

Comparator con una instancia arbitraria

String::compareTo coincide con Comparator<String>: los dos argumentos del comparador se convierten en el receptor y el parámetro:

List<String> words = List.of("banana","apple","cherry");

List<String> sorted = words.stream()
    .sorted(String::compareTo)
    .collect(Collectors.toList());
System.out.println(sorted); // [apple, banana, cherry]

Instancia arbitraria de una clase personalizada

Funciona con los métodos de instancia de cualquier clase, no solo con los tipos del JDK:

record Product(String name, double price) {
    boolean isExpensive() { return price > 50; }
    String label() { return name + " ($" + price + ")"; }
}

List<Product> products = List.of(
    new Product("Widget", 9.99),
    new Product("Gadget", 99.99),
    new Product("Donut", 1.50)
);

products.stream()
    .filter(Product::isExpensive)
    .map(Product::label)
    .forEach(System.out::println); // Gadget ($99.99)

Diferencia con una instancia específica

La diferencia clave:

  • Específica: obj::method — obj siempre es el receptor
  • Arbitraria: Type::method — cada elemento ES el receptor
String fixed = "prefix";
// Specific instance: fixed is always the receiver
Predicate<String> startsFixed = fixed::startsWith; // always checks 'prefix'.startsWith(arg)

// Arbitrary instance: each element is the receiver
Predicate<String> isEmpty = String::isEmpty; // each element.isEmpty()

Referencias a métodos en collectors

Las referencias a instancias arbitrarias se combinan de forma natural con los collectors:

List<String> items = List.of("  hello "," world ","  java  ");
List<String> trimmed = items.stream()
    .map(String::trim)
    .collect(Collectors.toList());
System.out.println(trimmed); // [hello, world, java]

Encadenamiento de referencias a métodos

Las referencias a métodos se pueden encadenar con andThen/compose en Function:

Function<String, String> pipeline =
    ((Function<String, String>) String::trim)
        .andThen(String::toUpperCase);

System.out.println(pipeline.apply("  hello world  "));
// HELLO WORLD

Problema frecuente: métodos sobrecargados

Cuando un método está sobrecargado, el compilador debe inferir qué sobrecarga coincide con la interfaz funcional. Si hay ambigüedad, se produce un error de compilación; use una lambda para resolverla:

// println is overloaded — which one?
// Consumer<String> c = System.out::println; // OK — infers println(String)
// Consumer<Object> c2 = System.out::println; // OK

// But if ambiguous:
// Function<Object,?> fn = System.out::println; // Error — println doesn't return a value

Rendimiento

Las referencias a métodos y las lambdas se compilan en el mismo bytecode (mediante invokedynamic). No hay ninguna diferencia de rendimiento; elija la opción más legible. La mayoría de las guías de estilo prefieren las referencias a métodos cuando expresan claramente la intención.

Comprobación rápida

¿Qué representa String::toUpperCase cuando se usa con .map()?

Resumen: referencias a métodos de instancias arbitrarias

Aspectos clave:

  • Sintaxis: ClassName::instanceMethod — cada elemento es el receptor
  • Coincide con interfaces funcionales cuyo primer parámetro es el receptor
  • Son más comunes en .map(), .filter(), .sorted() y .forEach()
  • Métodos de dos argumentos → BiFunction/BiPredicate con el elemento como receptor
  • No hay diferencia de rendimiento frente a una lambda; elija según la legibilidad

Preguntas frecuentes

¿La lección «Referencias a métodos de instancia arbitraria» es gratis?

Sí — el texto completo de «Referencias a métodos de instancia arbitraria» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Referencias a métodos de instancia arbitraria»?

Haga referencia a un método de instancia sin especificar el receptor, un uso muy habitual en operaciones de Stream. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Java Academy?

No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Referencias a métodos de instancia arbitraria»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Java Academy?

Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Referencias a métodos estáticos
  2. Referencias a métodos de instancia específica
  3. Referencias a métodos de instancia arbitraria
  4. Referencias a constructores
← Volver a Java Academy