0Pricing
Java Academy · Lección

El principio PECS

Producer Extends, Consumer Super

El principio PECS 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é significa PECS

PECS significa Producer Extends, Consumer Super. Es una regla mnemotécnica de Effective Java, de Joshua Bloch.

  • Si un parámetro produce T (usted lo lee), use ? extends T.
  • Si un parámetro consume T (usted escribe en él), use ? super T.
public class Main {
    public static void main(String[] args) {
        System.out.println("Producer Extends, Consumer Super");
    }
}

El método copy canónico

El ejemplo clásico de PECS es un método de copia. El origen produce, por lo que es ? extends T. El destino consume, por lo que es ? super T.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static <T> void copy(List<? extends T> src, List<? super T> dest) {
        for (T t : src) dest.add(t);
    }
    public static void main(String[] args) {
        List<Integer> src = List.of(1, 2, 3);
        List<Object> dest = new ArrayList<>();
        copy(src, dest);
        System.out.println(dest);
    }
}

Por qué ambos comodines aportan flexibilidad

Gracias a PECS, copy funciona con muchas combinaciones de tipos: un origen Integer en un destino Number u Object, o un origen String en un destino CharSequence.

Sin comodines, los tipos tendrían que coincidir exactamente, lo que limitaría enormemente la reutilización.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static <T> void copy(List<? extends T> src, List<? super T> dest) {
        for (T t : src) dest.add(t);
    }
    public static void main(String[] args) {
        List<Integer> ints = List.of(10, 20);
        List<Number> nums = new ArrayList<>();
        copy(ints, nums);
        System.out.println(nums);
    }
}

Un ejemplo de productor

Un método que solo lee de su colección debería usar extends. Aquí sumamos los elementos de un productor.

import java.util.List;

public class Main {
    static double sum(List<? extends Number> producer) {
        double total = 0;
        for (Number n : producer) total += n.doubleValue();
        return total;
    }
    public static void main(String[] args) {
        System.out.println(sum(List.of(1, 2, 3)));
        System.out.println(sum(List.of(1.1, 2.2)));
    }
}

Un ejemplo de consumidor

Un método que solo escribe en su colección debería usar super. Aquí insertamos valores en un consumidor.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static void pushDigits(List<? super Integer> consumer) {
        for (int i = 0; i < 5; i++) consumer.add(i);
    }
    public static void main(String[] args) {
        List<Number> nums = new ArrayList<>();
        pushDigits(nums);
        System.out.println(nums);
    }
}

Ambos roles: use un tipo simple

Si un parámetro es tanto productor como consumidor, no debería usar un comodín.

Un método que lee y escribe en la misma lista necesita el tipo exacto T.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static <T> void rotate(List<T> list) {
        if (list.isEmpty()) return;
        T last = list.remove(list.size() - 1);
        list.add(0, last);
    }
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
        rotate(list);
        System.out.println(list);
    }
}

PECS en Comparator

El JDK aplica PECS de forma generalizada. Collections.max recibe un Comparator<? super T> porque el comparador consume valores T para compararlos.

import java.util.Comparator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Comparator<Object> byHash = Comparator.comparingInt(Object::hashCode);
        List<String> words = List.of("a", "bb", "ccc");
        String max = java.util.Collections.max(words, byHash);
        System.out.println(max);
    }
}

PECS en Stream.collect

Muchas interfaces funcionales siguen PECS. Un Consumer<? super T> puede aceptar un controlador escrito para un tipo más amplio.

import java.util.List;
import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        Consumer<Object> printer = o -> System.out.println("got: " + o);
        List<String> items = List.of("x", "y");
        items.forEach(printer); // forEach takes Consumer<? super T>
    }
}

Productores y consumidores de Function

Function<? super T, ? extends R> es la forma completa de PECS: la entrada se consume (super) y la salida se produce (extends).

Esto permite que una transformación acepte entradas más amplias y devuelva salidas más específicas.

import java.util.function.Function;

public class Main {
    static <T, R> R apply(Function<? super T, ? extends R> fn, T value) {
        return fn.apply(value);
    }
    public static void main(String[] args) {
        Function<Object, Integer> len = o -> o.toString().length();
        System.out.println(apply(len, "hello"));
    }
}

Tipos de retorno: evite los comodines

No use comodines en los tipos de retorno. Obligan también a quienes llaman al método a trabajar con comodines, lo que expone una complejidad innecesaria.

Devuelva un tipo concreto y mantenga los comodines en los parámetros, donde aportan flexibilidad.

import java.util.ArrayList;
import java.util.List;

public class Main {
    // Good: concrete return type
    static List<Number> doubled(List<? extends Number> src) {
        List<Number> out = new ArrayList<>();
        for (Number n : src) out.add(n.doubleValue() * 2);
        return out;
    }
    public static void main(String[] args) {
        System.out.println(doubled(List.of(1, 2, 3)));
    }
}

Una combinación completa de PECS

Al combinarlo todo: una operación de combinación que lee de dos productores y escribe en un consumidor.

import java.util.ArrayList;
import java.util.List;

public class Main {
    static <T> void merge(List<? extends T> a, List<? extends T> b, List<? super T> out) {
        for (T t : a) out.add(t);
        for (T t : b) out.add(t);
    }
    public static void main(String[] args) {
        List<Integer> a = List.of(1, 2);
        List<Integer> b = List.of(3, 4);
        List<Number> out = new ArrayList<>();
        merge(a, b, out);
        System.out.println(out);
    }
}

Comprobación rápida

Aplique la regla PECS.

Resumen

Ha aprendido el principio PECS:

  • Producer Extends: los parámetros de solo lectura usan ? extends T.
  • Consumer Super: los parámetros de solo escritura usan ? super T.
  • Los parámetros con ambos roles usan un parámetro de tipo simple.
  • Evite los comodines en los tipos de retorno.

A continuación, aplicaremos estas ideas al diseño de API reales.

public class Main {
    public static void main(String[] args) {
        System.out.println("PECS recap: Producer Extends, Consumer Super");
    }
}

Preguntas frecuentes

¿La lección «El principio PECS» es gratis?

Sí — el texto completo de «El principio PECS» 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 «El principio PECS»?

Producer Extends, Consumer Super 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 «El principio PECS»?

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. Wildcards con límite superior
  2. Wildcards con límite inferior
  3. El principio PECS
  4. Wildcards en APIs
← Volver a Java Academy