Array di Java

Hai, teman-teman! Warteg Canggih makin laris, dan pemiliknya mau menambah dua menu baru: telur balado dan sayur asem. Kedengarannya sepele. Tapi coba lihat kode kasir versi 6: daftar menu ditulis di dua switch yang terpisah, satu untuk mencetak menu, satu lagi untuk memproses pesanan.

Menambah dua menu berarti mengedit dua tempat. Kalau suatu hari warteg punya 30 menu, berarti 30 case di tiap switch, ditambah 60 variabel kalau pakai cara menu1, harga1, menu2, harga2 seperti di artikel-artikel awal. Pasti ada cara yang lebih waras, dan cara itu adalah array di Java.


TL;DR: Array di Java adalah satu variabel yang menyimpan banyak nilai bertipe sama, berderet dan bernomor. Nomornya (index) selalu mulai dari 0, jadi elemen terakhir ada di length - 1. Array dibuat dengan {nilai1, nilai2} kalau isinya sudah diketahui, atau new int[5] kalau belum. Ukurannya tetap setelah dibuat. Cara paling umum mengolahnya adalah perulangan for atau for-each. Jebakan yang sering terjadi: mengakses index di luar batas (ArrayIndexOutOfBoundsException), mencetak array langsung yang hasilnya [I@..., dan tertukar antara length dan length().

Kenalan Dulu: Apa Itu Array di Java?

Coba bayangin rak lauk di etalase warteg. Ada satu rak panjang dengan beberapa sekat, dan tiap sekat diberi nomor. Kalau mau ambil lauk, kita cukup bilang "sekat nomor 2", tidak perlu tahu nama raknya satu per satu.

Array bekerja persis seperti itu. Satu variabel, banyak sekat, semua sekat berisi tipe data yang sama, dan tiap sekat punya nomor yang disebut index. Menurut tutorial Oracle tentang array, panjang array ditentukan saat dibuat, dan setelah itu panjangnya tetap.

Cara Membuat Array di Java

Ada dua cara, tergantung apakah isinya sudah diketahui dari awal.

Kalau isinya sudah diketahui, langsung tulis di dalam kurung kurawal:

String[] namaMenu = {"Nasi putih", "Tempe orek", "Es teh"};
int[] hargaMenu = {5000, 4000, 3000};

Tanda [] setelah nama tipe artinya "array dari tipe ini". Jadi int[] dibaca "array berisi int".

Kalau isinya belum diketahui, buat dulu sekatnya dengan new, lalu isi belakangan:

int[] porsi = new int[3];   // 3 sekat, belum diisi
porsi[1] = 2;               // sekat index 1 diisi 2

Sekat yang belum diisi tidak kosong melompong. Java otomatis mengisinya dengan nilai bawaan sesuai tipenya, seperti diatur di spesifikasi bahasa Java bab Arrays: 0 untuk angka, false untuk boolean, dan null untuk objek seperti String. Jadi isi porsi di atas sekarang [0, 2, 0].

Index Array Selalu Mulai dari 0

Ini bagian yang paling sering bikin bingung. Index pertama bukan 1, tapi 0:

System.out.println(namaMenu[0]);   // Nasi putih
System.out.println(namaMenu[2]);   // Es teh

Array dengan 3 elemen punya index 0, 1, dan 2. Index terakhir selalu panjang - 1. Panjangnya sendiri bisa dicek lewat namaMenu.length.

Di kasir, ini berarti ada "terjemahan" kecil. Pembeli menyebut menu nomor 1, tapi di array dia ada di index 0. Jadi rumusnya index = nomor - 1.

Jebakan: ArrayIndexOutOfBoundsException

Kalau kita meminta sekat yang tidak ada, Java tidak menebak-nebak. Program langsung berhenti:

int[] harga = {5000, 4000, 3000};
System.out.println(harga[3]);
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3

Pesannya jujur: index 3 diminta, padahal panjangnya cuma 3, jadi index terakhir adalah 2. Penyebab paling umum adalah off-by-one yang sudah kita kenal di artikel Perulangan di Java, yaitu memakai <= padahal seharusnya <. Menurut dokumentasi resminya, exception ini juga muncul untuk index negatif.

Untuk index yang datang dari luar, misalnya nomor menu pilihan pembeli, cek dulu sebelum dipakai:

int index = nomor - 1;
if (index < 0 || index >= namaMenu.length) {
    System.out.println("Menu nomor " + nomor + " tidak ada");
}

Mengolah Array dengan Perulangan

Array dan perulangan itu pasangan. Karena index berurutan dari 0, for dengan pola "mulai 0, pakai <" pas sekali:

for (int i = 0; i < namaMenu.length; i++) {
    System.out.println((i + 1) + ". " + namaMenu[i] + " (Rp" + hargaMenu[i] + ")");
}

Mau menunya 3 atau 30, kode ini tidak berubah. Itulah inti kenapa array dibutuhkan.

for-each: Kalau Index Tidak Dibutuhkan

Java juga punya bentuk for yang lebih ringkas, biasa disebut for-each. Bentuk ini mengambil isi array satu per satu, tanpa perlu mengurus index:

int[] pecahan = {10000, 5000, 2000, 1000};

for (int lembar : pecahan) {
    System.out.println("Rp" + lembar);
}

Cara bacanya: "untuk setiap lembar di dalam pecahan". Patokannya, pakai for-each kalau yang dibutuhkan cuma isinya. Kalau butuh nomor urutnya, misalnya untuk mencetak "1. Nasi putih" atau mengakses dua array sekaligus, kembali ke for biasa.

Array Paralel: Nama dan Harga di Index yang Sama

Di kasir, nama menu dan harganya disimpan di dua array terpisah, tapi dengan urutan yang sama:

String[] namaMenu = {"Nasi putih", "Tempe orek", "Es teh"};
int[] hargaMenu = {5000, 4000, 3000};

namaMenu[1] dan hargaMenu[1] sama-sama milik tempe orek. Pola ini disebut array paralel. Gampang dipakai, tapi ada satu syarat yang harus dijaga sendiri: urutan kedua array tidak boleh beda. Kalau harga ditambah di tengah tapi nama ditambah di akhir, semua harga setelahnya jadi bergeser. Cara yang lebih rapi untuk menyatukan nama dan harga akan muncul di Tahap 2, saat kita kenalan dengan class.

Array sebagai Penghitung

Array juga bisa dipakai untuk menghitung. Misalnya, kita mau tahu berapa porsi untuk tiap menu dari pesanan satu meja {1, 2, 2, 3}. Buat array porsi yang panjangnya sama dengan jumlah menu. Karena isi awalnya otomatis 0, tinggal tambahkan satu di sekat yang sesuai:

int[] pesanan = {1, 2, 2, 3};
int[] porsi = new int[namaMenu.length];

for (int nomor : pesanan) {
    porsi[nomor - 1]++;
}
// porsi sekarang [1, 2, 1]

Struk jadi bisa menampilkan "Tempe orek x2", bukan menulis tempe orek dua baris.

Jebakan Saat Mencetak dan Membandingkan Array

Mencetak Array Langsung

Ini jebakan yang hampir semua pemula alami:

int[] harga = {5000, 4000, 3000};
System.out.println(harga);

Hasilnya bukan daftar angka, tapi sesuatu seperti ini:

[I@2c34f934

Tulisan itu adalah teks bawaan untuk objek, yang menurut dokumentasi Object.toString berisi nama tipe ditambah sebuah kode heksadesimal. [I artinya "array int". Angka di belakangnya bisa beda tiap kali dijalankan. Untuk melihat isinya, pakai Arrays.toString dari class Arrays, dengan menambahkan import java.util.Arrays; di baris paling atas file:

System.out.println(Arrays.toString(harga));   // [5000, 4000, 3000]

Array Itu Rujukan, Bukan Isinya

Di artikel Variabel dan Tipe Data, kita sudah tahu bahwa objek disimpan sebagai rujukan. Array juga begitu. Akibatnya ada dua hal yang mengejutkan:

int[] a = {1, 2};
int[] b = {1, 2};
System.out.println(a == b);               // false
System.out.println(Arrays.equals(a, b));  // true

== membandingkan apakah dua variabel menunjuk ke array yang sama, bukan apakah isinya sama. Untuk membandingkan isi, pakai Arrays.equals. Ini mirip pelajaran == dan equals() pada String.

Hal kedua, int[] salinan = harga; tidak membuat array baru. Dua variabel itu menunjuk ke rak yang sama. Kalau salinan[0] diubah, harga[0] ikut berubah.

Ukurannya Tidak Bisa Ditambah

Setelah dibuat, panjang array tetap. Kalau perlu daftar yang bisa bertambah panjang, Java punya ArrayList. Untuk sekarang, array sudah cukup, karena daftar menu warteg tidak berubah saat program berjalan.

Kasir Warteg Versi 7: Menu Cukup Ditulis Sekali

Sekarang dua switch di versi 6 diganti array. Daftar menu cukup ditulis sekali, pesanan satu meja disimpan sebagai int[], struk menampilkan jumlah porsi per menu, dan pecahan kembalian juga jadi array.

import java.util.Arrays;

public class WartegCanggih {
    public static void main(String[] args) {
        final String NAMA_WARTEG = "Warteg Canggih";

        // daftar menu cukup ditulis sekali, index yang sama = menu yang sama
        String[] namaMenu = {"Nasi putih", "Tempe orek", "Es teh", "Telur balado", "Sayur asem"};
        int[] hargaMenu = {5000, 4000, 3000, 6000, 4000};
        int[] pecahan = {10000, 5000, 2000, 1000};

        int[] pesanan = {1, 2, 2, 4, 9, 3};   // nomor menu satu meja
        int uangPembeli = 38000;

        System.out.println("Selamat datang di " + NAMA_WARTEG + "!");
        System.out.println("Daftar menu:");
        for (int i = 0; i < namaMenu.length; i++) {
            System.out.println((i + 1) + ". " + namaMenu[i] + " (Rp" + hargaMenu[i] + ")");
        }
        System.out.println();
        System.out.println("Pesanan meja: " + Arrays.toString(pesanan));

        // rekap: berapa porsi untuk tiap menu, isi awalnya otomatis 0
        int[] porsi = new int[namaMenu.length];
        for (int nomor : pesanan) {
            int index = nomor - 1;
            if (index < 0 || index >= namaMenu.length) {
                System.out.println("Menu nomor " + nomor + " tidak ada, dilewati");
                continue;
            }
            porsi[index]++;
        }
        System.out.println();

        int subtotal = 0;
        for (int i = 0; i < namaMenu.length; i++) {
            if (porsi[i] == 0) {
                continue;
            }
            int hargaBaris = hargaMenu[i] * porsi[i];
            System.out.println(String.format("%-14s%3s%11s", namaMenu[i], "x" + porsi[i], "Rp" + hargaBaris));
            subtotal += hargaBaris;
        }

        int diskon;
        if (subtotal >= 20000) {
            diskon = 2000;
        } else if (subtotal >= 10000) {
            diskon = 1000;
        } else {
            diskon = 0;
        }
        int total = subtotal - diskon;

        System.out.println("-".repeat(28));
        System.out.println(String.format("%-17s%11s", "Subtotal", "Rp" + subtotal));
        System.out.println(String.format("%-17s%11s", "Diskon", "Rp" + diskon));
        System.out.println(String.format("%-17s%11s", "TOTAL", "Rp" + total));

        if (uangPembeli < total) {
            System.out.println("Uang kurang Rp" + (total - uangPembeli));
        } else {
            int sisa = uangPembeli - total;
            System.out.println("Kembalian: Rp" + sisa);
            for (int lembar : pecahan) {
                while (sisa >= lembar) {
                    System.out.println("  Rp" + lembar);
                    sisa -= lembar;
                }
            }
        }
    }
}

Hasilnya:

Selamat datang di Warteg Canggih!
Daftar menu:
1. Nasi putih (Rp5000)
2. Tempe orek (Rp4000)
3. Es teh (Rp3000)
4. Telur balado (Rp6000)
5. Sayur asem (Rp4000)

Pesanan meja: [1, 2, 2, 4, 9, 3]
Menu nomor 9 tidak ada, dilewati

Nasi putih     x1     Rp5000
Tempe orek     x2     Rp8000
Es teh         x1     Rp3000
Telur balado   x1     Rp6000
----------------------------
Subtotal             Rp22000
Diskon                Rp2000
TOTAL                Rp20000
Kembalian: Rp18000
  Rp10000
  Rp5000
  Rp2000
  Rp1000

Coba bandingkan bagian kembalian dengan versi 6. Rantai else if empat tingkat sekarang jadi for-each dengan while di dalamnya. Menambah lembar Rp20.000 cukup dengan menambah satu angka di depan array pecahan.

Kalau belum tahu cara menjalankan kode ini, langkahnya ada di Mengenal Java dan Menjalankan Program Java Pertama.

Error Umum Pemula

1. Index di luar batas. ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3. Periksa batas perulangan (<, bukan <=) dan cek index yang datang dari pengguna sebelum dipakai.

2. Tertukar length dan length(). Array memakai length tanpa kurung, String memakai length() dengan kurung. Kalau tertukar di array:

error: cannot find symbol
  symbol:   method length()
  location: variable namaMenu of type String[]

3. Lupa import java.util.Arrays. Pemakaian Arrays.toString tanpa import membuat compile gagal dengan cannot find symbol yang menunjuk ke Arrays.

4. Mencetak array langsung. Hasilnya [I@..., bukan isinya. Pakai Arrays.toString.

5. Lupa mengurangi 1 dari nomor menu. Pembeli memesan nomor 1, tapi kode mengambil namaMenu[1], sehingga yang keluar tempe orek, bukan nasi putih. Tidak ada error sama sekali, cuma struknya salah.

Penutup

Perubahan paling penting di versi 7 justru yang tidak terlihat: menambah menu sekarang cukup dengan menambah satu nama dan satu harga di dua array. Tidak ada switch yang perlu diedit, tidak ada perulangan yang perlu diubah batasnya.

Coba latihan ini: tambahkan menu keenam, misalnya "Perkedel" seharga 2000, lalu pesan nomor 6 di array pesanan. Kalau struk langsung menampilkan perkedel tanpa kamu mengubah baris lain, berarti kamu sudah paham kenapa batas perulangan ditulis namaMenu.length, bukan angka 5.

Tapi kalau dilihat lagi, main kasir kita makin panjang. Menampilkan menu, merekap porsi, menghitung diskon, mencetak struk, semuanya ditumpuk di satu tempat. Di artikel berikutnya, Method di Java: Parameter dan Return, tumpukan itu kita pecah jadi potongan-potongan kecil yang punya nama.

Kalau mau pembahasan array dari sudut lain, ada juga di Panduan Lengkap Array di Java.

Daftar semua artikel seri ini ada di label Warteg Canggih Series. Menu apa yang wajib ada di array warteg versimu? Tulis di kolom komentar.

Source code lengkap artikel ini bisa dilihat di GitHub: 07-array-di-java

FAQ

Apa itu array di Java? Array adalah satu variabel yang menyimpan banyak nilai bertipe sama secara berurutan. Setiap nilai punya nomor posisi yang disebut index, dan panjang array tetap setelah dibuat.

Kenapa index array di Java dimulai dari 0? Cara gampang mengingatnya: index adalah jarak dari elemen pertama, jadi elemen pertama berjarak 0. Akibatnya, array dengan panjang 3 punya index 0, 1, dan 2, dan index terakhir selalu length - 1.

Apa penyebab ArrayIndexOutOfBoundsException? Exception ini muncul saat program mengakses index yang tidak ada, yaitu index negatif atau index yang sama dengan atau lebih besar dari panjang array. Penyebab paling umum adalah batas perulangan <= yang seharusnya <.

Bagaimana cara mencetak isi array di Java? Pakai Arrays.toString(namaArray) setelah menambahkan import java.util.Arrays;. Kalau array dicetak langsung dengan println, hasilnya hanya teks seperti [I@2c34f934, bukan isinya.

Kapan pakai for biasa dan kapan pakai for-each? Pakai for-each kalau hanya butuh isi tiap elemen, karena kodenya lebih ringkas. Pakai for biasa kalau butuh nomor index, misalnya untuk mencetak nomor urut atau mengakses dua array paralel sekaligus.

Referensi

Posting Komentar untuk "Array di Java"