Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Sunday

Array Dinamis

Panjang suatu array tidak bisa diubah setelah dibuat. Akan tetapi, sering kali jumlah data yang disimpan dalam array bisa berubah setiap saat. Misalnya dalam contoh berikut : Suatu array menyimpan baris teks dalam program pengolah kata. Atau suatu array yang menyimpan daftar komputer yang sedang mengakses halaman suatu website. Atau array yang berisi gambar yang ditambahkan user oleh program gambar. Di sini jelas, bahwa kita butuh sesuatu yang bisa menyimpan data di mana jumlahnya tidak tetap.

Array Setengah Penuh
Bayangkan suatu aplikasi di mana sejumlah item yang ingin kita simpan di dalam array akan berubah-ubah sepanjang program tersebut berjalan. Karena ukuran array tidak bisa diubah, maka variabel terpisah digunakan untuk menyimpan berapa banyak sisa tempat kosong yang masih bisa diisi di dalam array.
Bayangkan misalnya, suatu program yang membaca bilangan bulat positif dari user, kemudian menyimpannya untuk diproses kemudian. Program akan berhenti membaca input apabila input yang diterima bernilai 0 atau kurang dari nol. Bilangan input n tersebut kita simpa di dalam array bilangan dengan tipe int[]. Katakan banyaknya bilangan yang bisa disimpan tidak lebih dari 100 buah. Maka ukuran array bisa dibuat 100.
Akan tetapi program tersebut harus melacak berapa banyak bilangan yang sudah diambil dari user. Kita gunakan variabel terpisah bernama jmlBilangan. Setiap kali suatu bilangan disimpan di dalam array, nilai jmlBilangan akan bertambah satu.
Sebagai contoh sederhana, masi kita buat program yang mengambil bilangan yang diinput dari user, kemudian mencetak bilangan-bilangan tersebut dalam urutan terbalik. (Ini adalah contoh pengolahan yang membutuhkan array, karena semua bilangan harus disimpan pada suatu tempat. Banyak lagi contoh program misalnya, mencari jumlah atau rata-rata atau nilai maksimum beberapa bilangan, bisa dilakukan tanpa menyimpan bilangan tersebut satu per satu)

public class BalikBilanganInput {
 
    public static void main(String[] args) {
 
        int[] bilangan;  // Array untuk menyimpan nilai input dari user
        int jmlBilangan;    // Banyaknya bilangan yang sudah disimpan dalam array
        int bil;          // Bilangan yang diambil dari user
 
        bilangan = new int[100];   // Buat array dengan 100 bilangan int
        jmlBilangan = 0;                // Belum ada bilangan yang disimpan
 
        System.out.println("Masukkan bilangan bulat positif (paling banyak 100 bilangan)" + 
            ", masukkan nol untuk mengakhiri.");
 
        while (true) {
            System.out.print("? ");
            bil = KonsolIO.ambilInt();
            if (bil <= 0)
                break;
            bilangan[jmlBilangan] = bil;
            jmlBilangan++;
        }
 
        System.out.println("\nBilangan yang Anda masukkan dalam urutan terbalik adalah :\n");
 
        for (int i = jmlBilangan - 1; i >= 0; i--) {
            System.out.println( bilangan[i] );
        }
 
    } // akhir main();
 
}  // akhir kelas BalikBilanganInput 
Penting untuk diingat bahwa jmlBilangan memiliki dua peran. Yang pertama, adalah melacak banyaknya bilangan yang sudah dimasukkan di dalam array. Yang kedua adalah menentukan di mana indeks kosong berikutnya di dalam array. Misalnya, jika 4 bilangan sudah dimasukkan ke dalam array, maka bilangan-bilangan tersebut diisi pada array di posisi 0, 1, 2, dan 3. Maka posisi kosong berikutnya adalah posisi 4.
Ketika kita akan mencetak angka di dalam array, maka poisisi penuh berikutnya adalah di lokasi jmlBilangan - 1, sehingga perulangan for mencetak bilangan dari jmlBilangan - 1 hingga 0.
Mari kita lihat contoh lain yang lebih realistis. Misalkan kita ingin menulis program game, di mana pemain bisa masuk ke dalam game dan keluar dari game setiap saat. Sebagai programmer berorientasi objek yang baik, mungkin kita memiliki kelas bernama Pemain sebagai lambang pemain di dalam game. Daftar pemain yang sedang ada di dalam game, bisa disimpan di dalam array ArrayPemain dengan tipe Pemain[].
Karena jumlah pemain bisa berubah-ubah maka kita bisa menggunakan variabel bantu, misalnya jumlahPemainAktif untuk mencatat banyaknya pemain yang sedang aktif berada di dalam game. Misalnya jumlah maksimum pemain di dalam game adalah 10 orang, maka kita bisa mendeklarasikan variabelnya sebagai :
Pemain[] ArrayPemain = new Pemain[10];  // Hingga 10 pemain.
int jumlahPemainAktif = 0;  // Di awal game, tidak ada pemain yang aktif
Setelah beberapa pemain masuk ke dalam game, variabel jumlahPemainAktif akan lebih dari 0, dan objek pemailn akan disimpan dalam array, misalnya ArrayPemain[0], ArrayPemain[1], ArrayPemain[2], dan seterusnya. Ingat bahwa pemain ArrayPemain[jumlahPemainAktif] tidak ada. Prosedur untuk menambah pemain baru, secara sederhana :
// Tambah pemain di tempat kosong
ArrayPemain[jumlahPemainAktif] = pemainBaru; 
// And increment playerCt to count the new player.
jumlahPemainAktif++;  
Untuk menghapus seorang pemain mungkin sedikit lebih sulit karena kita tidak ingin meninggalkan lubang di tengah-tengah array. Misalnya kita ingin menghapus pemain pada indeks k pada ArrayPemain. Jika kita tidak peduli urutan pemainnya, maka salah satu caranya adalah memindahkan posisi pemain terakhir ke posisi pemain yang meninggalkan game, misalnya :
ArrayPemain[k] = ArrayPemain[jumlahPemainAktif - 1];
jumlahPemainAktif--;
Pemain yang sebelumnya ada di posisi k, tidak lagi ada di dalam array. Pemain yang sebelumnya ada di posisi jumlahPemainAktif -1 sekarang ada di array sebanyak 2 kali. Akan tetapi sekarang ia berada di bagian yang valid, karena nilai jumlahPemainAktif kita kurangi dengan satu. Ingat bahwa setiap elemen di dalam array harus menyimpan satu nilai, akan tetapi satu-satunya nilai dari posisi 0 hingga jumlahPemainAktif - 1 akan tetap diproses seperti biasa.
Misalnya kita ingin menghapus pemain di posisi k, akan tetapi kita ingin agar urutan pemain tetap sama. Untuk melakukannya, semua pemain di posisi k+1 ke atas harus dipindahkan satu posisi ke bawah. Pemain k+ mengganti pemain k yang keluar dari game. Pemain k+2 mengganti pemain yang pindah sebelumnya, dan berikutnya. Kodenya bisa dibuat seperti
for (int i = k+1; i < jumlahPemainAktif; i++) {
    ArrayPemain[i-1] = ArrayPemain[i];
}
jumlahPemainAktif--;
Perlu ditekankan bahwa contoh Pemain di atas memiliki tipe dasar suatu kelas. Elemennya bisa bernilai null atau referensi ke suatu objek yang bertipe Pemain, Objek Pemain sendiri tidak disimpan di dalam array, hanya referensinya saja yang disimpan di sana. Karena aturan pemberian nilai pada Java, objek tersebut bisa saja berupa kelas turunan dari Pemain, sehingga mungkin juga array tersebut menyimpan beberapa jenis Pemain misalnya pemain komputer, pemain manusia, atau pemain lainnya, yang semuanya adalah kelas turunan dari Pemain.
Contoh lainnya, misalnya kelas BentukGeometri menggambarkan suatu bentuk geometri yang bisa digambar pada layar, dan ia memiliki kelas-kelas turunan yang merupakan bentuk-bentuk khusus, seperti garis, kotak, kotak bertepi bulat, oval, atau oval berisi warna, dan sebagainya. (BentukGeometri sendiri bisa berbentuk kelas abstrak, seperti didiskusikan sebelumnya). Kemudian array bertipe BentukGeometri[] bisa menyimpan referensi objek yang bertipe kelas turunan dari BentukGeometri. Misalnya, perhatikan contoh pernyataan berikut
BentukGeometri[] gambar = new BentukGeometri[100]; // Array untuk menyimpan 100 gambar.
gambar[0] = new Kotak();          // Letakkan beberapa objek di dalam array.
gambar[1] = new Garis();          // (Program betulan akan menggunakan beberapa
gambar[2] = new OvalBerwarna();    // parameter di sini
int jmlGambar = 3;  // Lacak jumlah objek di dalam array
bisa diilustrasikan sebagai berikut.
Array tersebut bisa digunakan dalam program gambar. Array bisa digunakan untuk menampung gambar-gambar yang akan ditampilkan. Jika BentukGeometri memiliki metode "void gambarUlang(Graphics g)" untuk menggambar pada grafik g, maka semua grafik dalam array bisa digambar dengan perulangan sederhana
for (int i = 0; i < jmlGambar; i++)
    gambar[i].gambarUlang(g);
Pernyataan "gambar[i].gambarUlang(g);" memanggil metode gambarUlang() yang dimiliki oleh masing-masing gambar pada indeks i di array tersebut. Setiap objek tahu bagaimana menggambar dirinya sendiri, sehingga perintah dalam perulangan tersebut sebetulnya melakukan tugas yang berbeda-beda tergantung pada objeknya. Ini adalah contoh dari polimorfisme dan pengolahan array.

Array Dinamis
Dalam contoh-contoh di atas, ada batas tententu dalam jumlah elemennya, yaitu 100 int, 100 Pemain, dan 100 BentukGeometris. Karena ukuran array tidak bisa berubah, array tersebut hanya bisa menampung maksimum sebanyak elemen yang didefinisikan pada pembuatan array. Dalam banyak kasus, adanya batas maksimum tersebut tidak diinginkan. Kenapa harus bekerja dengan hanya 100 bilangan bulat saja, bukan 101?
Alternatif yang umum adalah membuat array yang sangat besar sehingga bisa digunakan untuk dalam kehidupan sehari-hari. Akan tetapi cara ini tidak baik, karena akan sangat banyak memori komputer yang terbuang karena tidak digunakan. Memori itu mungkin lebih baik digunakan untuk yang lain. Apalagi jika komputer yang akan digunakan tidak memiliki memori yang cukup untuk menjalankan program tersebut.
Tentu saja, cara yang lebih baik adalah apabila kita bisa mengubah ukuran array sesuka kita kapan saja. Ingat bahwa sebenarnya variabel array tidak menyimpan array yang sesungguhnya. Variabel ini hanya menyimpan referensi ke objek tersebut. Kita tidak bisa membuat array tersebut lebih besar, akan tetapi kita bisa membuat array baru yang lebih besar, kemudian mengubah isi variabel array tersebut ke array baru itu.
Tentunya kita harus mengkopi semua isi di array yang lama ke array baru. Array lama akan diambil oleh pemulung memori, karena ia tidak lagi digunakan.
Mari kita lihat kembali contoh game di atas, di mana ArrayPemain adalah array dengan tipe Pemain[] dan jumlahPemainAktif[/code] adalah jumlah pemain yang sudah digunakan array tersebut. Misalnya kita tidak ingin membuat limit banyaknya pemainnya yang bisa ikut main. Jika pemain baru masuk dan array tersebut sudah penuh, kita akan membuat array baru yang lebih besar.
Variabel ArrayPemain akan merujuk pada array baru. Ingat bahwa setelah ini dilakukan, ArrayPemain[0] akan menunjuk pada lokasi memori yang berbeda, akan tetapi nilai ArrayPemain[0] sama dengan sebelumnya. Berikut ini adalah kode untuk melakukan hal di atas:
// Tambah pemain baru, meskipun array sudah penuh
 
if (jumlahPemainAktif == ArrayPemain.length) {
    // Array sudah penuh. Buat array baru yang lebih besar,
    // kemudian kopi isi array lama ke array baru lalu ubah
    // ArrayPemain ke array baru.
    int ukuranBaru = 2 * ArrayPemain.length;  // Ukuran array baru
    Pemain[] temp = new Pemain[ukuranBaru];  // Array baru
    System.arraycopy(ArrayPemain, 0, temp, 0, ArrayPemain.length);
    ArrayPemain = temp;  // Ubah referensi ArrayPemain ke array baru.
}
 
// Di sini kita sudah tahu bahwa pasti ada tempat di array baru.
 
ArrayPemain[jumlahPemainAktif] = pemainBaru; // Tambah pemain baru...
jumlahPemainAktif++;  //    ... dan tambah satu jumlahPemainAktif nya
Jika kita akan melakukan hal ini terus menerus, akan lebih indah jika kita membuat kelas untuk menangani hal ini. Objek mirip array yang bisa berubah ukuran untuk mengakomodasi jumlah data yang bisa ia tampung disebut array dinamis. Array dinamis memiliki jenis operasi yang sama dengan array : mengisi nilai pada posisi tertentu dan mengambil nilai di posisi tertentu. Akan tetapi tidak ada batas maksimum dari jumlah array (hanya tergantung pada jumlah memori komputer yang tersedia). Dalam kelas array dinamis, metode put dan get akan diimplementasikan sebagai metode instansi.
Di sini misalnya, adalah kelas yang mengimplementasikan array dinamis int :
public class ArrayDinamisInt {
    private int[] data;  // Array untuk menyimpan data
    public DynamicArrayOfInt() {
        // Konstruktor.
        data = new int[1];  // Array akan bertambah besar jika diperlukan
    }
 
    public int get(int posisi) {
        // Ambil nilai dari posisi tertentu di dalam array.
        // Karena semua posisi di dalam array adalah nol, maka
        // jika posisi tertentu di luar data array, nilai 0 akan dikembalikan
        if (posisi >= data.length)
            return 0;
        else
            return data[posisi];
    }
 
    public void put(int posisi, int nilai) {
        // Simpan nilai ke posisi yang ditentukan di dalam array
        // Data array tersebut akan bertambah besar jika diperlukan
 
        if (posisi >= data.length) {
            // Posisi yang ditentukan berada di luar array data
            // Besarkan ukuran array 2x lipat. Atau jika ukurannya masih
            // terlalu kecil, buat ukurannya sebesar 2*posisi
 
            int ukuranBaru = 2 * data.length;
            if (posisi >= ukuranBaru)
                ukuranBaru = 2 * posisi;
            int[] dataBaru = new int[ukuranBaru];
            System.arraycopy(data, 0, dataBaru, 0, data.length);
            data = dataBaru;
 
            // Perintah berikut hanya untuk demonstrasi
            System.out.println("Ukuran array dinamis diperbesar menjadi "
                + ukuranBaru);
        }
        data[posisi] = nilai;
    }
 
} // akhir kelas ArrayDinamisInt
Data pada objek ArrayDinamisInt disimpan dalam array biasa, akan tetapi arraynya akan dibuang dan diganti dengan array baru yang lebih besar apabila diperlukan. Jika bilangan adalah variable bertipe ArrayDinamisInt, maka perintah bilangan.put(pos,nilai) akan menyimpan bilangan pada posisi pos di array dinamis tersebut. Fungsi bilangan.get(pos) mengambil nilai yang disimpan pada posisi pos.
Pada contoh pertama, kita menggunakan array untuk menyimpan bilangan bulat positif yang dimasukkan oleh user. Kita bisa menulis ulang program tersebut dengan menggunakan ArrayDinamisInt. Referensi ke bilangan[i] diganti dengan bilangan.get[i]. Perintah "bilangan[jmlBilangan] = bil;" kita ganti dengan "bilangan.put(jmlBilangan,bil);". Berikut ini adalah programnya:
public class BalikBilanganInput {
 
    public static void main(String[] args) {
 
        ArrayDinamisInt bilangan;  // Array untuk menyimpan nilai input dari user
        int jmlBilangan;    // Banyaknya bilangan yang sudah disimpan dalam array
        int bil;          // Bilangan yang diambil dari user
 
        bilangan = new ArrayDinamisInt();
        jmlBilangan = 0;                // Belum ada bilangan yang disimpan
 
        System.out.println("Masukkan bilangan bulat positif, masukkan nol untuk mengakhiri.");
 
        while (true) {
            System.out.print("? ");
            bil = KonsolIO.ambilInt();
            if (bil <= 0)
                break;
            bilangan.put(jmlBilangan,bil);
            jmlBilangan++;
        }
 
        System.out.println("\nBilangan yang Anda masukkan dalam urutan terbalik adalah :\n");
 
        for (int i = jmlBilangan - 1; i >= 0; i--) {
            System.out.println( bilangan.get(i) );
        }
 
    } // akhir main();
 
}  // akhir kelas BalikBilanganInput 

Friday

Arraylists dan Vector

ArrayList
Kelas ArrayDinamisInt bisa digunakan jika kita membutuhkan array dengan batas maksimum yang tak terbatas. Akan tetapi jika kita ingin menyimpan BentukGeometri misalnya, kita harus membuat kelas baru. Kelas tersebut mungkin bernama ArrayDinamisBentukGeometri, dan akan tampak sama persis dengan ArrayDinamisInt dengan beberapa perubahan di mana "int" muncul akan diganti dengan "BentukGeometri". Juga demikian jika kita ingin membuat kelas ArrayDinamisDouble, ArrayDinamisPemain, dan sebagainya.
Yang agak sedikit lucu adalah kelas tersebut sangat mirip isinya, hanya kelas-kelasnya saja yang berlainan. Akan sangat lebih baik apabila kita bisa membuat kelas umum yang berlaku untuk semua kelas. Hal ini disebut dengan pemrograman generik. Beberapa bahasa pemrograman seperti C++ memiliki fasilitas untuk melakukan pemrograman generik. Java tidak memiliki fasilitas seperti itu (maksudnya tidak sama persis). Tapi kita bisa membuat sesuatu yang mirip dengan itu pada Java dengan menggunakan struktur data yang memiliki tipe "Object".
Pada Java, setiap kelas adalah kelas turunan dari kelas yang bernama Object. Artinya setiap objek dapat dirujuk oleh variabel bertiipe Object. Semua objek dapat dimasukkan dalam array bertipe Object[]. Jika suatu subrutin memiliki parameter formal bertipe Object, maka objek apapun bisa diberikan kepada subrutin tersebut.
Jika kita buat kelas ArrayDinamisObject, maka kita bisa menyimpan objek apapun. Ini sebenarnya bukan programming generik sebenarnya, dan tidak berlaku untuk tipe primitif seperti int dan double. Sebenarnya, kita tidak perlu membuat kelas ArrayDinamisObject sendiri, karena Java telah memiliki kelas standar yang dinamakan ArrayList yang sifatnya mirip dengan yang kita sebutkan sebelumnya.
ArrayList disimpan dalam paket java.util, jadi jika kita ingin menggunakan kelas ArrayList dalam sebuat program, kita harus memberikan "import java.util.ArrayList;" atau "import java.util.*;" di awal program kita.
Kelas ArrayList berbeda dengan kelas ArrayDinamisInt dalam arti, objek ArrayList selalu memiliki ukuran tertentu, dan kita tidak boleh mengambil posisi di luar ukuran ArrayList. Dalam hal ini, ArrayList mirip seperti array biasa. Akan tetapi, ukuran ArrayList bisa bertambah kapan saja jika diperlukan. Kelas ArrayList memiliki banyak metode instansi. Kita akan jelaskan sebagian yang sangat berguna. Misalnya daftar adalah variabel dengan tipe ArrayList.
  • daftar.size() -- Fungsi ini menghasilkan ukuran ArrayList saat ini. Posisi valid dalam daftar adalah yang bernomor 0 hingga daftar.size() - 1. Ingat bahwa ukurannya bisa nol. Panggilan konstruktor new ArrayList() akan membuat ArrayList dengan ukuran nol.
  • daftar.add(obj) -- Menambah objek di akhir ArrayList, kemudian menambah ukurannya dengan 1. Parameter obj merujuk pada objek dengan tipe apapun, atau bisa bernilai null.
  • daftar.get(N) -- Mengambil nilai yang disimpan pada posisi N pada ArrayList. N harus bertipe bilangan bulat antara 0 hingga daftar.size() - 1. Jika N berada di luar rentang ini, pesan kesalahan akan ditampilkan. Memanggil fungsi ini mirip dengan memanggil array seperti A[N] untuk suatu array A. Akan tetapi kita tidak bisa menggunakan daftar.get(N) pada ekspresi di sebelah kiri daftar.get(N) = 5 tidak boleh dilakukan)
  • daftar.set(N, obj) -- Mengisi suatu objek obj di posisi N dari suatu ArrayList, dan mengganti apapun yang sudah disimpan sebelumnya pada posisi N. Bilangan bulat N harus berada pada rentang 0 hingga daftar.size() - 1. Perintah ini mirip dengan perintah A[N] = obj pada array A.
  • daftar.remove(obj) -- Jika objek tersebut ada di dalam ArrayList, maka objek tersebut akan dibuang. Elemen lain setelah posisi objek tersebut di dalam ArrayList akan digeser satu posisi. Kemudian ukuran ArrayList akan berkurang 1. Jika obj terdapat dalam ArrayList lebih dari satu kali, hanya yang pertama saja yang dibuang.
  • daftar.remove(N) -- Untuk bilangan bulat N, maka perintah ini akan menghapus posisi ke-N pada ArrayList. N harus berada pada rentang 0 hingga daftar.size() - 1. Elemen setelah ini akan digeser satu posisi. Kemudian ukuran ArrayList berkurang 1.
  • daftar.indexOf(obj) -- Fungsi untuk mencari suatu objek obj di dalam ArrayList. Jika objek ditemukan, maka posisinya di dalam ArrayList akan dikembalikan. Jika tidak, maka fungsi ini akan mengembalikan -1.
Misalnya,kita akan membuat pemain dalam game yang digambarkan dengan objek dengan tipe Pemain. Pemain yang berada dalam game disimpan dalam ArrayList bernama paraPemain. Variabel ini dideklarasikan seperti :
ArrayList paraPemain;
dan kita inisialisasikan dengan objek kosong dengan perintah
paraPemain = new ArrayList();
Jika pemainBaru adalah variabel yang bertipe Pemain, maka pemain baru tersebut bisa ditambahkan ke dalam ArrayList dan ke dalam game dengan perintah :
paraPemain.add(pemainBaru);
dan jika pemain nomor i keluar dari game, maka kita hanya perlu memberikan perintah
paraPemain.remove(i);
Atau jika pemain adalah objek bertipe Pemain yang akan kita keluarkan dari game, maka kita bisa menggunakan perintah
paraPemain.remove(pemain);
Semuanya terlihat sangat mudah. Satu-satunya kesulitan yang akan kita temui adalah ketika kita ingin mengambil nilai yang disimpan pada posisi i di dalam ArrayList. Tipe keluaran fungsi ini adalah Object. Dalam hal ini objek yang diambil oleh fungsi ini sebenarnya bertipe Pemain. Supaya kita bisa menggunakan hasil keluarannya, maka kita perlu menggunakan casting tipe untuk mengubahnya menjadi tipe Player, dengan cara :
Pemain pmn = (Pemain)paraPemain.get(i);
Misalnya, jika kelas Pemain memiliki metode instansi yang dinamakan jalan() yang dipanggil ketika seorang pemain menjalankan dadu atau kartu, maka kita bisa menuliskan kode untuk memberi giliran kepada semua pemain untuk jalan, yaitu dengan
for (int i = 0;  i < paraPemain.size();  i++) {
    Pemain pmn = (Pemain)paraPemain.get(i);
    pmn.jalan();
}
Dua baris di dalam perulangan for tersebut dapat digabungkan dengan satu perintah :
((Pemain)paraPemain.get(i)).jalan();
Perintah ini akan mengambil elemen pada ArrayList mengcasting tipenya, kemudian memanggil metode jalan() pada pemain yang baru diambil tersebut. Tanda kurung di sekitar "(Pemain)paraPemain.get(i)" diperlukan karena aturan dalam Java sehingga perintah dalam kurung akan dijalankan terlebih dahulu sebelum metode jalan() dipanggil.

Vector
Kelas ArrayList diperkenalkan pada Java versi 1.2, sebagai salah satu kumpulan kelas yang digunakan untuk bekerja dengan sekumpulan koleksi objek. Jika akan bahas lebih lanjut tentang "kelas koleksi" pada bagian berikutnya. Versi awal Java tidak memiliki ArrayList, akan tetapi memiliki kelas yang sangat mirip yaitu java.util.Vector. Kita masih bisa melihat Vector digunakan pada program lama, dan dalam beberapa kelas standar Java, sehingga kita perlu tahu tentang kelas ini.
Menggunakan Vector mirip dengan menggunakan ArrayList. Perbedaannya adalah nama metode yang berbeda untuk melakukan tugas yang sama, atau nama metode yang berbeda untuk melakukan tugas yang sama.
Seperti ArrayList, suatu Vector mirip dengan array Object yang bisa berkembang jika diperlukan. Konstruktor new Vector() membuat vektor tanpa elemen.
Misalnya vec adalah suatu Vector. Maka :
  • vec.size() adalah fungsi untuk mengembalikan jumlah elemen di dalam vektor.
  • vec.addElement(obj) akan menambahkan Object obj di akhir vektor. Sama dengan metode add() pada ArrayList.
  • vec.removeElement(obj) menghapus obj dari dalam vektor, kalau ada. Hanya objek pertama yang ditemui akan dihapus. Sama dengan remove(obj) pada kelas ArrayList
  • vec.removeElementAt(N) menghapus elemen ke-N. N harus berada pada rentang 0 hingga vec.size() - 1. Sama dengan remove(N) pada ArrayList
  • vec.setSize(N) akan mengubah ukuran vektor menjadi N. Jika di dalam vektor terdapat elemen yang jumlahnya lebih banyak dari N, maka elemen lainnya akan dihapus. Jika lebih sedikit, maka tempat kosong akan diisi dengan null. Kelas ArrayList tidak memiliki metode seperti ini.
Kelas Vector memiiki banyak metode lagi, akan tetapi ini adalah metode yang sering digunakan.
 

Thursday

ARRAY

Array adalah struktur data yang terdiri dari item berurutan, di mana semua itemnya bertipe sama. Dalam Java, item dalam array selalu dinomori dari nol hingga nilai maksimum tertentu, yang nilainya ditentukan pada saat array tersebut dibuat. Misalnya, suatu array berisi 100 bilangan bulat, yang dinomori dari nol hingga 99. Item dalam array bisa bertipe salah satu tipe Java primitif. Item-item ini bisa juga berupa referensi ke objek, sehingga, misalnya kita bisa membuat array yang berisi semua komponen dalam applet.
Bagian ini akan membahas bagaimana array dibuat dan digunakan pada Java. Juga mencakup kelas standar java.util.ArrayList. Suatu objek bertipe ArrayList sangat mirip dengan array dari Object, akan tetapi ia bisa bertambah ukuran secara dinamis.

PENGENALAN STRUKTUR DATA DAN ALGORITMA

Dalam membuat suatu program kita pasti akan merancang program tersebut dengan konsep dan struktur yang tepat dan dinamis, maksudnya bahwa konsep dan struktur tersebut dimulai dengan perhitungan yang tepat dan proses yang benar dan berurutan. Demikian juga dalam pemrograman Java, struktur data sangat penting untuk memudahkan dalam penegcekan dan edit coding ketika muncul eror. Struktur data dalam Java masih cenderung menggunakan metode diagram trees (pohon), diagram ini sering dibahas dalam mata kuliah Sistem Basis Data.
Sedangkan pengertian Algoritma Sorting adalah kumpulan langkah sistematis atau secara berutan untuk memperoleh hasil yang diinginkan. Salah satu contoh dari algoritma untuk langkah ini adalah Sorting (pengurutan). Sorting dapat didefinisikan sebagai pengurutan sejumlah data berdasarkan nilai tertentu. Pengurutan dapat dilakukan dari nilai terkecil ke nilai terbesar (ascending) atau sebaliknya.

Langsung saja kita bahas satu persatu,

Pemrograman dengan Array

Array merupakan jenis struktur data yang sangat dasar dan sangat penting. Teknik pengolahan array merupakan teknik pemrograman yang paling penting yang kita harus kuasai. Dua jenis teknik pengolahan array -- pencarian dan pengurutan -- akan dibahas kemudian. Bagian ini akan memperkenalkan beberapa ide dasar pengolahan array secara umum.
Dalam banyak hal, pengolahan array berarti menggunakan operasi yang sama kepada setiap elemen di dalam array. Biasanya sering dilakukan dengan perulangan for. Perulangan untuk mengolah semua elemen dalam array A dapat ditulis dalam bentuk :
// lakukan inisialiasi yang diperlukan sebelumnya
for (int i = 0; i < A.length; i++) {
    . . . // proses A[i]
}
Misalnya, A adalah array dengan tipe double[]. Misalnya kita ingin menjumlah semua nilai dalam array tersebut. Algoritma umum untuk melakukannya adalah :
Mulai dengan 0;
Tambah A[0];   (proses elemen pertama di dalam A)
Tambah A[1];   (proses elemen kedua di dalam A)
.
.
.
Tambah A[ A.length - 1 ];   (proses elemen terakhir di dalam A)
Dengan menggunakan pengetahuan yang kita telah pelajari tentang perulangan, kita bisa ubah algoritma di atas menjadi bentuk perulangan for seperti berikut:
double jumlah;  // Jumlah nilai di dalam A
jumlah  = 0;    // Mulai dengan 0
for (int i = 0; i < A.length; i++)
    jumlah += A[i];  // tambah A[i] ke dalam jumlah untuk i = 0, 1, ..., A.length - 1
Lihat bahwa kondisi kelanjutan "i < A.length" menyatakan bahwa nilai i terakhir yang akan diolah adalah A.length - 1 yaitu elemen terakhir dalam array. Ingat bahwa kita menggunakan "<" bukan "<=" karena dengan "<=" komputer akan memberikan kesalahan indeks di luar batas.
Pada akhirnya, nanti Anda akan bisa membuat perulangan seperti di atas di luar kepala. Kita akan lihat beberapa contohnya. Di sini perulangan akan menghitung banyaknya elemen di dalam array A yang nilainya kurang dari nol :
int hitung;  // Untuk menghitung elemen
hitung = 0;  // Mulai dengan nol
for (int i = 0; i < A.length; i++) {
    if (A[i] < 0.0)   // Jika elemen ini kurang dari nol
        hitung++;          // tambah hitung dengan 1
}
// Di sini nilai "hitung" adalah banyaknya elemen yang kurang dari 0.
Kita bisa mengganti "A[i] < 0.0" jika kita ingin menghitung banyaknya elemen di dalam array yang memiliki sifat tertentu. Variasinya akan memiliki tema yang sama. Misalnya kita ingin menghitung banyaknya elemen di dalam array A yang sama dengan elemen sesudahnya. Elemen setelah A[i] adalah A[i+1], sehingga kita bisa mengganti klausa if dengan "if (A[i] == A[i+1])". Akan tetapi tunggu dulu : Tes ini tidak bisa digunakan apabila A[i] adalah elemen terakhir dalam array, karena tidak ada lagi array sesudahnya. Komputer akan menolak pernyataan ini. Sehingga kita harus berhenti satu elemen sebelum array terakhir, sehingga menjadi,
int hitung = 0;
// lihat kondisi for berubah dibandingkan dengan contoh sebelumnya
for (int i = 0; i < A.length - 1; i++) { 
    if (A[i] == A[i+1])
        hitung++;
}
Masalah umum lainnya adalah mencari nilai terbesar di dalam array A. Strateginya adalah lihat semua isi array, catat nilai terbesar saat itu. Kita akan simpan nilai terbesar yang kita temui dalam variabel maks. Pada saat kita melihat elemen array satu per satu, kapanpun kita melihat nilai elemen tersebut lebih besar dari maks kita akan mengganti nilai maks dengan nilai yang lebih besar tersebut. Setelah semua elemen array diproses, maka maks merupakan nilai elemen terbesar di dalam array tersebut. Pertanyaannya adalah, apa nilai awal maks? Salah satu kemungkinannya adalah mulai dengan nilai maks sama dengan A[0], baru kemudian melihat isi elemen array lainnya mulai dengan A[1]. Misalnya,
double maks = A[0];  // nilai maks berisi elemen array pertama
for (int i = 1; i < A.length; i++) {  // i mulai dari elemen kedua
    if (A[i] > maks)
        max = A[i];
}
// Di sini maks berisi nilai elemen array yang paling besar
(Ada masalah yang lebih penting di sini. Java membolehkan array memiliki panjang nol. Artinya bahkan A[0] pun tidak ada di dalam array, sehingga memanggil A[0] akan menghasilkan kesalahan indeks keluar batas. Akan tetapi array biasanya array dengan panjang nol biasanya sesuatu yang kita ingin hindarkan dalam kehidupan sehari-hari. Lagian apa artinya mencari nilai terbesar di dalam suatu array yang panjangnya nol?)
Contoh terakhir dari operasi array, misalnya kita ingin mengkopi suatu array. Untuk mengkopi array A, tidak cukup untuk menggunakan perintah
double[] B = A;
karena perintah ini tidak membuat objek array baru. Yang dibuat di sini adalah variabel baru yang merujuk pada objek yang sama dengan A. (Sehingga perubahan yang terjadi pada A[i] akan juga menyebabkan B[i] berubah). Untuk membuat array baru yang merupakan kopi dari array A, kita harus membuat objek array baru, dan mengkopi isinya satu per satu dari array A ke array baru, sehingga
// Buat objek array baru, yang panjangnya sama dengan panjang A
double[] B = new double[A.length]; 
 
for (int i = 0; i < A.length; i++)
    B[i] = A[i];   // Kopi setiap elemen dari A ke B
Mengkopi nilai dari satu array ke array yang lain adalah operasi umum sehingga Java memiliki subrutin untuk melakukannya, yaitu System.arraycopy(), yang merupakan subrutin anggota statik dari kelas standar System. Deklarasinya memiliki bentuk seperti :
public static void arraycopy(Object arraySumber, int indeksAwalSumber,
    Object arrayTujuan, int indeksAwalTujuan, int jumlah)
di mana arraySumber dan arrayTujuan bisa berbentuk array dengan tipe apapun. Nilai akan dikopi dari arraySumber ke arrayTujuan. jumlah adalah berapa banyak elemen yang akan dikopi. Nilai akan dikopi dari arraySumber mulai dari posisi indeksAwalSumber dan akan disimpan pada arrayTujuan mulai dari posisi indeksAwalTujuan. Misalnya kita akan mengkopi array A, maka kita bisa menggunakan perintah
double B = new double[A.length];
System.arraycopy( A, 0, B, 0, A.length );
Suatu tipe array, misalnya double[] adalah tipe Java biasa, sehingga kita bisa menggunakannya seperti tipe-tipe Java lainnya. Termasuk juga digunakan sebagai parameter formal di dalam suatu subrutin. Juga bisa digunakan sebagai tipe keluaran suatu fungsi. Misalnya, kita bisa menulis fungsi yang membuat kopi array dengan tipe double sebagai berikut :
double[]  kopi( double[] sumber ) {
    // Membuat dan mengembalikan kopi array sumber
    // Jika sumber null, maka kembalikan null
    if ( sumber == null )
        return null;
    double[]  kpi;  // Kopi array sumber
    kpi = new double[sumber.length];
    System.arraycopy( sumber, 0, kpi, 0, sumber.length );
    return kpi;
}
Rutin main() memiliki parameter dengan tipe String[] yang merupakan array String. Ketika sistem memanggil rutin main(), string di dalam array ini adalah parameter dari baris perintah. Jika kita menggunakan konsol, user harus mengetikkan perintah untuk menjalankan program. User bisa menambahkan input tambahan dalam perintah ini setelah nama program yang akan dijalankan.
Misalnya, jika kelas yang memiliki rutin main() bernama programKu, maka user bisa menjalankan kelas tersebut dengan perintah "java programKu" di konsol. Jika kita tulis dengan "java programKu satu dua tiga", maka parameter dari baris perintahnya adalah "satu", "dua", dan "tiga". Sistem akan memasukkan parameter-parameter ini ke dalam array String[] dan memberikan array ini pada rutin main().
Berikut ini adalah contoh program sederhana yang hanya mencetak parameter dari baris perintah yang dimasukkan oleh user.
public class CLDemo {
    public static void main(String[] args) {
        System.out.println("Anda memasukkan " + args.length
            + " parameter dari baris perintah");
        if (args.length > 0) {
            System.out.println("Parameter tersebut adaah :");
            for (int i = 0; i < args.length; i++)
                System.out.println("   " + args[i]);
            }
    } // akhir main()
} // akhir kelas CLDemo
Perhatikan bahwa parameter args tidak mungkin null meskipun tidak ada parameter yang dimasukkan. Jika tidak ada parameter dari baris perintah yang dimasukkan, maka panjang array ini adalah nol.

Hingga sekarang, contoh yang telah diberikan adalah bagaimana mengolah array dengan mengakses elemennya secara berurutan (sequential access). Artinya elemen-elemen array diproses satu per satu dalam urutan dari awal hingga akhir. Akan tetapi salah satu keuntungan array adalah bahwa array bisa digunakan untuk mengakses elemennya secara acak, yaitu setiap elemen bisa diakses kapan saja secara langsung.
Misalnya, kita ambil contoh suatu masalah yang disebut dengan masalah ulang tahun: Misalnya ada N orang di dalam suatu ruangan. Berapa kemungkinan dua orang di dalam ruangan tersebut memiliki ulang tahun yang sama (yang dilahirkan pada tanggal dan bulan yang sama, meskipun tahunnya berbeda)? Kebanyakan orang salah menerka jawabannya. Sekarang kita lihat dengan versi masalah yang berbeda: Misalnya kita memilih orang secara acak dan menanyakan ulang tahunnya. Berapa orang yang Anda harus tanya untuk mendapatkan hari ulang tahun yang sama dengan orang sebelumnya?
Tentunya jawabannya akan tergantung pada faktor yang bersifat acak, akan tetapi kita bisa simulasikan dengan program komputer dan menjalankan beberapa kali hingga kita tahu berapa kira-kira orang harus dicek.
Untuk mensimulasikan percobaan ini, kita harus mencatat semua ulang tahun yang kita sudah tanyakan. Ada 365 kemungkinan hari ulang tahun (Kita abaikan sementara tahun kabisat). Untuk setiap kemungkinan hari ulang tahun, kita perlu tahu, apakah hari ulang tahun tersebut telah digunakan? Jawabannya adalah nilai boolean true atau false. Untuk menyimpan data ini, kita bisa gunakan array dari 365 nilai boolean:
boolean[] sudahDitanya;
sudahDitanya = new boolean[365];
Tanggal-tanggal pada satu tahun dinomori dari 0 hingga 364. Nilai sudahDitanya[i] akan bernilai true jika orang yang kita tanya berulang tahun pada hari tersebut. Pada awalnya semua nilai pada array sudahDitanya[i] bernilai false. Ketika kita memilih satu orang dan menanyakan hari ulang tahunnya, misalnya i, kita akan mengecek terlebih dahulu apakah sudahDitanya[i] bernilai true. Jika tidak maka orang ini adalah orang kedua dengan ulang tahun yang sama. Artinya kita sudah selesai.
Jika sudahDitanya[i] bernilai false, maka belum ada orang sebelum ini yang memiliki hari ulang tahun tersebut. Kita akan ganti sudahDitanya[i] dengan true, kemudian kita akan tanyakan lagi kepada orang lain, dan begitu seterusnya hingga semua orang di dalam ruangan ditanyakan.
static void masalahUlangTahun() {
    // Melakukan simulasi dengan memilih seseorang secara acak
    // dan mengecek hari ulang tahunnya. Jika hari ulang tahunnya
    // sama dengan orang yang pernah kita tanya sebelumnya,
    // hentikan program dan laporkan berapa orang yang sudah dicek
 
    boolean[] sudahDitanya;
    // Untuk mencatat ulang tahun yang sudah ditanyakan
    // Nilai true pada sudahDitanya[i] berarti orang lain
    // sudah ada yang berulang tahun pada hari i
 
    int hitung;
    // Jumlah orang yang sudah pernah ditanya
 
    sudahDitanya = new boolean[365];
    // Awalnya, semua nilai adalah false
 
    hitung = 0;
 
    while (true) {
        // Ambil ulang tahun secara acak dari 0 hingga 364
        // Jika ulang tahun telah ditanya sebelumnya, keluar
        // Jika tidak catat dalam array
 
        int ultah;  // Ulang tahun seseorang
        ultah = (int)(Math.random()*365);
        hitung++;
        if ( sudahDitanya[ultah] )
            break;
        sudahDitanya[ultah] = true;
    }
 
    System.out.println("Ulang tahun yang sama ditemukan setelah menanyakan "
        + hitung + " orang.");
 
} // akhir masalahUlangTahun()
Subrutin ini menggunakan fakta bahwa array boolean yang baru dibuat memiliki seluruh elemen yang bernilai false. Jika kita ingin menggunakan array yang sama untuk simulasi kedua, kita harus mereset ulang semua elemen di dalamnya menjadi false kembali dengan perulangan for
for (int i = 0; i < 365; i++)
    sudahDitanya[i] = false;
Array paralel adalah menggunakan beberapa array dengan indeks yang sama. Misalnya kita ingin membuat beberapa kolom secara paralel -- array x di kolom pertama, array y di kolom kedua, array warna di kolom ketiga, dan seterusnya. Data untuk baris ke-i bisa didapatkan dari masing-masing array ini. Tidak ada yang salah dengan cara ini, akan tetapi cara ini berlawanan dengan filosofi berorientasi objek yang mengumpulkan data yang berhubungan di dalam satu objek. Jika kita mengikuti aturan seperti ini, amaka kita tidak harus membayangkan hubungan data yang satu dan yang lainnya karena semua data akan dikelompokkan di dalam satu tempat.
Misalnya saya menulis kelas seperti
class DataString {
    // Data dari salah satu pesan
    int x,y;        // Posisi pesan
    Color warna;    // Warna pesan
}
Untuk menyimpan data dalam beberapa pesan, kita bisa menggunakan array bertipe DataString[], yang kemudian dideklarasikan sebagai variabel instansi dengan nama data sehingga
DataString[] data;
Isi dari data bernilai null hingga kita membuat array baru, misalnya dengan
data = new DataString[JUMLAH_PESAN];
Setelah array ini dibuat, nilai setiap elemen array adalah null. Kita ingin menyimpan data di dalam objek yang bertipe DataString, akan tetapi tidak ada objek yang dibuat. Yang kita sudah buat hanyalah kontainernya saja. Elemen di dalamnya berupa objek yang belum pernah kita buat. Untuk itu elemen di dalamnya bisa kita buat dengan perulangan for seperti :
for (int i = 0; i < JUMLAH_PESAN; i++)
    data[i] = new DataString();
Sekarang kita bisa mengambil data setiap pesan dengan data[i].x, data[i].y, dan data[i].warna.

Terakhir berkaitan dengan pernyataan switch. Misalnya kita memiliki nilai bulan dari 0 hingga 11, yang melambangkan bulan dalam satu tahun dari Januari hingga Desember. Kita ingin mencetaknya di layar, dengan perintah
switch (bulan) {
case 0:
    bulanString = "Januari";
    break;
case 1:
    bulanString = "Februari";
    break;
case 2:
    bulanString = "Maret";
    break;
case 3:
    bulanString = "April";
    break;
.
.
.
case 11:
    bulanString = "Desember";
    break;
default:
    bulanString = "Salah bulan";
}
Kita bisa mengganti keseluruhan perintah switch tersebut dengan menggunakan array, misalnya dengan array namaBulan yang dideklarasikan sebagai berikut :
static String[] namaBulan = { "Januari", "Februari", "Maret",
    "April", "Mei", "Juni", "Juli", "Agustus", "September",
    "Oktober", "November", "Desember" };
Kemudian kita bisa ganti keseluruhan switch di atas dengan
bulanString = namaBulan[bulan];