PECS-prinsippet
Producer Extends, Consumer Super
PECS-prinsippet er en gratis leksjon i Java Academy på CoddyKit. Dette er leksjon 3 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Java Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Java Academy inneholder totalt 4 leksjoner.
Hva PECS står for
PECS betyr Producer Extends, Consumer Super. Det er en huskeregel fra Joshua Blochs Effective Java.
- Hvis en parameter produserer T (De leser fra den), bruker De
? extends T. - Hvis en parameter forbruker T (De skriver til den), bruker De
? super T.
public class Main {
public static void main(String[] args) {
System.out.println("Producer Extends, Consumer Super");
}
}Den kanoniske copy-metoden
Det klassiske PECS-eksempelet er en kopieringsmetode. Kilden produserer, så den er ? extends T. Målet forbruker, så det er ? 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);
}
}Hvorfor begge jokertegnene gir fleksibilitet
Takket være PECS fungerer copy med mange typekombinasjoner: en Integer-kilde til et Number- eller Object-mål, og en String-kilde til et CharSequence-mål.
Uten jokertegn måtte typene samsvare nøyaktig, noe som ville begrenset gjenbruk kraftig.
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);
}
}Et produsenteksempel
En metode som bare leser fra kolleksjonen sin, bør bruke extends. Her summerer vi en produsent.
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)));
}
}Et forbrukereksempel
En metode som bare skriver til kolleksjonen sin, bør bruke super. Her legger vi verdier inn i en forbruker.
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);
}
}Begge roller: bruk en vanlig type
Hvis en parameter både er en produsent og en forbruker, bør den ikke bruke et jokertegn.
En metode som leser og skriver i den samme listen, trenger den eksakte typen 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 i Comparator
JDK bruker PECS overalt. Collections.max tar en Comparator<? super T> fordi komparatoren forbruker T-verdier for å sammenligne dem.
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 i Stream.collect
Mange funksjonelle grensesnitt følger PECS. En Consumer<? super T> kan godta en behandlingsfunksjon som er skrevet for en bredere type.
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>
}
}Funksjoner som produsenter og forbrukere
Function<? super T, ? extends R> er den fullstendige PECS-formen: inndataene forbrukes (super), og utdataene produseres (extends).
Dette lar en transformasjon godta bredere inndata og returnere smalere utdata.
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"));
}
}Returtyper: unngå jokertegn
Ikke bruk jokertegn i returtyper. De tvinger også kallere til å håndtere jokertegn og gjør kompleksiteten synlig utenfor metoden.
Returner en konkret type, og bruk jokertegn på parametere når de gir større fleksibilitet.
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)));
}
}En fullstendig PECS-sammenslåing
La oss samle alt: en sammenslåing som leser fra to produsenter og skriver til én forbruker.
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);
}
}Hurtigsjekk
Bruk PECS-regelen.
Oppsummering
De har lært PECS-prinsippet:
- Producer Extends: skrivebeskyttede parametere bruker
? extends T. - Consumer Super: skriveparametere bruker
? super T. - Parametere med begge roller bruker en vanlig typeparameter.
- Unngå jokertegn i returtyper.
Deretter bruker vi disse ideene på utforming av ekte API-er.
public class Main {
public static void main(String[] args) {
System.out.println("PECS recap: Producer Extends, Consumer Super");
}
}Lær deg Java med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 104
- Leksjoner
- 374
Ofte stilte spørsmål
Er leksjonen «PECS-prinsippet» gratis?
Ja – hele teksten i «PECS-prinsippet» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Java Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Java Academy inneholder totalt 4 leksjoner.
Hva lærer jeg i «PECS-prinsippet»?
Producer Extends, Consumer Super Du øver på Java Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med Java Academy?
Ingen tidligere erfaring er nødvendig. Java Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.
Hvor lang tid tar leksjonen «PECS-prinsippet»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne Java Academy-leksjonen?
Ja. Alle Java Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.