Sepuluh Chapter belakangan melengkapi kotak peralatan kita: deklarasi method, parameter, return value, overloading, varargs, rekursi, kepemilikan static/instance, cakupan, hingga kemurnian. Peralatan itu baru benar-benar terasa nilainya ketika dipakai untuk pekerjaan yang sama tiap hari: merombak kode yang sudah bekerja namun susah dibaca menjadi susunan method yang rapi — tanpa mengubah perilakunya sedikit pun. Latihan semacam ini dinamai refactoring: menyusun ulang struktur internal program sambil menjaga perilaku eksternalnya tetap identik. Pada Chapter penutup ini kita ambil satu program laporan nilai yang monolitik, bedah gejalanya, lalu rombak bertahap menjadi method-method kecil yang masing-masing fokus pada satu tanggung jawab.

Studi Kasus Program Monolitik #

Berikut program laporan nilai yang seluruh logikanya ditumpuk di dalam main. Program ini bekerja benar — dan justru karena bekerja benar, struktur yang tidak teratur ini sering dibiarkan tumbuh:

public class LaporanMonolitik {

    public static void main(String[] args) {
        String[] nama = {"Budi", "Siti", "Dewi"};
        int[] nilai = {78, 85, 92};

        // Judul laporan
        System.out.println("=== Laporan Nilai Ujian ===");
        System.out.println("---------------------------");

        // Rincian tiap siswa beserta statusnya
        for (int i = 0; i < nilai.length; i++) {
            String status;
            if (nilai[i] >= 75) {
                status = "LULUS";
            } else {
                status = "REMEDIAL";
            }
            System.out.println(nama[i] + " : " + nilai[i] + " (" + status + ")");
        }

        // Statistik: total, nilai tertinggi, rata-rata
        int total = 0;
        int tertinggi = nilai[0];
        for (int i = 0; i < nilai.length; i++) {
            total += nilai[i];
            if (nilai[i] > tertinggi) {
                tertinggi = nilai[i];
            }
        }
        double rataRata = (double) total / nilai.length;

        // Ringkasan akhir
        System.out.println("---------------------------");
        System.out.println("rata-rata : " + rataRata);
        System.out.println("tertinggi : " + tertinggi);
    }
}

Output yang Dihasilkan:

text
=== Laporan Nilai Ujian ===
---------------------------
Budi : 78 (LULUS)
Siti : 85 (LULUS)
Dewi : 92 (LULUS)
---------------------------
rata-rata : 85.0
tertinggi : 92

Gejalanya khas program monolitik. Pertama, main mengerjakan empat pekerjaan berbeda sekaligus: mencetak judul, menyusun rincian siswa, menghitung statistik, dan mencetak ringkasan — pembaca harus menelusuri seluruh badan main untuk tahu program berniat apa. Kedua, pengetahuan penting terkubur di tengah kode: ambang kelulusan 75 hanya hidup di dalam percabangan, rata-rata hanya hidup sebagai variabel setempat. Ketiga, tidak ada yang bisa diuji sendiri: membuktikan rataRata benar berarti menjalankan seluruh program dan membaca keluarannya.

Merombak Bertahap #

Refactoring yang aman berjalan satu langkah kecil tiap waktu, dan setiap langkah dituntut satu bukti: keluaran program tidak berubah. Kita mulai dari pertanyaan paling kecil yang terkubur — “berapa status sebuah nilai?” — lalu angkat menjadi method statusNilai. Pertanyaan berikutnya, “berapa rata-rata sekumpulan nilai?” menjadi hitungRataRata; “berapa nilai tertingginya?” menjadi nilaiTertinggi; pencetakan rincian menjadi cetakRincian; terakhir, main cukup mendelegasikan seluruh laporan ke cetakLaporan:

java LaporanRapi.java
public class LaporanRapi {

    // Method murni kecil: satu pertanyaan, satu jawaban
    static String statusNilai(int nilai) {
        return (nilai >= 75) ? "LULUS" : "REMEDIAL";
    }

    static double hitungRataRata(int[] nilai) {
        int total = 0;
        for (int n : nilai) {
            total += n;
        }
        return (double) total / nilai.length;
    }

    static int nilaiTertinggi(int[] nilai) {
        int tertinggi = nilai[0];
        for (int n : nilai) {
            if (n > tertinggi) {
                tertinggi = n;
            }
        }
        return tertinggi;
    }

    static void cetakRincian(String[] nama, int[] nilai) {
        for (int i = 0; i < nilai.length; i++) {
            System.out.println(nama[i] + " : " + nilai[i]
                    + " (" + statusNilai(nilai[i]) + ")");
        }
    }

    static void cetakLaporan(String[] nama, int[] nilai) {
        System.out.println("=== Laporan Nilai Ujian ===");
        System.out.println("---------------------------");
        cetakRincian(nama, nilai);
        System.out.println("---------------------------");
        System.out.println("rata-rata : " + hitungRataRata(nilai));
        System.out.println("tertinggi : " + nilaiTertinggi(nilai));
    }

    public static void main(String[] args) {
        String[] nama = {"Budi", "Siti", "Dewi"};
        int[] nilai = {78, 85, 92};
        cetakLaporan(nama, nilai);
    }
}

Output yang Dihasilkan:

text
=== Laporan Nilai Ujian ===
---------------------------
Budi : 78 (LULUS)
Siti : 85 (LULUS)
Dewi : 92 (LULUS)
---------------------------
rata-rata : 85.0
tertinggi : 92

Mari kita bedah hasil rombakannya:

  1. Baris 4-6 (statusNilai): percabangan if-else yang tadinya terkubur dalam perulangan kini menjadi method murni satu baris. Ambang 75 kini punya alamat resmi — siapa pun yang mencari makna nilai kelulusan mendarat di sini.
  2. Baris 8-14 (hitungRataRata) dan 16-24 (nilaiTertinggi): dua statistik menjadi method murni bertipe return double dan int. Keduanya hanya membaca parameter, sehingga dapat diuji terpisah — panggil hitungRataRata dengan {78, 85, 92}, bandingkan dengan 85.0, selesai.
  3. Baris 26-31 (cetakRincian): efek samping pencetakan dikumpulkan di method satu tanggung jawab, dan baris 28-29 memanggil statusNilai(nilai[i]) — method kecil saling bekerja sama alih-alih logika digandakan.
  4. Baris 33-40 (cetakLaporan): method penyusun yang membaca seperti daftar isi — judul, rincian, garis, ringkasan. Struktur laporan kini terlihat dari nama pemanggilan, bukan dari urutan println.
  5. Baris 42-46 (main): menyusut menjadi tiga baris — siapkan data, minta laporan. main kembali menjadi tempat orkestrasi, bukan tempat kerja.

Menjaga Perilaku Tetap Sama #

Perhatikan bahwa blok output kedua sama persis dengan blok pertama — baris demi baris, spasi demi spasi. Kesamaan itulah satu-satunya alat ukur keberhasilan refactoring pada program kita: pembaca laporan tidak boleh bisa membedakan versi monolitik dari versi rapi. Dalam praktik nyata, disiplin ini diperkuat dengan menjalankan kedua versi (atau rangkaian pengujian otomatis) sebelum dan sesudah setiap langkah rombakan; satu beda saja berarti langkah tadi mengubah perilaku dan perlu dikaji ulang.

Dengan ini perjalanan Section Method dan Modularitas tuntas: dari anatomi method pertama hingga merombak program nyata menjadi method yang fokus dan teruji. Keterampilan memecah program akan terus terpakai di seluruh Course — mulai dari mengelola kumpulan data pada Section Array dan String, hingga menyusun perilaku objek pada Object-Oriented Programming.

Referensi #

Berkas Sumber

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

LaporanMonolitik.java

Unduh berkas
java
public class LaporanMonolitik {

    public static void main(String[] args) {
        String[] nama = {"Budi", "Siti", "Dewi"};
        int[] nilai = {78, 85, 92};

        // Judul laporan
        System.out.println("=== Laporan Nilai Ujian ===");
        System.out.println("---------------------------");

        // Rincian tiap siswa beserta statusnya
        for (int i = 0; i < nilai.length; i++) {
            String status;
            if (nilai[i] >= 75) {
                status = "LULUS";
            } else {
                status = "REMEDIAL";
            }
            System.out.println(nama[i] + " : " + nilai[i] + " (" + status + ")");
        }

        // Statistik: total, nilai tertinggi, rata-rata
        int total = 0;
        int tertinggi = nilai[0];
        for (int i = 0; i < nilai.length; i++) {
            total += nilai[i];
            if (nilai[i] > tertinggi) {
                tertinggi = nilai[i];
            }
        }
        double rataRata = (double) total / nilai.length;

        // Ringkasan akhir
        System.out.println("---------------------------");
        System.out.println("rata-rata : " + rataRata);
        System.out.println("tertinggi : " + tertinggi);
    }
}

LaporanRapi.java

Unduh berkas
java
public class LaporanRapi {

    // Method murni kecil: satu pertanyaan, satu jawaban
    static String statusNilai(int nilai) {
        return (nilai >= 75) ? "LULUS" : "REMEDIAL";
    }

    static double hitungRataRata(int[] nilai) {
        int total = 0;
        for (int n : nilai) {
            total += n;
        }
        return (double) total / nilai.length;
    }

    static int nilaiTertinggi(int[] nilai) {
        int tertinggi = nilai[0];
        for (int n : nilai) {
            if (n > tertinggi) {
                tertinggi = n;
            }
        }
        return tertinggi;
    }

    static void cetakRincian(String[] nama, int[] nilai) {
        for (int i = 0; i < nilai.length; i++) {
            System.out.println(nama[i] + " : " + nilai[i]
                    + " (" + statusNilai(nilai[i]) + ")");
        }
    }

    static void cetakLaporan(String[] nama, int[] nilai) {
        System.out.println("=== Laporan Nilai Ujian ===");
        System.out.println("---------------------------");
        cetakRincian(nama, nilai);
        System.out.println("---------------------------");
        System.out.println("rata-rata : " + hitungRataRata(nilai));
        System.out.println("tertinggi : " + nilaiTertinggi(nilai));
    }

    public static void main(String[] args) {
        String[] nama = {"Budi", "Siti", "Dewi"};
        int[] nilai = {78, 85, 92};
        cetakLaporan(nama, nilai);
    }
}