Sepanjang Section ini kita memilih struktur, mengelola urutan, dan menjaga keunikan — namun banyak pekerjaan sehari-hari dengan collection justru berbentuk operasi satu kali: urutkan daftar ini, balik urutannya, hitung berapa kali satu nilai muncul, acak urutan kartu. Daripada menulis loop manual untuk setiap tugas itu, pustaka Java menyediakan dua class perkakas: Collections berisi puluhan static method yang bekerja pada collection apa pun, dan Arrays menjadi pasangannya untuk array mentah. Pada Chapter ini kita berkeliling method yang paling sering dipakai, membuktikan bahwa binarySearch punya aturan pakai yang keras, dan menunjukkan bahwa bahkan pengacakan pun bisa dibuat terulang secara presisi.

Class Collections sebagai Kotak Perkakas #

Seluruh method Collections adalah static method yang menerima collection sebagai argumen — tidak ada yang perlu di-new. Program berikut merangkai delapan operasi inti pada satu ArrayList<Integer> yang sama sehingga efek tiap operasi terlihat berurutan:

import java.util.*;

public class OperasiDasar {
    public static void main(String[] args) {
        List<Integer> data = new ArrayList<>(List.of(45, 12, 89, 33, 7));
        System.out.println("awal         : " + data);

        Collections.sort(data);
        System.out.println("sort         : " + data);

        Collections.reverse(data);
        System.out.println("reverse      : " + data);

        Collections.swap(data, 0, 4);
        System.out.println("swap(0, 4)   : " + data);

        Collections.replaceAll(data, 33, 30);
        System.out.println("replaceAll   : " + data);

        Collections.addAll(data, 50, 60);
        System.out.println("addAll       : " + data);

        List<Integer> pola = Collections.nCopies(3, 0);
        System.out.println("nCopies(3, 0): " + pola);

        Collections.fill(data, 0);
        System.out.println("fill(0)      : " + data);
    }
}

Output yang Dihasilkan:

text
awal         : [45, 12, 89, 33, 7]
sort         : [7, 12, 33, 45, 89]
reverse      : [89, 45, 33, 12, 7]
swap(0, 4)   : [7, 45, 33, 12, 89]
replaceAll   : [7, 45, 30, 12, 89]
addAll       : [7, 45, 30, 12, 89, 50, 60]
nCopies(3, 0): [0, 0, 0]
fill(0)      : [0, 0, 0, 0, 0, 0, 0]

Poin bedahnya:

  1. Baris 7-9 (sort lalu reverse): sort menyusun menaik memakai urutan alami elemen (Integer.compare); untuk urutan lain, Collections.sort(data, comparator) menerima Comparator sebagaimana dibahas pada Chapter Comparable dan Comparator. reverse sekadar membalik posisi — jadi sort + reverse adalah cara singkat memperoleh urutan menurun.
  2. Baris 13-14 (swap dan replaceAll): swap(data, 0, 4) menukar dua posisi berdasarkan indeks, sedangkan replaceAll mengganti setiap kemunculan nilai 33 dengan 30 — penggantian massal tanpa loop.
  3. Baris 18-19 (addAll dan nCopies): addAll menerima varargs sehingga beberapa elemen bisa masuk dalam satu panggilan; nCopies(3, 0) membuat list immutable berisi tiga elemen 0 — objek yang sama dirujuk tiga kali, murah untuk dipakai sebagai nilai pengisi awal.
  4. Baris 23-24 (fill): menimpa seluruh isi dengan satu nilai. Karena fill mengubah list di tempat, ia hanya menerima list mutable — Collections.fill(List.of(1, 2), 0) berakhir dengan UnsupportedOperationException.

Statistik Cepat dan Pencarian Biner #

Kelompok kedua menjawab pertanyaan tanpa mengubah data: berapa frekuensi sebuah nilai, apakah dua collection saling lepas, di mana nilai terbesar dan terkecil, serta di posisi mana sebuah nilai berada pada list terurut:

import java.util.*;

public class StatistikDanPencarian {
    public static void main(String[] args) {
        List<Integer> data = new ArrayList<>(List.of(12, 7, 45, 12, 89, 7, 12));

        System.out.println("frequency(12) : " + Collections.frequency(data, 12));
        System.out.println("frequency(99) : " + Collections.frequency(data, 99));

        List<Integer> hadiah = List.of(100, 200);
        System.out.println("disjoint       : " + Collections.disjoint(data, hadiah));

        System.out.println("max            : " + Collections.max(data));
        System.out.println("min            : " + Collections.min(data));
        System.out.println("max (reverse)  : " + Collections.max(data, Comparator.reverseOrder()));

        List<String> nama = List.of("Budi", "Siti", "Dewi", "Anton");
        System.out.println("max nama       : " + Collections.max(nama));
        System.out.println("min nama       : " + Collections.min(nama));

        // binarySearch menuntut list yang sudah terurut menaik.
        List<Integer> terurut = new ArrayList<>(data);
        Collections.sort(terurut);
        System.out.println("terurut        : " + terurut);
        System.out.println("cari 45        : " + Collections.binarySearch(terurut, 45));
        System.out.println("cari 20        : " + Collections.binarySearch(terurut, 20));
    }
}

Output yang Dihasilkan:

text
frequency(12) : 3
frequency(99) : 0
disjoint       : true
max            : 89
min            : 7
max (reverse)  : 7
max nama       : Siti
min nama       : Anton
terurut        : [7, 7, 12, 12, 12, 45, 89]
cari 45        : 5
cari 20        : -6

Poin bedahnya:

  1. Baris 8-9 (frequency): menghitung kemunculan 12 menghasilkan 3 — pekerjaan yang manual menuntut satu loop penuh, di sini menjadi satu panggilan.
  2. Baris 12 (disjoint): mengembalikan true karena tidak ada elemen yang sama antara data dan hadiah — berguna untuk memeriksa dua kelompok yang seharusnya tidak saling bersinggungan; false berarti ada minimal satu elemen bersama.
  3. Baris 14-17 (max/min): tanpa Comparator, keduanya memakai urutan alami; varian dua argumen menerima Comparator — max(data, Comparator.reverseOrder()) menghasilkan 7, membuktikan bahwa “terbesar” mengikuti definisi urutan yang kita pasang. max/min juga bekerja pada Collection apa pun, bukan hanya List.
  4. Baris 25-27 (binarySearch): pencarian biner membelah wilayah pencarian menjadi dua pada setiap langkah sehingga berbiaya O(log n). Menemukan 45 menghasilkan indeks 5; tidak menemukan 20 menghasilkan -6 — bukan sekadar false. Angka negatif itu adalah kode: -(titikSisip) - 1, sehingga -6 berarti 20 akan disisipkan pada indeks 5 (di antara 12 dan 45) bila kita ingin memasukkannya sambil menjaga list tetap terurut.

Acak yang Terkendali #

Collections.shuffle(list) mengacak urutan dengan sumber acak bawaan. Panggilan yang sama dengan argumen kedua — objek Random ber-seed tetap — menghasilkan pengacakan yang selalu identik, karena algoritma java.util.Random ditetapkan dalam spesifikasi Java sehingga seed yang sama menghasilkan deretan angka yang sama di semua JVM:

import java.util.*;

public class AcakTerkendali {
    public static void main(String[] args) {
        List<Integer> data = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 8));

        Collections.shuffle(data, new Random(42));
        System.out.println("shuffle seed 42 (pertama): " + data);

        List<Integer> salinan = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 8));
        Collections.shuffle(salinan, new Random(42));
        System.out.println("shuffle seed 42 (ulang)  : " + salinan);

        Collections.shuffle(data, new Random(7));
        System.out.println("shuffle seed 7           : " + data);
    }
}

Output yang Dihasilkan:

text
shuffle seed 42 (pertama): [3, 7, 4, 2, 5, 1, 8, 6]
shuffle seed 42 (ulang)  : [3, 7, 4, 2, 5, 1, 8, 6]
shuffle seed 7           : [3, 4, 8, 7, 5, 2, 6, 1]

Poin bedahnya:

  1. Baris 7-8 dan 11-12 (dua seed 42): dua list berisi sama diacak dengan new Random(42) yang masing-masing baru dibuat — hasilnya persis identik [3, 7, 4, 2, 5, 1, 8, 6]. Inilah determinisme yang membuat pengacakan bisa diuji.
  2. Baris 14-15 (seed 7): seed berbeda menghasilkan pengacakan berbeda pada list yang sama. Seed adalah “kunci” seluruh deretan angka acak yang menyusulnya.
  3. Keterbatasan struktural: shuffle memindahkan elemen di tempat, sehingga list immutable seperti List.of(...) akan menolaknya; salin dulu ke ArrayList sebagaimana dicontohkan.

Saudara Dekat: Class Arrays #

Class Arrays memainkan peran yang sama untuk array mentah: Arrays.sort mengurutkan, Arrays.toString mencetak isi, dan Arrays.asList menjembatani array ke dunia collection:

java Perkakas class Arrays
int[] angka = {45, 12, 89};
Arrays.sort(angka);
System.out.println(Arrays.toString(angka));

List<String> jembatan = Arrays.asList("Budi", "Siti");
jembatan.set(0, "Anton");   // boleh: penggantian elemen didukung
jembatan.add("Dewi");       // ditolak: ukuran tetap

Output yang Dihasilkan:

text
[12, 45, 89]
[Budi, Siti]
[Anton, Siti]
add ditolak: java.lang.UnsupportedOperationException

Hasil Arrays.asList adalah list berukuran tetap yang menempel pada sumbernya — set mengubah elemen, tetapi add dan remove ditolak karena menambah atau mengurangi elemen berarti mengubah ukuran array yang tidak bisa bertumbuh. Untuk list yang bebas berubah, salin lewat new ArrayList<>(Arrays.asList(...)).

Perkakas Collections dan Arrays menuntaskan kotak alat pengelolaan isi. Pertanyaan penutup Section ini bersifat arsitektural: dari belasan struktur yang kini kita kenal — ArrayList, HashSet, TreeMap, ArrayDeque, PriorityQueue — mana yang seharusnya dipilih untuk sebuah kebutuhan data tertentu? Chapter berikutnya menyusun kerangka berpikirnya dalam bentuk pohon keputusan.

Referensi #

Berkas Sumber

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

AcakTerkendali.java

Unduh berkas
java
import java.util.*;

public class AcakTerkendali {
    public static void main(String[] args) {
        List<Integer> data = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 8));

        Collections.shuffle(data, new Random(42));
        System.out.println("shuffle seed 42 (pertama): " + data);

        List<Integer> salinan = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 8));
        Collections.shuffle(salinan, new Random(42));
        System.out.println("shuffle seed 42 (ulang)  : " + salinan);

        Collections.shuffle(data, new Random(7));
        System.out.println("shuffle seed 7           : " + data);
    }
}

OperasiDasar.java

Unduh berkas
java
import java.util.*;

public class OperasiDasar {
    public static void main(String[] args) {
        List<Integer> data = new ArrayList<>(List.of(45, 12, 89, 33, 7));
        System.out.println("awal         : " + data);

        Collections.sort(data);
        System.out.println("sort         : " + data);

        Collections.reverse(data);
        System.out.println("reverse      : " + data);

        Collections.swap(data, 0, 4);
        System.out.println("swap(0, 4)   : " + data);

        Collections.replaceAll(data, 33, 30);
        System.out.println("replaceAll   : " + data);

        Collections.addAll(data, 50, 60);
        System.out.println("addAll       : " + data);

        List<Integer> pola = Collections.nCopies(3, 0);
        System.out.println("nCopies(3, 0): " + pola);

        Collections.fill(data, 0);
        System.out.println("fill(0)      : " + data);
    }
}

StatistikDanPencarian.java

Unduh berkas
java
import java.util.*;

public class StatistikDanPencarian {
    public static void main(String[] args) {
        List<Integer> data = new ArrayList<>(List.of(12, 7, 45, 12, 89, 7, 12));

        System.out.println("frequency(12) : " + Collections.frequency(data, 12));
        System.out.println("frequency(99) : " + Collections.frequency(data, 99));

        List<Integer> hadiah = List.of(100, 200);
        System.out.println("disjoint       : " + Collections.disjoint(data, hadiah));

        System.out.println("max            : " + Collections.max(data));
        System.out.println("min            : " + Collections.min(data));
        System.out.println("max (reverse)  : " + Collections.max(data, Comparator.reverseOrder()));

        List<String> nama = List.of("Budi", "Siti", "Dewi", "Anton");
        System.out.println("max nama       : " + Collections.max(nama));
        System.out.println("min nama       : " + Collections.min(nama));

        // binarySearch menuntut list yang sudah terurut menaik.
        List<Integer> terurut = new ArrayList<>(data);
        Collections.sort(terurut);
        System.out.println("terurut        : " + terurut);
        System.out.println("cari 45        : " + Collections.binarySearch(terurut, 45));
        System.out.println("cari 20        : " + Collections.binarySearch(terurut, 20));
    }
}