Saturday, December 17, 2016

Bab 5. Java Teori dan Implementasi



Metode



5.1 Introduksi

Dimisalkan Anda ingin mencari penjumlahan integer, berturut-turut, dari 1 sampai 10, dari 20 sampai 30, dan dari 35 sampai 45. Anda mungkin akan memiliki kode sebagai berikut:

int jumlah = 0;
for (int i = 1; i <= 10; i++)
jumlah += i;
System.out.println("Jumlah dari 1 sampai 10 adalah " + jumlah);

jumlah = 0;
for (int i = 20; i <= 30; i++)
jumlah += i;
System.out.println("Jumlah dari 20 sampai 30 adalah " + jumlah);

jumlah = 0;
for (int i = 35; i <= 45; i++)
jumlah += i;
System.out.println("Jumlah dari 35 sampai 45 adalah " + jumlah);

Anda dapat mengamati bahwa menghitung penjumlahan integer dari 1 sampai 10, dari 20 sampai 30, dan dari 35 sampai 45 adalah sama kecuali bahwa integer awal dan integer akhir yang berbeda. Apakah tidak lebih mudah bila suatu kode ditulis untuk melakukan penjumlahan integer dan kemudian mendaur-ulangnya (menggunakannya kembali) tanpa perlu menulis-ulangnya? Anda dapat melakukannya lewat pendefinisian metode. Metode dibuat untuk menciptakan kode yang bisa didaur-ulang. Kode sebelumnya dapat disederhanakan sebagai berikut:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static int jumlah(int i1, int i2) {
  int jumlah = 0;
  for (int i = i1; i <= i2; i++)
    jumlah += i;

  return jumlah;
}

public static void main(String[] args) {
  System.out.println("Jumlah dari 1 sampai 10 = " + jumlah(1, 10));
  System.out.println("Jumlah dari 20 sampai 30 = " + jumlah(20, 30));
  System.out.println("Jumlah dari 35 sampai 45 = " + jumlah(35, 45));
}

Baris 1-7 mendefinisikan metode yang bernama jumlah dengan dua parameter i dan j. Statemen-statemen di dalam metode main memanggil jumlah(1, 10) untuk menghitung penjumlahan dari 1 sampai 10, jumlah(20, 30) untuk menghitung penjumlahan dari 20 sampai 30, jumlah(35, 45) untuk menghitung penjumlahan dari 35 sampai 45.

Suatu metode merupakan koleksi statemen-statemen yang dikelompokkan bersama untuk melakukan suatu operasi. Dalam beberapa bab sebelumnya, Anda telah menggunakan beberapa metode yang terdefinisi di dalam pustaka JAVA seperti  System.out.println, JOption-Pane.showMessageDialog, JOptionPane.showInputDialog, Integer.parseInt, Double.parseDouble, System.exit, Math.pow, dan Math.random. Pada bab ini, Anda akan belajar bagaimana mendefinisikan metode Anda sendiri dan menerapkan abstraksi metode untuk menyelesaikan masalah-masalah yang lebih kompleks.


5.2 Mendefinisikan Suatu Metode

Sintaks untuk mendefinisikan suatu metode adalah sebagai berikut:

pemodifikasi tipeNilaiBalik namaMetode(daftar parameter) {
  // Tubuh metode;
}

Sekarang mari kita periksa suatu metode yang diciptakan untuk mencari integer  yang lebih besar dari dua integer. Metode ini, diberi nama max, memiliki dua parameter, num1 dan num2. Salah satu dari kedua integer tersebut dijadikan nilai balik fungsi. Gambar 5.1 mengilustrasikan komponen-komponen metode ini.

Gambar 5.1 Suatu definisi metode yang memuat header metode dan tubuh metode


Header metode memuat pemodifikasi (modifier), tipe nilai balik, nama metode, dan parameter-parameter formal. Pemodifikasi statik digunakan pada semua metode dalam bab ini. Alasan penggunaannya akan dijelaskan pada Bab. 8.

Suatu metode boleh memiliki nilai balik. tipeNilaiBalik adalah tipe data nilai yang dikembalikan oleh suatu metode. Beberapa metode melakukan operasi tanpa perlu memberikan nilai balik. Pada kasus ini, tipeNilaiBalik adalah katakunci void. Sebagai contoh, tipeNilaiBalik adalah void dalam metode main, sama seperti System.exit, System.out.println, dan JOptionPane.showMessageDialog. Jika suatu metode mengembalikan suatu nilai, maka disebut dengan metode pengembali-nilai, sebaliknya disebut dengan metode void.

Variabel-variabel yang didefinisikan dalam header metode dikenal dengan parameter formal atau parameter saja. Ketika suatu metode dipanggil, Anda melewatkan suatu nilai kepada parameter. Parameter ini dikenal dengan parameter aktual. Daftar parameter merujuk pada tipe, urutan, dan jumlah parameter dalam suatu metode. Nama metode dan daftar parameter membentuk sidik metode atau tanda-tangan metode. Parameter bersifat opsional; artinya suatu metode bisa saja tidak memiliki satu parameter pun. Sebagai contoh, metode Math.random() tidak memiliki parameter.

Tubuh metode memuat koleksi statemen yang mendefinisikan apa yang dilakukan suatu metode. Tubuh metode dari metode max menggunakan suatu statemen if untuk menentukan angka mana yang lebih besar dan menjadikan nilai angka tersebut sebagai nilai balik. Agar suatu metode pengembali-nilai dapat memberikan suatu nilai balik, digunakan katakunci return pada nilai balik tersebut. Metode berhenti setelah mengeksekusi statemen return.

Dalam beberapa bahasa pemrograman, metode disebut juga dengan fungsi atau prosedur. Suatu metode pengembali-nilai disebut dengan fungsi; suatu metode void disebut dengan prosedur.

Dalam header metode, Anda perlu mendeklarasikan tipe data setiap parameter secara terpisah. Misalnya, max(int num1, int num2), tetapi max(int num1, num2) adalah salah.

Perbedaan antara “mendefinisikan metode” dengan “mendeklarasikan variabel”. Suatu definisi mendefinisikan item-item yang terdefinisi, tetapi suatu deklarasi biasanya hanya mengalokasikan memori untuk menyimpan data untuk item yang terdeklarasi.


5.3 Memanggil Suatu Metode
Dalam menciptakan suatu metode, Anda mendefinisikan apa yang dilakukan oleh metode tersebut. Untuk menggunakan suatu metode, Anda harus memanggilnya. Ada dua cara memanggil metode, tergantung apakah metode tersebut memiliki nilai balik atau tidak.

Jika metode memberikan suatu nilai balik, maka pemanggilan terhadap metode itu diperlakukan seperti layaknya suatu nilai. Sebagai contoh,

int lebihBesar = max(3, 4);

memanggil metode max(3, 4) dan menugaskan hasil metode itu kepada lebihBesar. Contoh lain yang memperlakukan pemanggilan metode sebagai nilai adalah

System.out.println(max(3, 4));

yang menampilkan nilai balik dari pemanggilan metode max(3, 4).

Jika metode mengembalikan void, maka pemanggilan terhadap metode tersebut harus berupa suatu statemen. Sebagai contoh, metode println memberikan nilai balik void. Pemanggilan berikut ini adalah suatu statemen:

System.out.println("JAVA itu Tangguh!");

Ketika suatu program memanggil suatu metode, kendali program dipindahkan kepada metode yang dipanggil tersebut. Metode yang dipanggil mengembalikan kendali kepada pemanggil setelah statemen return dieksekusi atau ketika kurung kurawal penutup suatu metode diraih. Kode5.1 menampilkan suatu program utuh yang digunakan untuk menguji metode max.

Kode5.1 UjiMax.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class UjiMax {
  /** metode utama */
  public static void main(String[] args) {
    int i = 5;
    int j = 2;
    int k = max(i, j);
    System.out.println("Nilai maksimum antara " + i +
    " dan " + j + " adalah " + k);
  }

  /** Mengembalikan nilai maksimum antara dua angka */
  public static int max(int num1, int num2) {
  int hasil;

  if (num1 > num2)
    hasil = num1;
 else
    hasil = num2;

 return hasil;
 }
}

Keluaran:

Nilai maksimum antara 5 dan 2 adalah 5

Program memuat metode main dan metode max. Metode main sama seperti metode lain, kecuali bahwa metode tersebut dipanggil oleh JVM.

Header metode main selalu sama. Seperti contoh ini, header metode main memuat pemodifikasi public dan static, memberikan nilai balik void, nama metode main, dan suatu parameter tipe String[]. String[] mengindikasikan bahwa parameter merupakan suatu array String, yang akan dibahas pada Bab. 6.

Statemen-statemen di dalam main bisa saja memanggil metode-metode lain yang didefinisikan di dalam kelas yang memuat metode main atau di dalam kelas-kelas lain. Pada contoh ini, metode main memanggil max(i, j), yang didefinisikan di dalam kelas yang sama dengan metode main.

Ketika metode main dipanggil (baris 6), nilai variabel i sebesar 5 dilewatkan kepada num1, dan nilai variabel j sebesar 2 dilewatkan kepada num2 di dalam metode max. Aliran kendali program beralih ke metode max. Kemudian metode max dieksekusi. Ketika statemen return dalam metode max dieksekusi, kendali program dikembalikan kepada pemanggilnya (dalam kasus ini, pemanggil adalah metode main). Proses ini diilustrasikan pada Gambar 5.2.
  
Gambar 5.2 Ketika metode max dipanggil, aliran kendali program beralih kepada metode tersebut. Begitu metode max selesai dieksekusi, kendali program kembali kepada pemanggil

Suatu statemen return dibutuhkan oleh metode pengembali-nilai. Metode yang ditampilkan pada (a) di bawah ini secara legal benar, tetapi memiliki error kompilasi karena kompiler JAVA berpikir bahwa sangat mungkin metode ini tidak mengembalikan nilai balik.

Untuk mengatasi masalah ini, hapuskan if( n < 0) pada (a), sehingga kompiler melihat statemen return untuk dieksekusi apapun hasil evaluasi terhadap statemen if.




Metode memampukan pendaur-ulangan dan pemakaian secara bersama. Metode max bisa saja dipanggil dari sembarang kelas selain kelas UjiMax. Jika Anda menciptakan kelas lain, Anda bisa memanggil metode max menggunakan NamaKelas.namaMetode (misalnya, UjiMax.max).


5.3.1 Tumpukan Pemanggilan
Setiap kali suatu metode dipanggil, sistem menyimpan parameter dan variabel di suatu memori yang dikenal dengan tumpukan, yang menyimpan elemen-elemen secara LIFO (last-in, first-out). Ketika suatu metode memanggil metode lain, ruang memori dalam tumpukan untuk pemanggil dibiarkan utuh, dan ruang memori baru diciptakan untuk menangani pemanggilan metode. Ketika metode yang dipanggil selesai dieksekusi dan kendali program kembali kepada pemanggilnya, maka ruang memori yang tercipta untuk metode yang dipanggil dihapus.

Memahami tumpukan pemanggilan dapat membantu Anda mengerti bagaimana metode-metode dipanggil. Variabel-variabel yang didefinisikan di dalam metode main adalah i, j, dan k. Variabel-variabel yang didefinisikan dalam metode max adalah num1 dan num2. Variabel num1 dan num2 didefinisikan dalam sidik metode dan merupakan parameter metode. Gambar 5.3 mengilustrasikan variabel-variabel di dalam tumpukan.


Gambar 5.3 Ketika metode max dipanggil, aliran kendali program beralih ke metode max. Setelah metode max selesai dieksekusi, kendali program kembali kepada pemanggil.



5.4 Contoh Metode void
Contoh sebelumnya adalah metode pengembali-nilai. Pada bagian ini, ditunjukkan untuk mendefinisikan dan memanggil suatu metode main. Kode5.2 memberikan suatu program yang mendefinisikan suatu metode bernama cetakNilai dan memanggilnya untuk menampilkan nilai untuk skor yang diberikan.

Kode5.2 UjiMetodeVoid.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class UjiMetodeVoid {
  public static void main(String[] args) {
    System.out.print("Nilai adalah ");
    cetakNilai(78.5);

    System.out.print("Nilai adalah ");
    cetakNilai(59.5);
  }

  public static void cetakNilai(double skor) {
    if (skor >= 90.0) {
      System.out.println('A');
    }
    else if (skor >= 80.0) {
      System.out.println('B');
    }
    else if (skor >= 70.0) {
      System.out.println('C');
    }
    else if (skor >= 60.0) {
      System.out.println('D');
    }
    else {
      System.out.println('F');
    }
  }
}

Keluaran:

Nilai adalah C
Nilai adalah F

Metode cetakNilai merupakan suatu metode void, yang tidak mengembalikan nilai apapun. Pemanggilan terhadap suatu metode void harus berupa statemen. Jadi, metode cetakNilai dipanggil sebagai suatu statemen pada baris 4 dalam metode main. Sama seperti statemen dalam JAVA, harus diakhiri dengan tanda titik koma.

Untuk melihat perbedaan antara metode pengembali-nilai dengan metode void, maka kode5.2 akan didesain-ulang menggunakan metode pengembali-nilai. Metode yang baru, dapatNilai, mengembalikan nilai seperti ditunjukkan pada kode5.3.

Kode5.3 UjiMetodePengembaliNilai.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class UjiMetodePengembaliNilai {
  public static void main(String[] args) {
    System.out.print("Nilai adalah " + dapatNilai(78.5));
    System.out.print("\nNilai adalah "+ dapatNilai(59.5));
  }

  public static char dapatNilai(double skor) {
    if (skor >= 90.0)
      return 'A';
    else if (skor >= 80.0)
      return 'B';
    else if (skor >= 70.0)
      return 'C';
    else if (skor >= 60.0)
      return 'D';
    else
      return 'F';
  }
}

Keluaran:

Nilai adalah C
Nilai adalah F


Metode dapatNilai yang didefinisikan pada baris 7-18 memberikan nilai balik berupa suatu karakter nilai berdasarkan nilai skor numerik.

Suatu statemen return tidak dibutuhkan oleh metode void, tetapi bisa digunakan untuk menghentikan metode dan mengalihkan kendali program kepada pemanggil. Sintaksnya cuku sederhana:

return;

Hal ini tidak sering dilakukan, tetapi kadang-kadang dibutuhkan untuk memaksa kendali program di dalam suatu metode void. Sebagai contoh, kode berikut ini memiliki suatu statemen return untuk menghentikan metode ketika skor tidak valid.

public static void cetakNilai(double skor) {
  if (skor < 0 || skor > 100) {
    System.out.println("Skor tidak valid");
    return;
  }

  if (skor >= 90.0) {
    System.out.println('A');
  }
  else if (skor >= 80.0) {
    System.out.println('B');
  }
  else if (skor >= 70.0) {
    System.out.println('C');
  }
  else if (skor >= 60.0) {
    System.out.println('D');
  }
else {
    System.out.println('F');
  }
}


5.5 Melewatkan Parameter Dengan Nilai
Kekuatan suatu metode adalah kemampuannya dalam bekerja dengan parameter. Anda bisa menggunakan println untuk menampilkan sembarang string dan metode max untuk mencari nilai maksimum di antara dua integer. Ketika memanggil suatu metode, Anda perlu menyediakan argumen, yang harus diberikan dalam urutan yang sama dengan parameter pada sidik metode. Hal ini dikenal dengan asosiasi urutan parameter. Sebagai contoh, metode ini menampilkan suatu pesan sebanyak n kali:

public static void nPrintln(String pesan, int n) {
  for (int i = 0; i < n; i++)
    System.out.println(pesan);
}

Anda dapat menggunakan nPrintln(“JAVA”, 3) akan menampilkan “JAVA” sebanyak tiga kali. Statemen nPrintln(“JAVA”, 3)  melewatkan parameter string aktual “JAVA” kepada parameter pesan; melewatkan 3 kepada n; dan mencetak “JAVA” tiga kali. Namun, statemen nPrintln(3, “JAVA”) akan salah. Tipe data 3 tidak cocok dengan parameter pertama, pesan, begitu juga dengan parameter kedua, “JAVA”, tidak sesuai dengan parameter n.

Ketika Anda memanggil suatu metode dengan parameter, nilai argumen dilewatkan kepada parameter. Hal ini disebut dengan pelewatan dengan nilai. Jika argumen adalah suatu variabel, bukan nilai literal, maka nilai variabel tersebut dilewatkan kepada parameter. Nilai variabel tidak terpengaruh oleh perubahan yang terjadi pada parameter di dalam metode. Seperti pada kode5.4, nilai x(1) dilewatkan kepada parameter n untuk memanggil metode inkremen (baris 5). Nilai n diinkremen sebesar 1 di dalam metode (baris 10), tetapi x tetap tidak berubah.

Kode5.4 Inkremen.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Inkremen {
  public static void main(String[] args) {
    int x = 1;
    System.out.println("Sebelum pemanggilan, x adalah " + x);
    inkremen(x);
    System.out.println("Setelah pemanggilan, x adalah " + x);
  }

  public static void inkremen(int n) {
    n++;
    System.out.println("n di dalam metode adalah " + n);
  }
}

Keluaran:

Sebelum pemanggilan, x adalah 1
n di dalam metode adalah 2
Setelah pemanggilan, x adalah 1

Kode5.5 memberikan suatu program lain yang mendemonstrasikan pengaruh pelewatan dengan nilai. Program menciptakan suatu metode untuk menukar dua variabel. metode tukar dipanggil dengan pelewatan dua variabel. Yang menarik adalah bahwa nilai-nilai argumen tidak berubah setelah metode dipanggil.

Kode5.5 UjiPelewatanDenganNilai.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class UjiPelewatanDenganNilai {
  /** Metode utama */
  public static void main(String[] args) {
    // Mendeklarasikan dan menginisialisasi variabel
    int num1 = 1;
    int num2 = 2;

    System.out.println("Sebelum memanggil metode tukar, num1 adalah " +
    num1 + " dan num2 adalah " + num2);

    // Memanggil metode tukar untuk menukar dua variabel
    tukar(num1, num2);

    System.out.println("Setelah memanggil metode tukar, num1 adalah " +
    num1 + " dan num2 adalah " + num2);
  }

  /** Menukar dua variabel */
  public static void tukar(int n1, int n2) {
    System.out.println("\tDi dalam metode tukar");
    System.out.println("\t\tSebelum penukaran n1 adalah " + n1
    + " n2 adalah " + n2);

    // Menukar n1 dengan n2
    int temp = n1;
    n1 = n2;
    n2 = temp;

    System.out.println("\t\tSetelah penukaran n1 adalah " + n1
    + " n2 adalah " + n2);
  }
}

Keluaran:

Sebelum memanggil metode tukar, num1 adalah 1 dan num2 adalah 2
    Di dalam metode tukar
        Sebelum penukaran n1 adalah 1 n2 adalah 2
        Setelah penukaran n1 adalah 2 n2 adalah 1
Setelah memanggil metode tukar, num1 adalah 1 dan num2 adalah 2

Sebelum metode tukar dipanggil (baris 12), num1 adalah 1 dan num2 adalah 2. Setelah metode tukar dipanggil, num1 masih 1 dan num2 masih 2. Kedua nilai tidak saling ditukar. Seperti ditunjukkan pada Gambar 5.4, nilai-nilai argumen num1 dan num2 dilewatkan kepada n1 dan n2, tetapi n1 dan n2 memiliki lokasi memori yang berbeda dari num1 dan num2. Oleh karena itu, perubahan pada n1 dan n2 tidak berpengaruh pada num1 dan num2.

Gambar 5.4 Nilai-nilai variabel dilewatkan kepada parameter-parameter metode


5.6 Kode Modular
Metode bisa digunakan untuk mereduksi kode yang berlebihan dan memampukan pendaur-ulangan kode. Metode juga dapat dipakai untuk memodularkan dan memperbaiki kualitas suatu program.

Kode4.8 memberikan suatu program yang meminta pengguna untuk memasukkan dua integer dan menampilkan GCD atas kedua integer tersebut. Anda bisa menulis-ulang program tersebut menggunakan suatu metode, seperti ditunjukkan pada Gambar 5.6 sebagai berikut:

Kode5.6 MetodeGCD.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.Scanner;

public class MetodeGCD {
  /** Metode utama */
  public static void main(String[] args) {
    // Menciptakan Scanner
    Scanner masukan = new Scanner(System.in);

    // Meminta pengguna memasukkan dua integer
    System.out.print("Masukkan integer pertama: ");
    int n1 = masukan.nextInt();
    System.out.print("Masukkan integer kedua: ");
    int n2 = masukan.nextInt();

    System.out.println("GCD atas " + n1 +
    " dan " + n2 + " adalah " + gcd(n1, n2));
  }

  /** Memberikan nilai balik gcd atas dua integer */
  public static int gcd(int n1, int n2) {
    int gcd = 1;   // gcd awal = 1
    int k = 2;     // gcd yang mungkin

    while (k <= n1 && k <= n2) {
      if (n1 % k == 0 && n2 % k == 0)
      gcd = k; // Perbarui gcd
      k++;
    }
    return gcd;  // Memberikan nilai balik gcd
  }
}

Keluaran:

Masukkan integer pertama: 15
Masukkan integer kedua: 355
GCD atas 15 dan 355 adalah 5

Dengan mengenkapsulasi kode untuk mendapatkan gcd dalam suatu metode, program ini memiliki beberapa keuntungan:
  1. Program mengisolasi masalah untuk menghitung gcd dari bagian kode lain dalam metode main. Jadi, logika programmer menjadi lebih terang dan program mudah dibaca.
  2. Error dalam menghitung gcd dilokalisir di dalam metode gcd, yang mempersempit skop pembetulan error (debugging).
  3. Metode gcd sekarang bisa digunakan oleh program lain.


Kode5.7 menerapkan konsep modularisasi kode untuk memperbaiki kode4.14, AngkaPrima.java.

Kode5.7 MetodeAngkaPrima.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class MetodeAngkaPrima {
  public static void main(String[] args) {
    System.out.println("50 angka prima pertama adalah \n");
    cetakAngkaPrima(50);
  }

  public static void cetakAngkaPrima(int angkaPrima) {
    final int JUMLAH_ANGKA_PRIMA_PER_BARIS = 10; // 10 per baris
    int hitung = 0;   // Menghitung jumlah angka prima
    int angka = 2;    // Angka yang akan diuji keprimaannya

    // Secara berulang menemukan angka-angka prima
    while (hitung < angkaPrima) {
      // Menampilkan angka prima dan menambah hitung
      if( apaPrima(angka)) {
        hitung++; // Menambah hitung

        if (hitung % JUMLAH_ANGKA_PRIMA_PER_BARIS == 0) {
          //Menampilkan angka prima dan mengganti baris
          System.out.printf("%-5s\n", angka);
        }
        else
          System.out.printf("%-5s", angka);
      }

      // Memeriksa apakah angka berikutnya adalah prima
      angka++;
    }
  }

  /** Memeriksa apakah suatu angka prima atau tidak */
  public static boolean apaPrima(int angka) {
    for (int pembagi = 2; pembagi <= angka / 2; pembagi++) {
    if (angka % pembagi == 0) {  // Jika true, angka bukan prima
      return false; // angka bukan prima
    }
  }

  return true; // angka prima
  }
}

Keluaran:

50 angka prima pertama adalah

2    3    5    7    11   13   17   19   23   29  
31   37   41   43   47   53   59   61   67   71  
73   79   83   89   97   101  103  107  109  113 
127  131  137  139  149  151  157  163  167  173 
179  181  191  193  197  199  211  223  227  229 


5.7 Mengkonversi Desimal Menjadi Heksadesimal

Heksadesimal seringkali digunakan dalam pemrograman. Tantangannya di sini adalah menyajikan suatu program yang bisa mengubah desimal menjadi heksadesimal.

Untuk mengkonversi suatu angka desimal  menjadi suatu angka desimal dilakukan pencarian dijit-dijit heksadesimal , dan  sehingga


 Angka-angka ini dapat ditemukan dengan secara terus-menerus membagi  dengan 16 sampai hasil bagi (quotient) 0. Sisa-sisa adalah , dan .

Sebagai contoh, angka desimal 123 adalah 7B dalam heksadesimal. Konversi ini dilakukan sebagai berikut:



Program pada kode5.8 meminta pengguna untuk memasukkan suatu angka desimal dan mengkonversinya menjadi bilangan heksadesimal dalam string.

Kode5.8 KonversiDesimal2Hex.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.util.Scanner;

public class KonversiDesimal2Hex {
  /** Metode utama */
  public static void main(String[] args) {
    // Menciptakan Scanner
    Scanner masukan = new Scanner(System.in);

    // Meminta pengguna memasukkan suatu angka desimal
    System.out.print("Masukkan suatu angka desimal: ");
    int desimal = masukan.nextInt();

    System.out.println("Angka desimal untuk angka desimal " +
    desimal + " adalah " + desimalKeHex(desimal) );
  }

  /** Mengkonversi desimal menjadi heksadesimal sebagai suatu string */
  public static String desimalKeHex(int desimal) {
    String hex = "";

    while (desimal != 0) {
      int nilaiHex = desimal % 16;
      hex =keHexChar(nilaiHex) + hex;
      desimal = desimal / 16;
    }

    return hex;
  }

  /** Mengkonversi integer menjadi satu dijit hex dalam karakter */
  public static char keHexChar(int nilaiHex) {
    if (nilaiHex <= 9 && nilaiHex >= 0)
      return (char)(nilaiHex + '0');
    else // nilaiHex <= 15 && nilaiHex >= 10
      return (char)(nilaiHex - 10 + 'A');
  }
}


Keluaran:

Masukkan suatu angka desimal: 823242
Angka desimal untuk angka desimal 823242 adalah C8FCA

Masukkan suatu angka desimal: 3456
Angka desimal untuk angka desimal 3456 adalah D80

Program menggunakan metode desimalKeHex (baris 18-28) untuk mengkonversi suatu integer desimal menjadi angka heksadesimal dalam string. Metode ini mendapatkan sisa pembagian atas integer desimal oleh 16 (baris 22). Sisa yang didapatkan dikonversi menjadi karakter dengan memanggil metode keHexChar (baris 23). Karakter yang didapatkan kemudian digabungkan ke string heksadesimal (baris 23). String heksadesimal pada mulanya kosong (baris 19).

Metode keHexChar (baris 31-36) mengkonversi suatu nilaiHex antara 0 sampai 15 menjadi suatu karakter heksadesimal. Jika nilaiHex memiliki rentang 0 sampai 9, maka akan dikonversi menjadi (char)(hexValue + '0') (baris 33). Ingat bahwa bila menambahkan suatu karakter dengan suatu integer, maka Unicode atas karakter tersebut digunakan dalam evaluasi. Sebagai contoh, jika diberikan nilaiHex adalah 5, (char)(hexValue + '0') akan memberikan nilai balik sebesar 5. Dengan logika yang sama, jika nilaiHex dalam rentang 10 sampai 15, maka akan dikonversi menjadi (char)(hexValue + 'A') (baris 35). Sebagai contoh, jika diberikan nilaiHex adalah 11, (char)(hexValue + 'A') akan memberikan nilai balik sebesar ‘B’.


5.8 Overloading Metode
Metode max yang telah diciptakan sebelumnya hanya bisa bekerja dengan tipe data int saja. Tetapi bagaimana jika Anda ingin menentukan mana yang tertinggi dari dua angka pecahan? Solusinya adalah menciptakan metode lain dengan nama sama namun dengan parameter-parameter yang berbeda, seperti ditunjukkan pada kode berikut ini:

public static double max(double num1, double num2) {
  if (num1 > num2)
    return num1;
  else
    return num2;
}

Jika Anda memanggil metode max dengan parameter-parameter int, maka metode max dengan dafta parameter int yang dipanggil, Jika Anda memanggil metode max dengan parameter-parameter double, maka metode max dengan dafta parameter double yang dipanggil. Hal ini disebut dengan overloading metode; yaitu bahwa, dua metode dengan nama sama tetapi dengan daftar perameter yang berbeda di dalam satu kelas. Kompiler JAVA yang menentukan metode mana yang digunakan berdasarkan pada sidik metode.

Kode5.9 adalah suatu program untuk menciptakan tiga metode. Yang pertama adalah metode untuk mencari nilai maksimum int, yang kedua adalah metode untuk mencari nilai maksimum double, dan yang ketiga adalah metode untuk mencari nilai maksimum double di antara tiga nilai double.

Kode5.9 UjiOverloadingMetode.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class UjiOverloadingMetode {
  /** Metode utama */
  public static void main(String[] args) {
    // Memanggil metode max dengan parameter-parameter int
    System.out.println("Nilai maksimum antara 3 dan 4 adalah "
    + max(3, 4));

    // Memanggil metode max dengan parameter-parameter double
    System.out.println("Nilai maksimum antara 3.0 dan 5.4 adalah "
    + max(3.0, 5.4));

    // Memanggil metode max dengan tiga parameter double
    System.out.println("Nilai maksimum antara 3.0, 5.4, dan 10.14 adalah "
    + max(3.0, 5.4, 10.14));
  }

  /** Memberikan nilai balik berupa nilai maksium antara dua int */
  public static int max(int num1, int num2){
    if (num1 > num2)
      return num1;
    else
      return num2;
  }

  /** Memberikan nilai balik berupa nilai maksium antara dua double */
  public static double max(double num1, double num2){
    if (num1 > num2)
      return num1;
    else
      return num2;
  }

  /** Memberikan nilai balik berupa nilai maksium antara tiga double */
  public static double max(double num1, double num2, double num3){
    return max(max(num1, num2), num3);
  }
}

Keluaran:

Nilai maksimum antara 3 dan 4 adalah 4
Nilai maksimum antara 3.0 dan 5.4 adalah 5.4
Nilai maksimum antara 3.0, 5.4, dan 10.14 adalah 10.14

Ketika memanggil metode max(3, 4) (baris 6), metode max untuk mencari nilai maksimum dari dua int yang dipanggil. Ketika memanggil metode max(3.0, 5.4) (baris 10), metode max untuk mencari nilai maksimum dari dua double yang dipanggil. Ketika memanggil metode max(3.0, 5.4, 10.14) (baris 14), metode max untuk mencari nilai maksimum dari tiga double yang dipanggil.

Dapatkah Anda memanggil metode max dengan suatu nilai int dan suatu nilai double, seperti max(2, 2.5)? Metode max manakah yang dipanggil? Jawabannya adalah bisa. Metode max untuk mencari nilai maksimum dari dua double yang dipanggil. Nilai argumen 2 secara otomatis dikonversi menjadi suatu nilai double dan dilewatkan kepada metode ini.

Anda mungkin bertanya-tanya mengapa bukan max(double, double) yang dipanggil saat pemanggilan max(3, 4). Kedua max(int, int) dan max(double, double) adalah kecocokan yang mungkin untuk max(3, 4). Kompiler JAVA menerapkan kriteria yang spesifik dalam pemanggilan suatu metode. Karena metode max(int, int) merupakan kriteria yang paling spesifik daripada max(double, double), maka max(int, int) yang digunakan untuk memanggil max(3, 4).

Perhatikan bahwa metode-metode yang dioverload harus memiliki daftar parameter yang berbeda. Anda tidak bisa mengoverload metode berdasarkan pada tipe nilai balik atau pemodifikasi.

Kadang-kala terdapat dua atau lebih kecocokan yang mungkin dalam pemanggilan suatu metode, dan kompiler JAVA tidak bisa menemukan salah satu yang paling spesifik. Hal ini dikenal dengan pemanggilan ambigu. Pemanggilan ambigu menyebabkan error kompilasi. Perhatikan kode berikut ini:

public class OverloadingAmbigu {
  public static void main(String[] args) {
    System.out.println(max(1, 2));
  }

  public static double max(int num1, double num2) {
    if (num1 > num2)
      return num1;
    else
      return num2;
  }

  public static double max(double num1, int num2){
    if (num1 > num2)
      return num1;
    else
      return num2;
  }
}

Kedua max(int, double) dan max(double, int) merupakan kandidat yang mungkin untuk max(1, 2). Karena tidak satupun lebih spesifik dari yang lain, maka hal ini menciptkan pemanggilan ambigu dan menyebabkan error kompilasi.


5.9 Skop Variabel
Skop suatu variabel adalah bagian dari program dimana variabel dapat direferensi. Suatu variabel yang didefinisikan di dalam suatu metode dikenal dengan variabel lokal.



Gambar 5.5 Suatu variabel yang dideklarasikan dalam bagian aksi-awal suatu loop for memiliki skop di dalam keseluruhan loop.

Skop dari suatu variabel lokal dimulai dari pendeklarasian variabel tersebut dan berlanjut ke akhir blok yang memuat variabel itu. Suatu variabel lokal harus dideklarasikan dan ditugasi nilai sebelum digunakan.

Suatu variabel yang dideklarasikan dalam bagian aksi-awal suatu loop for memiliki skop di dalam keseluruhan loop. Tetapi suatu variabel yang dideklarasikan di dalam tubuh loop memiliki skop dimulai dari pendeklarasian variabel tersebut dan berlanjut ke akhir blok yang memuat variabel itu, seperti yang ditampilkan pada Gambar 5.5.

Anda bisa mendeklarasikan suatu variabel lokal dengan nama sama di dalam blok-blok yang berbeda di dalam suatu metode, tetapi Anda tidak bisa mendeklarasikan suatu variabel lokal dua kali di dalam blok yang sama atau di dalam blok-blok nested, seperti pada Gambar 5.6.

Gambar 5.6 Suatu variabel lokal dapat dideklarasikan berkali-kali dalam blok-blok yang tidak nested, tetapi tidak hanya boleh dideklarasikan sekali saja dalam blok-blok nested

Jangan deklarasikan suatu variabel di dalam suatu blok dan kemudian mencoba menggunakannya di luar blok tersebut. Berikut adalah salah satu contoh yang kerap kali terjadi:

for (int i = 0; i < 10; i++) {
}
System.out.println(i);

Statemen terakhir akan menyebabkan suatu error sintaks, karena variabel i tidak terdefinisi di luar loop for.


5.10 Kelas Math
Kelas Math memuat metode-metode yang dibutuhkan untuk melakukan fungsi-fungsi matematik dasar. Anda telah menggunakan metode pow(a, b) untuk menghitung  pada kode2.8, HitungHutang.java dan metode Math.random() untuk pada kode3.4, KuisPengurangan.java. Bagian ini akan mengenalkan Anda tentang metode-metode lain dalam kelas Math. Metode-metode tersebut dikategorikan sebagai metode trigonometrik, metode eksponen, dan metode servis. Di samping metode-metode, kelas Math juga menyediakan dua konstanta double, PI dan E (logaritma natural). Anda bisa menggunakan dua konstanta ini sebagai Math.PI dan Math.E dalam sembarang program.


5.10.1 Metode-Metode Trogonometrik
Kelas Math memuat metode-metode trigonometrik sebagai berikut:

/** Mengembalikan sinus trigonometrik atas suatu sudut dalam radian */
public static double sin(double radian)

/** Mengembalikan kosinus trigonometrik atas suatu sudut dalam radian */
public static double cos(double radian)

/** Mengembalikan tangent trigonometrik atas suatu sudut dalam radian */
public static double tan(double radian)

/** Mengubah sudut dalam derajat menjadi radian */
public static double toRadians(double derajat)

/** Mengubah sudut dalam radian menjadi derajat */
public static double toDegrees(double radian)

/** Mengembalikan sudut dalam radian untuk invers dari sin */
public static double asin(double a)

/** Mengembalikan sudut dalam radian untuk invers dari cos */
public static double acos(double a)

/** Mengembalikan sudut dalam radian untuk invers dari tan */
public static double atan(double a)

Parameter untuk sin, cos, dan tan adalah sudut dalam radian. Nilai balik untuk asin, acos, dan atan adalah derajat dalam radian dengan rentang  sampai . Satu derajat sama dengan  dalam radian, 90 derajat sama dengan , dan 30 derajat sama dengan  dalam radian.

Sebagai contoh,

Math.toDegrees(Math.PI / 2) menghasilkan 90.0
Math.toRadians(30) menghasilkan π/6
Math.sin(0) menghasilkan 0.0
Math.sin(Math.toRadians(270)) menghasilkan -1.0
Math.sin(Math.PI / 6) menghasilkan 0.5
Math.sin(Math.PI / 2) menghasilkan 1.0
Math.cos(0) menghasilkan 1.0
Math.cos(Math.PI / 6) menghasilkan 0.866
Math.cos(Math.PI / 2) menghasilkan 0
Math.asin(0.5) menghasilkan π/6


5.10.2 Metode-Metode Eksponen
Ada lima metode yang berkaitan dengan eksponen dalam kelas Math:

/** Mengembalikan  */
public static double exp(double x)

/** Mengembalikan ln(x) = (x) */
public static double log(double x)

/** Mengembalikan (x) */
public static double log10(double x)

/** Mengembalikan  */
public static double pow(double a, double b)

/** Mengembalikan  untuk x >= 0 */
public static double sqrt(double x)
Sebagai contoh,

Math.exp(1) mengembalikan 2.71828

Math.log(Math.E) mengembalikan 1.0

Math.log10(10) mengembalikan 1.0

Math.pow(2, 3) mengembalikan 8.0

Math.pow(3, 2) mengembalikan 9.0

Math.pow(3.5, 2.5) mengembalikan 22.91765

Math.sqrt(4) mengembalikan 2.0

Math.sqrt(10.5) mengembalikan 3.24


5.10.3 Metode-Metode Pembulatan
Kelas Math memuat lima metode pembulatan:

/** x dibulatkan ke atas ke integer terdekat. Integer ini dikembalikan
  * sebagai suatu nilai double. */
public static double ceil(double x)

/** x dibulatkan ke bawah ke integer terdekat. Integer ini dikembalikan
  * sebagai suatu nilai double. */
public static double floor(double x)

/** x dibulatkan ke integer terdekat. Jika x sama-sama dekat kepada
  * dua integer, maka dibulatkan kepada integer yang genap sebagai
  * suatu nilai  double. */
public static double rint(double x)

/** Mengembalikan (int)Math.floor(x + 0.5). */
public static int round(float x)

/** Mengembalikan (long)Math.floor(x + 0.5). */
public static long round(double x)

Sebagai contoh,
Math.ceil(2.1) mengembalikan 3.0

Math.ceil(2.0) mengembalikan 2.0

Math.ceil(-2.0) mengembalikan –2.0

Math.ceil(-2.1) mengembalikan -2.0

Math.floor(2.1) mengembalikan 2.0

Math.floor(2.0) mengembalikan 2.0

Math.floor(-2.0) mengembalikan –2.0

Math.floor(-2.1) mengembalikan -3.0

Math.rint(2.1) mengembalikan 2.0

Math.rint(-2.0) mengembalikan –2.0

Math.rint(-2.1) mengembalikan -2.0

Math.rint(2.5) mengembalikan 2.0

Math.rint(3.5) mengembalikan 4.0

Math.rint(-2.5) mengembalikan -2.0

Math.round(2.6f) mengembalikan 3 // Mengembalikan int

Math.round(2.0) mengembalikan 2 // Mengembalikan long

Math.round(-2.0f) mengembalikan -2

Math.round(-2.6) mengembalikan -3


5.10.4 Metode max, min, dan abs
Metode max dan min dioverload sehingga memberikan nilai balik berupa angka maksimum dan minimum dari dua angka (int, long, float, atau double). Sebgai contoh, max(3.4, 5.0) menghasilkan 5.0 , dan min(3, 2) menghasilkan 2.

Metode abs dioverload sehingga memberikan nilai balik berupa nilai absolut atas suatu angka (int, long, float, atau double). Sebagai, contoh

Math.max(2, 3) mengembalikan 3

Math.max(2.5, 3) mengembalikan 3.0

Math.min(2.5, 3.6) mengembalikan 2.5

Math.abs(-2) mengembalikan 2

Math.abs(-2.1) mengembalikan 2.1


5.10.5 Metode random
Anda telah menggunakan metode random() untuk membangkitkan suatu nilai double acak dengan rentang lebih besar atau sama dengan 0 dan lebih rendah dari 1 (0 <=Math.random() < 1.0). Metode ini sangat berguna. Anda dapat menggunakannya untuk menuliskan suatu ekspresi sederhana untuk membangkitkan angka-angka acak dengan sembarang rentang. Sebagai contoh,

(int) (Math.random() * 10)        = untuk membangkitkan suatu angka acak 0
                            sampai 9.

50 + (int) (Math.random() * 50)   = untuk membangkitkan suatu angka acak 50
                            sampai 99.

Pada umumnya,

a + (int) (Math.random() * b)     = untuk membangkitkan suatu angka acak a
                                   sampai a + b.

Anda bisa membaca dokumentasi yang informatif untuk kelas Math secara online di http://java.sun.com/ javase/6/docs/api/index.html, seperti tertampil pada Gambar 5.7.

Gambar 5.7 Anda bisa membaca dokumentasi JAVA API secara online


5.11 Studi Kasus: Membangkitkan Karakter Acak
Program komputer dapat mengolah data numerik maupun data karakter. Anda telah banyak melihat contoh yang melibatkan data numerik. Namun, adalah juga penting untuk memahami karakter dan bagaimana memprosesnya.

Seperti yang telah diintroduksi pada 2.13, setiap karakter memiliki Unicode antara 0 sampai FFFF di dalam heksadesimal (65535 dalam desimal). Untuk membangkitkan karakter acak, diperlukan membangkitkan integer acak antara 0 sampai 65535 menggunakan ekspresi berikut ini (perhatikan bahwa karena 0 <= Mat.random() < 1.0, maka Anda perlu menambahkan 1 pada 65535):

(int)(Math.random() * (65535 + 1))

Sekarang didiskusikan bagaimana membangkitkan suatu huruf kecil acak. Unicode atas huruf-huruf kecil adalah integer yang berurutan dari Unicode ‘a’ sampai ‘z’. Unicode atas ‘a’ adalah

(int) ‘a’

Jadi, suatu integer acak dari (int) ‘a’ sampai (int) ‘z’ adalah:

(int)((int)'a' + Math.random() * ((int)'z' - (int)'a' + 1)

Seperti yang telah didiskusikan pada 2.13.3 bahwa semua operator numerik dapat diterapkan terhadap operand-operand char. Operand char dicast menjadi suatu angka bila operand lainnya adalah suatu angka atau suatu karakter. Jadi, ekspresi sebelumnya dapat disederhanakan menjadi:

'a' + Math.random() * ('z' - 'a' + 1)

dan suatu huruf kecil acak adalah

(char)('a' + Math.random() * ('z' - 'a' + 1))

Untuk mengeneralisir diskusi ini, disimpulkan bahwa untuk membangkitkan suatu karakter acak antara ch1 sampai ch2  dengan ch1 < ch2 diperlukan:

(char)(ch1 + Math.random() * (ch2 – ch1 + 1))

Hal ini sederhana tetapi sangat berguna kelak bagi Anda. Berikutnya akan diciptakan suatu kelas bernama KarakterAcak pada kode5.10 dengan lima metode teroverload untuk menghasilkan beberapa tipe karakter acak. Anda bisa menggunakan metode-metode ini dalam proyek perangkat lunak Anda kelak.


Kode5.10 KarakterAcak.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class KarakterAcak {
  /** Membangkitkan suatu karakter acak antara ch1 sampai ch2 */
  public static char dapatKarakterAcak(char ch1, char ch2){
    return (char)(ch1 + Math.random() * (ch2 - ch1 + 1));
  }

  /** Membangkitkan suatu huruf kecil acak */
  public static char dapatHurufKecilAcak(){
    return dapatKarakterAcak('a', 'z');
  }

  /** Membangkitkan suatu huruf besar acak */
  public static char dapatHurufBesarAcak(){
    return dapatKarakterAcak('A', 'Z');
  }

  /** Membangkitkan suatu karakter dijit acak */
  public static char dapatKarakterDijitAcak(){
    return dapatKarakterAcak('0', '9');
  }

  /** Membangkitkan suatu karakter acak */
  public static char dapatKarakterAcak(){
    return dapatKarakterAcak('\u0000', '\uFFFF');
  }
 }


Kode5.11 memberikan suatu program uji untuk menampilkan 300 buah huruf kecil acak.

Kode5.11 UjiKarakterAcak.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class UjiKarakterAcak {
  /** Metode utama */
  public static void main(String[] args) {
    final int JUMLAH_KARAKTER = 175;
    final int KARAKTER_PER_BARIS = 25;

    // Menampilkan karakter acak 'a' sampai 'z', 25 karakter per baris
    for (int i = 0; i < JUMLAH_KARAKTER; i++) {
      char ch = KarakterAcak.dapatHurufKecilAcak();
      if ((i + 1) % KARAKTER_PER_BARIS == 0)
        System.out.println(ch);
      else
        System.out.print(ch);
    }
  }
}

Keluaran:

zgmivzovjjtbvttdrvqongsry
zhekocyyjbplotalqmptznvzp
fgvbiiahvudvqkqdzbkoyalxx
nyteucdyfexjoifgpbzysudru
nyveanuylhssexnfkeeunbtql
copvntkwlactlnkifldplhgub
gmmyxwmucopsomrscgcnenxiy
nqkvavilpcwofgkrdkadpqkgx
tfqngssyychgzfywcakutthbe
xnmdtlyhmkmyynblfjsoizoid
lshdvsefdkdedlzybdxsuforl
chgnhemgtdizxovnuwlyatdmw

LIJGTUCNFVDBWLDVAYDSZNPCU
YWGTWSCGJEUQVAYMEBXZMKOPN
UJIAAUBTAGATGDCGVMGBHRTMZ
ETAEFQDDUOTQLNTGIBUBLCUSP
VNTCAWYXEAFGNKUKMVXSITINM
DWXBPADHMNMBXAPPFTZAANEYJ
HBJVBGXBDFKDASQEXXRMGHVAX
HBBVCOOEMPJTUECPPYNVHTBGY
FUXBDOBVYTRRNUVVKIHVUCBCD
UJRIVJFIWZZADUFLFRSODUYXR
ALMYDYOROJDHVLXCBVZWULMWM
KNZRISDMZEFLFLDUBKZUPMZGM


Baris 9 memanggil dapatHurufKecilAcak yang didefinisikan dalam kelas KarakterAcak. Perhatikan bahwa metode dapatHurufKecilAcak tidak memiliki parameter, tetapi Anda masih harus menggunakan sepasang kurung untuk mendefinisikan dan memanggilnya.


5.12 Abstraksi Metode
Kunci untuk mengembangkan perangkat lunak adalah dengan menerapkan konsep abstraksi. Anda akan belajar banyak level abstraksi dalam buku ini. Abstraksi metode dicapai dengan memisahkan penggunaan suatu metode dari implementasinya. Klien dapat menggunakan suatu metode tanpa perlu mengetahui implementasinya. Detil implementasi dienkapsulasi di dalam metode dan klien tidak perlu mengetahuinya ketika memanggil metode tersebut. Hal ini disebut pula dengan penyembunyian informasi atau enkapsulasi. Jika Anda mengubah implementasinya, klien tidak akan terpengaruh sepanjang Anda tidak mengubah sidik metode. Implementasi metode disembunyikan dari klien dalam suatu “kotak hitam”, seperti ditunjukkan pada Gambar 5.8.

Gambar 5.8 Tubuh metode dapat dianggap sebagai suatu kotak hitam yang memuat implementasi detil.

Anda telah menggunakan metode System.out.print untuk menampilkan suatu string, dan metode JOptionPane.showInputDialog untuk membaca suatu string dari suatu kotak dialog, dan metode max untuk mencari nilai maksimum. Anda juga telah mengetahui bagaimana menuliskan kode untuk memanggil metode-metode tersebut di dalam program Anda, tetapi sebagai seorang pengguna, Anda tidak syaratkan untuk mengetahui bagaimana ketiga metode tersebut diimplementasikan.

Konsep abstraksi metode dapat diterapkan pada proses pengembangan perangkat lunak. Ketika menulis suatu program yang panjang, Anda bisa menggunakan strategi takluk-dan-bagi, yang dikenal dengan stepwise refinement, untuk membagi-bagi program menjadi bagian-bagian kecil dengan masalah-masalah yang lebih kecil. Berikut akan diterapkan pendekatan takluk-dan-bagi untuk menampilkan kalender dari bulan tertentu.


5.12.1 Perancangan Top-Down
Bagaimana Anda memulai menulis suatu program? Apakah Anda langsung memulai mengkode? Banyak programmer pemula seringkali memulai dengan mencari solusi permasalahan sampai ke tingkat detil. Meskipun kedetilan penting dalam tahap akhir, namun perhatian yang terlalu tertuju pada kedetilan dapat menghambat proses penyelesaian-masalah. Untuk membuat langkah penyelesaian masalah selancar mungkin, contoh ini dimulai dengan menerapkan abstraksi metode untuk mengisolasi kedetilan dari perancangan.

Pada contoh ini, masalah dibagi menjadi dua submasalah: mendapatkan masukan dari pengguna, dan menampilkan kalender bulan yang diminta. Pada tahap ini, Anda harus memfokuskan pada apa yang dicapai oleh submasalah ini, bukan pada bagaimana mendapatkan masukan dari pengguna atau bagaimana menampilkan kalender bulan. Anda kemudian dapat menggambarkan suatu struktur agar menolong Anda memvisualisasikan bagaimana mendekomposisi masalah (lihat Gambar 5.9a).


Gambar 5.9 Struktur yang menunjukkan bahwa masalah tampilKalender dibagi menjadi dua submasalah, bacaMasukan dan tampilBulan, dan tampilBulan dibagi lagi menjadi submasalah yang lebih kecil, tampilJudulBulan dan tampilTubuhBulan

Masalah menampilkan kalender dari bulan yang diberikan dapat dibagi menjadi dua submasalah: menampilkan judul bulan, dan menampilkan tubuh bulan, seperti yang ditunjukkan pada Gambar 5.9b. Judul bulan memuat tiga baris: bulan dan tahun, garis sambung, dan nama-nama hari dalam seminggu. Anda perlu mendapatkan nama bulan (misalnya, Januari) dari bulan numerik (misalnya, 1). Hal ini dicapai dalam dapatNamaBulan (Gambar 5.10a).


Gambar 5.10 (a) Untuk tampilJudulBulan, dibutuhkan dapatNamaBulan. (b) tampilTubuhBulan dibagi menjadi submasalah yang lebih kecil

Untuk menampilkan tubuh bulan, Anda perlu mengetahui hari pertama dalam sebulan (dapatHariMulai)  dan berapa banyak hari dalam sebulan (dapatJlhHariDalamSebulan), seperti yang ditunjukkan pada Gambar 5.10b. Sebagai contoh, Desember 2005 memiliki 31 hari, dan 1 Desember 2005 adalah hari Kamis.

Bagaimana Anda mendapatkan hari pada tanggal pertama tiap bulannya? Ada beberapa cara melakukannya. Untuk sementara ini, Anda bisa menggunakan pendekatan berikut ini. Diasumsikan bahwa Anda mengetahui hari awal (hariMulai1800 = 3) untuk 1 Januari 1800 yang merupakan hari Rabu. Anda kemudian dapat menghitung total jumlah hari (totalJumlahHari) dari 1 Januari 1800 sampai tanggal awal bulan kalender. Hari mulai bulan kalender adalah (totalJumlahHari + hariMulai1800) % 7 karena setiap minggu memiliki tujuh hari. Masalah dapatHariMulai kemudian dispesifikasi sebagai dapatTotalJumlahHari, seperti yang ditampilkan pada Gambar 5.11a.


Gambar 5.11 (a) Untuk dapatHariMulai, Anda membutuhkan dapatTotalJumlahHari. (b) dapatTotalJumlahHari didekomposisi menjadi dua submasalah yang lebih kecil.


Gambar 5.12 Struktur yang menunjukkan hubungan hirarki antar submasalah dalam program

Untuk mendapatkan total jumlah hari, Anda perlu mengetahui apakah tahun tersebut leap atau tidak dan jumlah hari pada masing-masing bulan. Jadi dapatTotalJumlahHari kemudian didekomposisi menjadi dua submasalah: apaTahunLeap dan dapatJlhHariDalamSebulan, seperti yang ditampilkan pad Gambar 5.11b. Struktur yang utuh ditampilkan pada Gambar 5.12.


5.12.2 Implementasi Metode
Sekarang perhatian dialihkan kepada implementasi. Pada umumnya, suatu submasalah berkaitan dengan implementasi metode. Anda harus memutuskan modul-modul mana yang diimplementasikan sebagai metode dan mana yang perlu digabungkan dengan metode-metode lain. Keputusan ini hendaknya didasarkan pada apakah keseluruhan program nantinya akan mudah dibaca atau tidak. Pada contoh ini, submasalah bacaMasukan dapat diletakkan pada metode main saja.

Pertama-tama, Anda perlu mengimplementasikan metode main, baru kemudian metode tampilBulan. Jadi, program Anda akan tampak seperti ini:

public class TampilKalender {
  /** Metode utama */
  public static void main(String[] args) {
    Scanner masukan = new Scanner(System.in);

    // Meminta pengguna memasukkan tahun
    System.out.print("Masukkan tahun (misalnya, 2001): ");
    int tahun = masukan.nextInt();

    // Meminta pengguna memasukkan bulan
    System.out.print("Masukkan bulan antara 1 sampai 12: ");
    int bulan = masukan.nextInt();

    // Menampilkan kalender untuk bulan dan tahun yang diminta
    tampilBulan(tahun, bulan);
  }

  /** Konsep implementasi tampilBulan */
  public static void tampilBulan(int tahun, int bulan){
    System.out.print(bulan + " " + tahun);
  }

  /** Konsep implementasi tampilJudulBulan */
  public static void tampilJudulBulan (int tahun, int bulan)
  {
  }

  /** Konsep implementasi dapatTubuhBulan */
  public static void dapatTubuhBulan(int tahun, int bulan)
  {
  }

  /** Konsep implementasi dapatNamaBulan */
  public static String dapatNamaBulan(int bulan)
  {
    return "January";
  }

  /** Konsep implementasi dapatHariMulai */
  public static int dapatHariMulai(int tahun, int bulan)
  {
    return 1;
  }

  /** Konsep implementasi dapatTotalJumlahHari */
  public static int dapatTotalJumlahHari(int tahun, int bulan)
  {
    return 10000;
  }

  /** Konsep implementasi dapatJlhHariDalamSebulan */
  public static int dapatJlhHariDalamSebulan(int tahun, int bulan)
  {
    return 31;
  }

  /** Konsep implementasi apaTahunLeap */
  public static boolean apaTahunLeap(int year)
  {
    return true;
  }
}

Anda bisa mengkompilasi program di atas dan melihat apakah ada error yang terjadi. Selanjutnya akan disajikan detil implementasi metode.


5.12.3 Detil Implementasi
Metode apaTahunLeap dapat diimplementasikan menggunakan kode berikut ini:

return (tahun % 400 == 0 || (tahun % 4 == 0 && tahun % 100 != 0));

Untuk mengimplementasikan dapatJlhHariDalamSebulan, Anda harus memahami fakta-fakta sebagai berikut:
·         Januari, Maret, Mei, Juli, Agustus, Oktober, dan Desember memiliki 31 hari.
·         April, Juni, September, dan Nopember memiliki 30 hari.
·         Pebruari memiliki 28 hari pada tahun reguler dan 29 hari pada tahun leap. Oleh karena itu, pada tahun reguler terdiri-dari 365 hari, dan pada tahun leap 366 hari.
Berikut program utuh diberikan pada kode5.12.

Kode5.12 TampilKalender.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import java.util.Scanner;

public class TampilKalender {
  /** Metode utama */
  public static void main(String[] args) {
    Scanner masukan = new Scanner(System.in);

    // Meminta pengguna memasukkan tahun
    System.out.print("Masukkan tahun (misalnya, 2001): ");
    int tahun = masukan.nextInt();

    // Meminta pengguna memasukkan bulan
    System.out.print("Masukkan bulan antara 1 sampai 12: ");
    int bulan = masukan.nextInt();

    // Menampilkan kalender untuk bulan dan tahun yang diminta
    tampilBulan(tahun, bulan);
  }

  /** Konsep implementasi tampilBulan */
  public static void tampilBulan(int tahun, int bulan){
    // Menampilkan kepala kalender
    tampilJudulBulan(tahun, bulan);
   
    // Menampilkan tubuh kalender
    tampilTubuhBulan(tahun, bulan);
  }

  /** Konsep implementasi tampilJudulBulan */
  public static void tampilJudulBulan (int tahun, int bulan) {
    System.out.println(" " + dapatNamaBulan(bulan)
    + " " + tahun);
    System.out.println("—————————————————————————————-———-———-———-——");
    System.out.println(" Minggu Senin Selasa Rabu Kamis Jumat Sabtu");
  }

  /** Konsep implementasi dapatTubuhBulan */
  public static void tampilTubuhBulan(int tahun, int bulan) {
    // Mendapatkan hari awal tanggal pertama tiap bulan
    int hariMulai = dapatHariMulai(tahun, bulan);
      
    // Get number of days in the month
    int jumlahHariDalamSebulan = dapatJlhHariDalamSebulan(tahun, bulan);
 
    // Padding spasi sebelum hari pertama tiap bulan
    int i = 0;
    for (i = 0; i < hariMulai; i++)
      System.out.print("      ");

    for (i = 1; i <= jumlahHariDalamSebulan; i++) {
      System.out.printf("%6d", i);

      if ((i + hariMulai) % 7 == 0)
        System.out.println();
    }

    System.out.println();
  }

  /** Konsep implementasi dapatNamaBulan */
  public static String dapatNamaBulan(int bulan) {
    String namaBulan = " ";
    switch (bulan) {
      case 1: namaBulan = "Januari"; break;
      case 2: namaBulan = "pebruari"; break;
      case 3: namaBulan = "Maret"; break;
      case 4: namaBulan = "April"; break;
      case 5: namaBulan = "Mei"; break;
      case 6: namaBulan = "Juni"; break;
      case 7: namaBulan = "Juli"; break;
      case 8: namaBulan = "Agustus"; break;
      case 9: namaBulan = "September"; break;
      case 10: namaBulan = "Oktober"; break;
      case 11: namaBulan = "Nopember"; break;
      case 12: namaBulan = "Desember";
    }

    return namaBulan;
 }

  /** Konsep implementasi dapatHariMulai */
  public static int dapatHariMulai(int tahun, int bulan) {
    final int HARI_MULAI_JAN_1_1800 = 3;
    // Mendapatkan total jumlah hari sejak 1/1/1800 ke bulan/1/tahun
    int totalJumlahHari = dapatTotalJumlahHari(tahun, bulan);

    // Kembali ke hari awal bulan/1/tahun
    return (totalJumlahHari + HARI_MULAI_JAN_1_1800) % 7;
  }
 
  /** Konsep implementasi dapatTotalJumlahHari */
  public static int dapatTotalJumlahHari(int tahun, int bulan) {
    int total = 0;

    // Mendapatkan total hari dari 1800 sampai 1/1/year
    for (int i = 1800; i < tahun; i++)
      if (apaTahunLeap(i))
        total = total + 366;
    else
       total = total + 365;

    // Menambahkan hari dari Jan sampai bulan yang diminta
    for (int i = 1; i < bulan; i++)
      total = total + dapatJlhHariDalamSebulan(tahun, i);

    return total;
  }
 
  /** Konsep implementasi dapatJlhHariDalamSebulan */
  public static int dapatJlhHariDalamSebulan(int tahun, int bulan){
    if (bulan == 1 || bulan == 3 || bulan == 5 || bulan == 7 ||
      bulan == 8 || bulan == 10 || bulan == 12)
      return 31;

    if (bulan == 4 || bulan == 6 || bulan == 9 || bulan == 11)
      return 30;

    if (bulan == 2) return apaTahunLeap(tahun) ? 29 : 28;

    return 0; // Jika bulan tidak benar
  }

  /** Konsep implementasi apaTahunLeap */
  public static boolean apaTahunLeap(int tahun) {
    return tahun % 400 == 0 || (tahun % 4 == 0 && tahun % 100 != 0);
  }
}

Keluaran:

Masukkan tahun (misalnya, 2001): 2012
Masukkan bulan antara 1 sampai 12: 11
Nopember 2012
—————————————————————————————-———-———-———-——
 Minggu Senin Selasa Rabu Kamis Jumat Sabtu
                             1     2     3
     4     5     6     7     8     9    10
    11    12    13    14    15    16    17
    18    19    20    21    22    23    24
    25    26    27    28    29    30

Masukkan tahun (misalnya, 2001): 1977
Masukkan bulan antara 1 sampai 12: 4
April 1977
—————————————————————————————-———-———-———-——
 Minggu Senin Selasa Rabu Kamis Jumat Sabtu
                                   1     2
     3     4     5     6     7     8     9
    10    11    12    13    14    15    16
    17    18    19    20    21    22    23
    24    25    26    27    28    29    30

No comments:

Post a Comment