Prinsip PECS
Producer Extends, Consumer Super.
Prinsip PECS adalah pelajaran Java Academy gratis di CoddyKit. Ini adalah pelajaran 3 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Java Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Java Academy mencakup 4 pelajaran total.
Kepanjangan PECS
PECS berarti Producer Extends, Consumer Super. Ini adalah mnemonik dari buku Effective Java karya Joshua Bloch.
- Jika suatu parameter menghasilkan T (Anda membacanya), gunakan
? extends T. - Jika suatu parameter mengonsumsi T (Anda menulis ke dalamnya), gunakan
? super T.
public class Main {
public static void main(String[] args) {
System.out.println("Producer Extends, Consumer Super");
}
}Metode copy Kanonis
Contoh PECS klasik adalah metode copy. Sumber menghasilkan, jadi tipenya adalah ? extends T. Tujuan mengonsumsi, jadi tipenya adalah ? 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);
}
}Mengapa Kedua Karakter Pengganti Menambah Fleksibilitas
Berkat PECS, copy dapat digunakan untuk banyak kombinasi tipe: sumber bilangan bulat ke tujuan Number atau Object, serta sumber String ke tujuan CharSequence.
Tanpa karakter pengganti, tipe-tipe tersebut harus sama persis, sehingga penggunaan ulang menjadi sangat terbatas.
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);
}
}Contoh Produsen
Metode yang hanya membaca dari koleksinya harus menggunakan extends. Di sini kita menjumlahkan sebuah produsen.
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)));
}
}Contoh Konsumen
Metode yang hanya menulis ke koleksinya harus menggunakan super. Di sini kita mendorong nilai ke dalam konsumen.
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);
}
}Kedua Peran: Gunakan Tipe Biasa
Jika suatu parameter berperan sebagai produsen sekaligus konsumen, parameter tersebut tidak boleh menggunakan karakter pengganti.
Metode yang membaca dan menulis daftar yang sama memerlukan tipe T yang tepat.
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 dalam Comparator
JDK menerapkan PECS secara luas. Collections.max menerima Comparator<? super T> karena pembanding mengonsumsi nilai T untuk membandingkannya.
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 dalam Stream.collect
Banyak antarmuka fungsional mengikuti PECS. Consumer<? super T> dapat menerima penangan yang ditulis untuk tipe yang lebih luas.
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>
}
}Produsen dan Konsumen Function
Function<? super T, ? extends R> adalah bentuk PECS lengkap: input dikonsumsi (super), sedangkan output dihasilkan (extends).
Dengan demikian, transformasi dapat menerima input yang lebih luas dan mengembalikan output yang lebih sempit.
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"));
}
}Tipe Pengembalian: Hindari Karakter Pengganti
Jangan gunakan karakter pengganti dalam tipe pengembalian. Karakter ini memaksa pemanggil untuk menangani karakter pengganti juga, sehingga kerumitan tersebar keluar.
Kembalikan tipe konkret dan pertahankan karakter pengganti pada parameter jika hal itu membantu fleksibilitas.
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)));
}
}Penggabungan PECS Lengkap
Menggabungkan semuanya: operasi merge yang membaca dari dua produsen ke dalam satu konsumen.
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);
}
}Pemeriksaan Singkat
Terapkan aturan PECS.
Ringkasan
Anda telah mempelajari prinsip PECS:
- Producer Extends: parameter hanya-baca menggunakan
? extends T. - Consumer Super: parameter hanya-tulis menggunakan
? super T. - Parameter dengan kedua peran menggunakan parameter tipe biasa.
- Hindari karakter pengganti dalam tipe pengembalian.
Selanjutnya, terapkan gagasan ini pada rancangan API nyata.
public class Main {
public static void main(String[] args) {
System.out.println("PECS recap: Producer Extends, Consumer Super");
}
}Pertanyaan yang Sering Diajukan
Apakah pelajaran “Prinsip PECS” gratis?
Ya — teks lengkap “Prinsip PECS” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Java Academy, upgrade ke CoddyKit PRO. Kursus Java Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Prinsip PECS”?
Producer Extends, Consumer Super. Kamu berlatih Java Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai Java Academy?
Tidak diperlukan pengalaman sebelumnya. Java Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 3 dari 4.
Berapa lama pelajaran “Prinsip PECS” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran Java Academy ini?
Ya. Setiap pelajaran Java Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.