0Pricing
Java Academy · Lektion

Das PECS-Prinzip

Producer Extends, Consumer Super

Das PECS-Prinzip ist eine kostenlose Java Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Java Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.

Wofür PECS steht

PECS steht für Producer Extends, Consumer Super. Es handelt sich um eine Merkhilfe aus Joshua Blochs Effective Java.

  • Wenn ein Parameter T produziert (Sie lesen daraus), verwenden Sie ? extends T.
  • Wenn ein Parameter T konsumiert (Sie schreiben hinein), verwenden Sie ? super T.
public class Main {
    public static void main(String[] args) {
        System.out.println("Producer Extends, Consumer Super");
    }
}

Die kanonische copy-Methode

Das klassische PECS-Beispiel ist eine Kopiermethode. Die Quelle produziert, daher verwendet sie ? extends T. Das Ziel konsumiert, daher verwendet 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);
    }
}

Warum beide Wildcards Flexibilität schaffen

Dank PECS funktioniert copy mit vielen Typkombinationen: eine Integer-Quelle in ein Number- oder Object-Ziel, eine String-Quelle in ein CharSequence-Ziel.

Ohne Wildcards müssten die Typen exakt übereinstimmen, was die Wiederverwendbarkeit stark einschränken würde.

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);
    }
}

Ein Beispiel für einen Produzenten

Eine Methode, die nur aus ihrer Sammlung liest, sollte extends verwenden. Hier summieren wir einen Produzenten.

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)));
    }
}

Ein Beispiel für einen Konsumenten

Eine Methode, die nur in ihre Sammlung schreibt, sollte super verwenden. Hier schreiben wir Werte in einen Konsumenten.

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);
    }
}

Beide Rollen: Verwenden Sie einen einfachen Typ

Wenn ein Parameter sowohl Produzent als auch Konsument ist, sollte er keine Wildcard verwenden.

Eine Methode, die dieselbe Liste liest und beschreibt, benötigt den exakten Typ 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 in Comparator

Das JDK wendet PECS durchgängig an. Collections.max akzeptiert einen Comparator<? super T>, weil der Comparator T-Werte konsumiert, um sie zu vergleichen.

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 in Stream.collect

Viele funktionale Schnittstellen folgen PECS. Ein Consumer<? super T> kann einen Handler akzeptieren, der für einen allgemeineren Typ geschrieben wurde.

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>
    }
}

Function als Produzent und Konsument

Function<? super T, ? extends R> ist die vollständige PECS-Form: Die Eingabe wird konsumiert (super), die Ausgabe wird produziert (extends).

Dadurch kann eine Transformation allgemeinere Eingaben akzeptieren und speziellere Ausgaben zurückgeben.

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"));
    }
}

Rückgabetypen: Vermeiden Sie Wildcards

Verwenden Sie keine Wildcards in Rückgabetypen. Dadurch müssen sich auch die Aufrufer mit Wildcards auseinandersetzen, was die Komplexität nach außen trägt.

Geben Sie einen konkreten Typ zurück und verwenden Sie Wildcards bei Parametern, wenn sie die Flexibilität erhöhen.

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)));
    }
}

Eine vollständige PECS-Zusammenführung

Zusammengeführt sieht das so aus: Eine Zusammenführung liest aus zwei Produzenten und schreibt in einen Konsumenten.

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);
    }
}

Kurzer Test

Wenden Sie die PECS-Regel an.

Zusammenfassung

Sie haben das PECS-Prinzip kennengelernt:

  • Producer Extends: Nur lesbare Parameter verwenden ? extends T.
  • Consumer Super: Nur schreibbare Parameter verwenden ? super T.
  • Parameter mit beiden Rollen verwenden einen einfachen Type-Parameter.
  • Vermeiden Sie Wildcards in Rückgabetypen.

Als Nächstes wenden Sie diese Ideen auf den Entwurf echter APIs an.

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

Häufig gestellte Fragen

Ist die Lektion „Das PECS-Prinzip“ kostenlos?

Ja — der vollständige Text von „Das PECS-Prinzip“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Java Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Java Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Das PECS-Prinzip“?

Producer Extends, Consumer Super Du übst Java Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Java Academy zu starten?

Keine Vorkenntnisse erforderlich. Java Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Das PECS-Prinzip“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Java Academy-Lektion Code schreiben und ausführen?

Ja. Jede Java Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Wildcards mit oberer Schranke
  2. Wildcards mit unterer Schranke
  3. Das PECS-Prinzip
  4. Wildcards in APIs
← Zurück zu Java Academy