Di loket pelayanan pelanggan, orang yang datang lebih dulu dilayani lebih dulu — aturan sederhana yang oleh ilmu komputer dinamai FIFO (first-in, first-out). Interface Queue membawa aturan tersebut ke dalam Collections Framework sebagai cabang tersendiri: elemen dimasukkan lewat ekor antrean dan dikeluarkan lewat kepalanya, sehingga urutan keluar selalu sama dengan urutan masuk. Berbeda dari List yang bisa diakses di posisi mana pun, Queue sengaja membatasi pintu aksesnya agar niat “antrean” terlihat jelas di dalam kode. Pada Chapter ini kita bedah kontrak Queue, kenali dua keluarga method-nya yang tampak kembar namun berperilaku berbeda, lalu membuktikan semuanya dengan antrean layanan sungguhan.

Kontrak Antrean FIFO #

Queue mewarisi seluruh kontrak Collection — tetap bisa size, contains, isEmpty, dan diiterasi — kemudian menambahkan operasi khas antrean pada dua titik istimewa: kepala (elemen yang akan keluar berikutnya) dan ekor (tempat penyisipan baru). Pada antrean FIFO murni seperti ArrayDeque yang kita pakai sebagai Queue, penyisipan selalu terjadi di ekor dan pengambilan di kepala; ArrayDeque, LinkedList, dan PriorityQueue adalah tiga implementasi Queue yang paling umum, dengan PriorityQueue sebagai pengecualian aturan FIFO karena mengurutkan keluaran berdasarkan prioritas (Chapter khusus membahasnya).

Satu keputusan desain membuat Queue istimewa: hampir setiap operasi tersedia dalam dua bentuk. Bentuk pertama melempar Exception ketika operasi gagal; bentuk kedua mengembalikan nilai khusus (false atau null) tanpa mengganggu alur program. Tabel berikut merangkum keenam method tersebut:

AksiBentuk exceptionBentuk nilai khusus
Menyisipkan elemenadd(e) → IllegalStateExceptionoffer(e) → false
Mengambil & menghapus kepalaremove() → NoSuchElementExceptionpoll() → null
Melihat kepala tanpa menghapuselement() → NoSuchElementExceptionpeek() → null

Untuk penyisipan, perbedaan kedua bentuk baru terlihat pada antrean berkapasitas terbatas: add melempar IllegalStateException saat penuh, sedangkan offer cukup mengembalikan false agar pemanggil memutuskan langkah berikutnya. Untuk pengambilan dan pemeriksaan, perbedaan muncul justru saat antrean kosong — dan inilah yang paling sering dijumpai sehari-hari.

Antrean Layanan dalam Praktik #

Program berikut mengelola antrean pelanggan dengan bentuk nilai khusus (offer, poll, peek), termasuk saat antrean menjadi kosong:

import java.util.*;

public class AntreanLayanan {
    public static void main(String[] args) {
        Queue<String> antrean = new ArrayDeque<>();
        antrean.offer("Budi");
        antrean.offer("Siti");
        antrean.offer("Dewi");
        System.out.println("Isi antrean : " + antrean);

        // peek() melihat kepala antrean tanpa menghapus.
        System.out.println("peek()      : " + antrean.peek());
        System.out.println("Setelah peek: " + antrean);

        // poll() mengambil kepala antrean dan menghapusnya (FIFO).
        System.out.println("poll()      : " + antrean.poll());
        System.out.println("poll()      : " + antrean.poll());
        System.out.println("Sisa        : " + antrean);

        // Antrean sudah kosong: bentuk nilai khusus mengembalikan penanda.
        System.out.println("poll() lagi : " + antrean.poll());
        System.out.println("peek() lagi : " + antrean.peek());
        System.out.println("isEmpty()   : " + antrean.isEmpty());
    }
}

Output yang Dihasilkan:

text
Isi antrean : [Budi, Siti, Dewi]
peek()      : Budi
Setelah peek: [Budi, Siti, Dewi]
poll()      : Budi
poll()      : Siti
Sisa        : [Dewi]
poll() lagi : Dewi
peek() lagi : null
isEmpty()   : true

Mari kita bedah baris-baris pentingnya:

  1. Baris 6-8 (offer(...) tiga kali): Budi, Siti, Dewi masuk lewat ekor antrean. Hasil cetakan [Budi, Siti, Dewi] memperlihatkan urutan kepala-ke-ekor yang sama dengan urutan penyisipan.
  2. Baris 11-12 (peek()): mengembalikan Budi — kepala antrean — tanpa menghapusnya; cetakan berikutnya membuktikan isi antrean masih utuh tiga orang.
  3. Baris 15-17 (poll() dua kali): poll mengambil kepala dan menghapusnya. Budi keluar lebih dulu, disusul Siti — urutan keluar sama persis dengan urutan masuk, inti kontrak FIFO.
  4. Baris 20-22 (poll() dan peek() pada antrean kosong): Dewi terakhir keluar, lalu kedua method mengembalikan null dengan tenang. Tidak ada exception, tidak ada program berhenti — cocok untuk loop yang cukup memeriksa poll() != null atau isEmpty().

Saat Bentuk Exception yang Dibutuhkan #

Lalu kapan bentuk exception lebih tepat? Ketika antrean kosong berarti bug — kondisi yang seharusnya tidak mungkin terjadi dalam alur normal program. Pada kasus demikian, kegagalan keras lebih berguna karena stack trace menunjuk langsung ke baris yang bermasalah. Berkas berikut sengaja memanggil remove() pada antrean kosong:

import java.util.*;

public class AmbilDariKosong {
    public static void main(String[] args) {
        Queue<String> antrean = new ArrayDeque<>();
        System.out.println("Antrean kosong: " + antrean);

        // Bentuk exception: remove() pada antrean kosong melempar error.
        String kepala = antrean.remove();
        System.out.println("Kepala: " + kepala);
    }
}

JVM menghentikan program dengan exception berikut:

text
Exception in thread "main" java.util.NoSuchElementException

Cetak Antrean kosong: [] sempat tampil, lalu antrean.remove() pada baris kesembilan melempar NoSuchElementException sebelum baris cetak Kepala sempat dieksekusi. Perilaku element() serupa — sama-sama membaca kepala antrean, bedanya element() melempar exception saat kosong sedangkan peek() mengembalikan null.

Queue dengan satu kepala dan satu ekor sudah menyelesaikan banyak kasus, tetapi ada situasi yang menuntut lebih: undo/redo yang mendorong dan menarik dari kedua ujung, deck kartu yang bisa diambil dari atas maupun bawah, atau algoritma pencarian yang bekerja dari dua arah. Untuk itu Java menyediakan Deque — perluasan Queue yang membuka kedua ujungnya sekaligus, materi Chapter berikutnya.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

AmbilDariKosong.java

Unduh berkas
java
import java.util.*;

public class AmbilDariKosong {
    public static void main(String[] args) {
        Queue<String> antrean = new ArrayDeque<>();
        System.out.println("Antrean kosong: " + antrean);

        // Bentuk exception: remove() pada antrean kosong melempar error.
        String kepala = antrean.remove();
        System.out.println("Kepala: " + kepala);
    }
}

AntreanLayanan.java

Unduh berkas
java
import java.util.*;

public class AntreanLayanan {
    public static void main(String[] args) {
        Queue<String> antrean = new ArrayDeque<>();
        antrean.offer("Budi");
        antrean.offer("Siti");
        antrean.offer("Dewi");
        System.out.println("Isi antrean : " + antrean);

        // peek() melihat kepala antrean tanpa menghapus.
        System.out.println("peek()      : " + antrean.peek());
        System.out.println("Setelah peek: " + antrean);

        // poll() mengambil kepala antrean dan menghapusnya (FIFO).
        System.out.println("poll()      : " + antrean.poll());
        System.out.println("poll()      : " + antrean.poll());
        System.out.println("Sisa        : " + antrean);

        // Antrean sudah kosong: bentuk nilai khusus mengembalikan penanda.
        System.out.println("poll() lagi : " + antrean.poll());
        System.out.println("peek() lagi : " + antrean.peek());
        System.out.println("isEmpty()   : " + antrean.isEmpty());
    }
}