You are on page 1of 607

BAGAIMANA CARA BERPIKIR SEBAGAI ILMUWAN KOMPUTER

Versi Java 

Pengarang 

Allen B. Downey 

Penerjemah 

Wim Permana, wimkhan@yahoo.com

(Bab 6­17)

Muhammad Fuad Dwi Rizki, fuad1986@gmail.com

(Bab 5, 18, 19, 20) 

(Lampiran Foreach Dan Generik)

(Jawaban Latihan)

Agus Juliardi

(Bab 1­4)

1
Copyright 2003 Allen Downey.

Permission is granted to copy, distribute, and/or modify this document under

the terms of the GNU Free Documentation License, Version 1.1 or any later ver­

sion published by the Free Software Foundation; with Invariant Sections being

“Preface”, with no Front­Cover Texts, and with no Back­Cover Texts. A copy

of the license is included in the appendix entitled “GNU Free Documentation

License.”

The GNU Free Documentation License is available from www.gnu.org or by

writing to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,

Boston, MA 02111­1307, USA.

Copyright (c) Terjemahan, Lampiran Foreach dan Generik, dan


Jawaban Latihan © 2006 oleh Wim Permana, Muhammad Fuad Dwi
Rizki, dan Agus Juliardi. Permission is granted to copy,
distribute and/or modify this document under the terms of the
GNU Free Documentation License, Version 1.2 or any later version
published by the Free Software Foundation; with no Invariant
Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled
"GNUFree Documentation License".

2
Daftar Isi 

1. Alur Program..............................................................................................................14

1.1Apa itu Bahasa  Pemrograman?.............................................................................14

1.2 Apa itu program ?.................................................................................................17

1.4 Bahasa Formal dan Natural...................................................................................21

1.5 Program Pertama...................................................................................................24

1.6 Daftar Kata............................................................................................................27

1.7. Latihan.................................................................................................................28

2. Variabel dan Tipenya..................................................................................................31

2.1 Mencetak lebih banyak.........................................................................................31

2.2 Variabel.................................................................................................................33

2.3 Assignment...........................................................................................................34

2.4 Mencetak Variabel................................................................................................36

2.5 Keywords..............................................................................................................38

2.6 Operator................................................................................................................39

2.7 Operasi..................................................................................................................41

2.8 Operator pada String.............................................................................................42

2.9 Komposisi.............................................................................................................43

2.10 Daftar kata...........................................................................................................44

2.11 Latihan­latihan....................................................................................................46

3. Method........................................................................................................................49

3.1 Floating­point........................................................................................................49

3.2 Mengkonversi double ke int..................................................................................51

3.3 Method Matematika..............................................................................................52

3.4 Composition..........................................................................................................54

3
3.5 Menambahkan metode baru..................................................................................55

3.6 Class dan method..................................................................................................59

3.7 Program dengan banyak method...........................................................................61

3.8 Parameter dan argumen........................................................................................62

3.9 Stack diagram.......................................................................................................65

3.10 Metode Dengan Banyak Parameter....................................................................66

3.11 Method dan hasilnya...........................................................................................67

3.12 Daftar kata...........................................................................................................68

3.13 Latihan................................................................................................................69

4. Kondisional dan rekursi..............................................................................................74

4.1 Operator modulus.................................................................................................74

4.2 Percabangan..........................................................................................................74

4.3 Eksekusi Alternatif...............................................................................................76

4.4 Percabangan Berantai...........................................................................................77

4.5 Percabangan Bersarang.........................................................................................78

4.6 The return statement.............................................................................................79

4.7 Konversi Tipe........................................................................................................80

4.8 Recursion..............................................................................................................81

4.9 Diagram Stack Untuk Metode Rekursif................................................................84

4.10 Konvensi dan Divine Law...................................................................................85

4.11 Daftar Kata .........................................................................................................86

4.12 Latihan................................................................................................................87

5. Fruitful methods..........................................................................................................93

5.1 Nilai Kembalian....................................................................................................93

5.2 Pengembangan Program.......................................................................................96

5.3 Komposisi...........................................................................................................100

4
5.4 Overloading........................................................................................................101

5.5 Ekspresi Boolean................................................................................................103

5.6 Operator Logika .................................................................................................104

5.7 Metode Boolean..................................................................................................105

5.8 Lagi tentang Rekursi ..........................................................................................106

5.9 Leap of faith........................................................................................................109

5.10 Satu Contoh Lagi..............................................................................................111

5.11 Daftar Kata........................................................................................................112

5.12 Latihan .............................................................................................................113

6. Iterasi.........................................................................................................................121

6.1 Multiple Assignment...........................................................................................121

6.2 Iterasi ..................................................................................................................123

6.3 Pernyataan While ...............................................................................................123

6.4 Tabel...................................................................................................................126

6.5 Tabel Dua Dimensi.............................................................................................129

6.6 Enkapsulasi dan Generalisasi..............................................................................131

6.7 Metode................................................................................................................133

6.8 Enkapsulasi .... sekali lagi!..................................................................................133

6.9 Variabel Lokal....................................................................................................134

6.10 Generalisasi. Sekali lagi dengannya ................................................................135

6.11 Daftar Kata­Kata...............................................................................................139

6.12 Latihan..............................................................................................................140

7. String.........................................................................................................................145

7.1 Memanggil metode dalam objek.........................................................................145

7.2 Length.................................................................................................................147

7.3 Traversal.............................................................................................................148

5
 7.4 Run­Time errors.................................................................................................149

7.5 Membaca Dokumentasi......................................................................................149

7.6 Metode indexOf..................................................................................................150

7.7 Looping dan Counting........................................................................................153

7.8 Operator Increment dan Decrement....................................................................154

7.9 Strings are Immutable.........................................................................................155

7.10 Strings are Incomparable..................................................................................156

7.11 Daftar Kata­Kata...............................................................................................158

7.12 Latihan..............................................................................................................159

8. Interesting Objects....................................................................................................168

8.1 Apanya yang menarik?.......................................................................................168

8.2 Paket­paket..........................................................................................................168

8.3 Objek Titik (Point)..............................................................................................169

8.4  Variabel Instan...................................................................................................170

8.5 Objek Sebagai Parameter....................................................................................171

8.6 Rectangle.............................................................................................................172

8.7 Objek sebagai tipe kembalian (Return Type).....................................................173

8.8 Objek dapat diubah­ubah (Mutable)...................................................................173

8.9 Aliasing...............................................................................................................175

8.10 Null...................................................................................................................176

8.11 Garbage Collection...........................................................................................177

8.12 Objek dan Primitif.............................................................................................178

8.13 Daftar Kata­Kata...............................................................................................180

8.14 Latihan..............................................................................................................181

9. Membuat Objek Anda Sendiri..................................................................................188

9.1 Definisi­definisi kelas dan tipe­tipe objek..........................................................188

6
9.2 Time ...................................................................................................................189

9.4 Konstruktor Lagi.................................................................................................192

9.5 Membuat Sebuah Objek yang Baru....................................................................193

9.6 Mencetak Sebuah Objek.....................................................................................195

9.7 Operasi Pada Objek.............................................................................................196

9.8 Fungsi­fungsi murni............................................................................................197

9.9 Modifier..............................................................................................................200

9.10 Fill­in Methods..................................................................................................202

9.11 Mana yang terbaik?...........................................................................................203

9.12 Pengembangan secara bertahap vs perencanaan...............................................204

9.13 Generalisasi.......................................................................................................206

9.14 Algoritma..........................................................................................................207

9.15 Daftar Kata­Kata...............................................................................................208

9.16 Latihan .............................................................................................................209

10.Array.........................................................................................................................215

10.1 Mengakses Elemen...........................................................................................216

10.2 Menyalin Array.................................................................................................217

10.3 Bentuk Perulangan for .....................................................................................218

10.4 Array dan Objek................................................................................................220

10.5 Panjang Array...................................................................................................220

10.6 Angka­Angka Acak (Random) ........................................................................221

10.7 Array dari Angka­angka Random (Acak) ........................................................223

10.8 Pencacahan........................................................................................................225

10.9 Histogram..........................................................................................................227

10.10 Solusi Single­Pass...........................................................................................228

10.11 Daftar Kata­Kata.............................................................................................229

7
10.12 Latihan............................................................................................................230

11.Array berisi Objek....................................................................................................238

11.1 Komposisi.........................................................................................................238

11.2 Objek Card........................................................................................................238

11.3 Metode printCard..............................................................................................241

11.4 Metode sameCard.............................................................................................243

11.5 Metode compareCard........................................................................................245

11.6 Array berisi Card..............................................................................................248

11.7 Metode printDeck.............................................................................................250

11.8 Searching..........................................................................................................251

11.9 Tumpukan dan subtumpukan............................................................................257

11.10 Daftar Kata­Kata.............................................................................................258

11.11 Latihan............................................................................................................259

12.Objek berisi Array....................................................................................................261

12.1 Kelas Deck........................................................................................................261

12.2 Shuffling...........................................................................................................264

12.3 Pengurutan (Sorting).........................................................................................265

12.4 Subtumpukan (Subdecks).................................................................................266

12.5 Pengacakan dan Pembagian Kartu (Shuffling and Dealing).............................268

12.6 Mergesort..........................................................................................................270

12.7 Daftar Kata­Kata...............................................................................................274

12.8 Latihan..............................................................................................................274

13.Pemrograman Berorientasi Objek............................................................................280

13.1 Bahasa Pemrograman dan Teknik­tekniknya...................................................280

12.3 Metode Objek dan Metode Kelas......................................................................281

13.3 Objek Terkini....................................................................................................281

8
13.4 Bilangan Kompleks...........................................................................................282

13.5 Fungsi­fungsi dalam Bilangan Kompleks.........................................................283

13.6 Fungsi­fungsi lainnya dalam Bilangan Kompleks............................................285

13.7 Modifier............................................................................................................286

13.8 Metode toString................................................................................................287

13.9 Metode equals...................................................................................................288

13.10 Memanggil Satu Metode Objek dari Metode Objek Lain..............................289

13.11 Keganjilan dan Error.......................................................................................290

13.12 Inheritance.......................................................................................................291

13.13 Lingkaran yang bisa digambar .......................................................................292

13.14 Hierarki Kelas.................................................................................................293

13.15 Rancangan Berorientasi Objek.......................................................................294

13.16 Daftar Kata­Kata.............................................................................................295

13.17 Latihan............................................................................................................296

14.Linked List................................................................................................................298

14.1 Acuan­acuan dalam Objek................................................................................298

14.2 Kelas Node........................................................................................................298

14.3 List sebagai Collection......................................................................................301

14.4 List dan Rekursi................................................................................................302

14.5 Infinite List........................................................................................................304

14.6 Teorema Ambiguitas Fundamental...................................................................305

14.7 Metode Objek Untuk Node­Node.....................................................................306

14.8 Memodifikasi List.............................................................................................307

14.9 Wrappers dan Helpers.......................................................................................308

14.10 Kelas intList....................................................................................................310

14.11 Invariants.........................................................................................................312

9
14.12 Daftar Kata­Kata.............................................................................................313

14.13 Latihan............................................................................................................313

15.Stacks........................................................................................................................316

15.1 Tipe Data Abstrak ............................................................................................316

15.2 The Stack ADT.................................................................................................317

15.3 Objek Stack dalam Java....................................................................................318

15.4 Kelas Pembungkus............................................................................................320

15.5 Membuat Kelas Pembungkus............................................................................321

15.6 Membuat Kelas Pembungkus Lagi...................................................................321

15.7 Mengeluarkan Nilai­Nilai.................................................................................322

15.8 Metode­Metode Bermanfaat dalam Kelas Pembungkus...................................323

15.9 Ekspresi Postfix................................................................................................324

15.10 Parsing............................................................................................................325

15.11 Mengimplementasikan ADT...........................................................................327

15.12 Implementasi Array untuk Stack ADT...........................................................327

15.13 Mengubah Ukuran Array................................................................................329

15.14 Daftar Kata­Kata.............................................................................................332

15.15 Latihan............................................................................................................333

16.Antrian dan Antrian Prioritas...................................................................................337

16.1 ADT Antrian.....................................................................................................338

16.2 Veneer...............................................................................................................340

16.3 Linked Queue....................................................................................................343

16.4 Circular Buffer..................................................................................................345

16.5 Priority Queue...................................................................................................351

16.6 Metaclass...........................................................................................................352

16.7 Implementasi Array untuk Antrian Prioritas....................................................353

10
16.8 Klien Antrian Prioritas......................................................................................355

16.9 Kelas Golfer......................................................................................................357

16.10 Daftar Kata­Kata.............................................................................................360

16.11 Latihan............................................................................................................361

17.Pohon (Trees)...........................................................................................................364

17.1 Simpul Pohon....................................................................................................364

17.2 Membuat Pohon................................................................................................365

17.3 Menelusuri Pohon.............................................................................................366

17.4 Pohon Ekspresi.................................................................................................367

17.5 Penelusuran.......................................................................................................368

17.6 Enkapsulasi.......................................................................................................370

17.7 Mendefinisikan metaclass.................................................................................372

17.8 Mengimplementasikan Metaclass.....................................................................373

17.9 Kelas Vector......................................................................................................374

17.10 Kelas Iterator...................................................................................................377

17.11 Daftar Kata­Kata.............................................................................................378

17.12 Latihan............................................................................................................380

18.Heap..........................................................................................................................384

18.1 Implementasi Pohon menggunakan Array........................................................384

8.2 Analisis Kinerja .................................................................................................389

18.3 Analisis Merge Sort..........................................................................................392

18.4 Overhead...........................................................................................................394

18.5 Implementasi PriorityQueue.............................................................................395

18.6 Definisi Heap ...................................................................................................397

18.7 Penghapusan pada heap....................................................................................398

18.8 Penambahan Heap ............................................................................................400

11
18.9 Kinerja Heap ....................................................................................................401

18.10 Heapsort..........................................................................................................403

18.11 Daftar Kata Kata.............................................................................................404

18.12 Latihan............................................................................................................405

19.Maps.........................................................................................................................407

19.1 Array, Vector, Map...........................................................................................407

19.2 Map ADT..........................................................................................................408

19.3 HashMap built­in..............................................................................................408

19.4 Implementasi Dengan Vector...........................................................................414

19.5 Kelas Abstrak List.............................................................................................422

19.6 Implementasi dengan HashMap........................................................................423

19.7 Fungsi Hash......................................................................................................424

19.8 Mengubah Ukuran Hash Map...........................................................................427

19.9 Kinerja dari pengubahan ukuran.......................................................................428

19.10 Daftar Kata......................................................................................................429

19.11 Latihan............................................................................................................430

20.Kode Huffman..........................................................................................................434

20.1 Variabel­length codes.......................................................................................434

20.2 Tabel frekuensi ................................................................................................435

20.3 Pohon Huffman.................................................................................................437

20.4 Metode super.....................................................................................................440

20.5 Pemecahan Kode...............................................................................................443

20.6 Pengkodean.......................................................................................................444

20.7 Daftar Kata........................................................................................................445

21.Lampiran Foreach dan Generik................................................................................446

Generik......................................................................................................................446

12
Foreach......................................................................................................................448

Daftar Kata ...............................................................................................................451

22.Jawaban Latihan.......................................................................................................452

Bab 2.........................................................................................................................452

Bab 3.........................................................................................................................453

Bab 4.........................................................................................................................456

Bab 6.........................................................................................................................457

Bab 7.........................................................................................................................465

Bab 8.........................................................................................................................471

Bab 9.........................................................................................................................473

Bab 10.......................................................................................................................478

Bab 11.......................................................................................................................488

Bab 12.......................................................................................................................492

Bab 13.......................................................................................................................504

Bab 14 ......................................................................................................................507

Bab 15.......................................................................................................................520

Bab 16.......................................................................................................................537

Bab 17.......................................................................................................................546

Bab 18.......................................................................................................................556

Bab 19.......................................................................................................................566

BAB 20.....................................................................................................................588

23.History .....................................................................................................................606

24.GNU Free Documentation License..........................................................................606

13
BAB 1

Alur Program

Tujuan dari buku ini dan kelas ini adalah untuk mengajarkan anda untuk berfikir seperti 

ahli   komputer.   Saya   menyukai   cara   berfikir   ahli   komputer   karena   mereka 

menggabungkan beberapa fitur matematika, engineering, dan ilmu alam. Seperti ahli 

matematika,   ilmu   komputer   menggunakan   bahasa   formal   untuk   mengutarakan   ide 

(secara   spesifik   komputasi).   Seperti   seorang   engineer,   komputer   mendesain   sesuatu, 

mengumpulkan komponen kedalam sistem dan mengevaluasi alternatif antar pertukaran 

data. Seperti seorang ilmuwan,  komputer meneliti sifat kompleksitas sistem, hipotesa 

form dan prediksi tes.

Salah   satu   dari   kemampuan   penting   dari   komputer   adalah   pemecahan   masalah 

(Problem­Solving). Dengan pengertian kemampuan untuk memformulasikan masalah, 

berfikir   secara   kreatif   pemecahannya   dan   mengekspresikan   solusi   secara   jelas   dan 

sayarat.   Dengan   demikian,   proses   dari   pembelajaran   ke   program   merupakan 

kesempatan  sempurna   untuk  mempraktekkan  kemampuan   pemecahan  masalah.  Oleh 

karena itu bab ini dinamakan “Alur Program”.

Di level pertama, Anda akan belajar program yang merupakan kemampuan berguna 

untuk diri sendiri. Di level lainnya Anda akan menggunakan pemrograman yang berarti 

suatu berakhir. Jika kita pelan maka akhirnya akan menjadi jelas.

1.1Apa itu Bahasa  Pemrograman?

Bahasa Pemrograman yang akan Anda pelajari adalah Java, yang relatif masih baru 

14
(Sun   merilis   versi   pertama   pada   bulan   mei   1995).   Java   merupakan   contoh   bahasa 

tingkat tinggi; bahasa tingkat tinggi lainnya yang mungkin pernah Anda dengar adalah 

pascal, C, C++, dan FORTRAN.

Seperti yang Anda duga selain Bahasa Tingkat Tinggi ada juga Bahasa Tingkat Rendah. 

Kadang­kadang dikenal juga dengan bahasa mesin atau bahasa asembly. Dengan kata 

lain   komputer   hanya   dapat   mengeksekusi   program   dalam   bahasa   tingkat   rendah. 

Sehingga   program   yang   ditulis   menggunakan   bahasa   tingkat   harus   diterjemahkan 

terlebih dahulu sebelum dapat di Jalankan. Terjemahan ini akan memakan waktu dan 

itulah sedikit kekurangan dari bahasa tingkat tinggi.

Akan   tetapi   keuntungannya   sangat   banyak,   pertama,   sangatlah   mudah   membuat 

program dengan bahasa tingkat tinggi, mudah dalam arti program dapat dibuat dalam 

waktu  singkat,  cepat dan mudah  dibaca dan mudah untuk  dikoreksi.  Kedua, bahasa 

tingkat tinggi bersifat portable, yang berarti bahwa bahasa tingkat tinggi dapat berjalan 

diberbagai komputer yang berbeda   dengan sedikit ataupun tanpa modifikasi. Bahasa 

tingkat rendah hanya dapat berjalan pada satu macam komputer saja dan harus ditulis 

ulang jika dijalankan pada komputer lainnya.

Dengan   beberapa   keuntungan   ini,   hampir   semua   program   yang   ditulis   dengan 

menggunakan   bahasa   tingkat   tinggi.   Bahasa   tingkat   rendah   hanya   digunakan   untuk 

aplikasi tertentu saja. Ada dua cara dalam menterjemahkan program;   diterjemahkan 

(intrepeter)   atau   di   compile.   Penterjemah   (intrepeter)   adalah   sebuah   program   yang 

membaca  program   tingkat  tinggi  dan  menerjemahkan   perintahnya.  Sebagai  efeknya, 

program diterjemahkan per baris. Secara berurutan membaca baris dan melaksanakan 

perintahnya.

15
Compiler   adalah   sebuah   program   yang   membaca   suatu   bahasa   tingkat   tinggi   dan 

menterjemahkan   semua   sekaligus   sebelum   mengeksekusi   perintah.   Biasanya   Anda 

sering   membuat program secara terpisah lalu mengeksekusi kodenya diakhir. Dalam 

kasus   ini   program   tingkat   tinggi   dinamakan   source   code   dan   terjemahan   program 

dinamakan object code atau executable.

Sebagai   contoh   sekiranya   Anda   menulis   program   dalam   bahasa   C.   Anda   mungkin 

menggunakan teks editor untuk menulis program (teks editor adalah editor sederhana). 

Ketika program selesai, Anda mungkin menyimpannya dalam sebuah file dengan nama 

program.c, dimana “program” adalah nama file. Dan akhiran .c adalah convensi yang 

menandai kode program dalam bahasa C. 

Lalu,   berdasarkan   programming   environment   yang   Anda   sukai,   Anda   bisa 

meninggalkan   text   editor   dan   menjalankan   compilernya.   Compiler   akan   membaca 

source code anda, menterjemahkannya, dan membuat file baru yang bernama program.o 

yang berisi kode objek atau program.exe yang executable.

16
Pada bahasa Java tidak seperti biasa karena langsung dikompilasi dan di interpreted. 

Sebagai ganti terjemahan bahasa Java ke bahasa mesin, Java Compiler men generate 

java byte code. Byte code sangat mudah diinterpretasikan seperti bahasa tingkat tinggi. 

Seperti   itu,   dimungkinkan   untuk   mengkompile   program   java   pada   satu   mesin,   lalu 

mentransfer byte code ke mesin lain dengan jaringan. lalu menginterpretasikan byte 

code  ke  mesin lainnya. Kemampuan ini adalah salah satu keunggulan Java diantara 

banyak keunggulan lainnya sebagai bahasa tingkat tinggi.

Walaupun proses ini tampak rumit, pada kebanyakan lingkungan pemrograman (kadang 

disebut   development   environment),   langkah   ini   langsung   secara   otomatis.   Biasanya 

Anda hanya menulis program dan menekan tombol compile untuk meng­compile dan 

untuk menjalankannya. Disisi lain hal ini berguna untuk mengetahui langkahnya dan 

apa   yang   terjadi   pada   layar.   Sehingga   jika   terjadi   kesalahan   Anda   dapat   langsung 

memperbaikinya.

1.2 Apa itu program ?

Program   adalah   urutan   dari   perintah­perintah   tertentu   untuk   melaksanakan   proses 

komputasi. Komputasi dapat berupa beberapa perhitungan matematika, seperti halnya 

menyelesaikan suatu sistem persamaan untuk menemukan akar­akar polinomial. Akan 

17
tetapi juga bisa berupa sebuah simbol komputasi seperti searching, dan replacing teks 

pada sebuah dokumen atau cara lain (meng­compile sebuah program).

Perintah yang kita sebut sebagai suatu pernyataan, kelihatan berbeda pada setiap bahasa 

pemrograman yang berbeda tetapi terdapat beberapa operasi dasar yang kebanyakan 

bahasa menyediakan:

Input  :memasukkan   data   dari   keyboard,   atau   sebuah   file,   atau   beberapa 

perangkat lain.

Output  :menampilkan data dari layar dan membuat sebuah file atau perangkat 

lain.

Math  :menyelesaikan   operasi   dasar   matematika   seperti   penambahan,   dan 

perkalian.

Testing  :mencek     kondisi   tertentu   dan   meng­eksekusi   urutan   dari   pernyataan 

yang sesuai.

Repetition  :melakukan suatu aksi secara berulang biasanya dengan beberapa variasi.

Semua hal diatas sangatlah baik. Setiap program yang pernah Anda gunakan, tak

masalah   itu   rumit,   terdiri   dari   pernyataan­pernyataan   yang   melaksanakan   beberapa 

operasi. Lalu satu cara untuk menggambarkan pemrograman yaitu sebuah proses dari 

Task yang besar dan kompleks menjadi subtask yang kecil  bahkan sampai pada subtask 

yang cukup sederhana yang dilakukankan dengan satu operasi­operasi dasar.

Sebagai contoh, dalam bahasa inggris, sebuah kalimat harus dimulai dengan huruf besar 

dan diakhiri dengan periode. Kalimat mengandung syntax error. Begitupun dengan yang 

satu ini. Untuk kebanyakan pembaca , beberapa syntax yang error bukanlah masalah 

yang signifikan. Yang mana sama halnya kenapa kita membaca puisi yang mengabaikan 

apabila ada kesalahan.

18
Compiler tidak memperbolehkan satu kesalahan.Jika ada satu kesalahan pada program 

Anda , compiler akan menampilkan pesan kesalahan dan   lalu keluar. Sehingga Anda 

tidak bisa menjalankan program  Anda.

Untuk mempersulit persoalan, ada beberapa peraturan syntax pada Java yang dalam 

bahasa inggris, dan pesan kesalahan yang anda terima dari compiler sering tidak banyak 

membantu. Selama beberapa minggu pertama pembuatan program anda, kemungkinan 

Anda   akan   menghabiskan   waktu   untuk   mencari   kesalahan   syntax.     Semakin   anda 

mendapatkan   pengalaman   maka   anda  semakin   sedikit   melakukan   kesalahan   dan 

semakin cepat menemukan error.

1.3.2 RUN­TIME ERROR

Tipe kedua dari error adalah Runtime error. Disebut demikian karena error yang terjadi 

tidak   muncul   sampai   program   dijalankan.   Pada   Java   runtime   errror   terjadi   ketika 

interpereter menjalankan byte code dan terjadi suatu kesalahan.

Untungnya,   Java   cenderung   merupakan   bahasa   yang   aman.   Yang   berarti   runtime 

errornya jarang, terutama pada program singkat yang sederhana yang akan kita tulis 

untuk beberapa minggu selanjutnya kedepan.

Kemudian dalam semester nanti, Anda kemungkinan akan melihat lebih jelas tentang 

run time error. Terutam ketika kita membicarakan tentang objek dan reference. (Bab 8).

Pada Java runtime error dinamakan exceptions, dan pada kebanyakan environment itu 

muncul pada windows dengan kotak dialog   yang mengandung informasi tentang apa 

yang terjadi  dan apa yang program kan ketika itu terjadi. Informasi ini berguna untuk 

19
proses Debugging.

1.3.3 Logics error dan semantics

Tipe ketiga dari error adalah logical dan semantics errror. Jika ada logical error pada 

program Anda, maka akan di compile dan berhasil di run dengan pengertian komputer 

tidak akan men­generate setiap pesan kesalahan. Akan tetapi hal itu bukan hal yang 

benar.  Ada hal  lain yang akan dilakukan   yaitu program melakukan apa yang anda 

suruh.

Masalahnya program yang anda tulis bukanlah program yang anda inginkan. Artinya 

programnya (semantiknya) salah. Mengindentifikasi logical error sangat sulit. Karena 

itu   mengharuskan   anda   untuk   kembali   melihat   output   program   dan   mencoba   untuk 

memperbaiki apa yang telah dilakukan.

1.3.4 Experimental debugging

Salah   satu   dari   kemampuan   penting   yang   akan   Anda   dapatkan   dikelas   ini   adalah 

debugging. Walaupun itu dapat menimbulkan frustasi , debugging adalah salah satu dari 

hal yang beralasan, menantang dan menarik dalam sebuah pemrograman. 

Dengan kata lain debugging seperti pekerjaan detektif. Anda dihadapkan pada petunjuk, 

dan anda harus menyimpulkan proses dan kejadian yang mengarah pada hasil yang anda 

lihat.

Debugging juga seperti ilmu percobaan. Sesekali Anda memiliki ide apa yang akan 

salah, Anda memperbaiki program dan mencobanya lagi. Jika hipotesis Anda benar, 

20
lalu Anda dapat memprediksi hasil dari modifikasi, lalu Anda mengambil langkah yang 

terdekat untuk mengerjakan program. Jika hipotesis Anda salah Anda harus mengulang 

lagi   membuat   program   yang   baru.   Sherlock   Holmes   mengatakan:   ”jika   Anda   telah 

mengeliminasi   ketidakmungkinan,   maka   apa   saja   yang   tersisa   haruslah   benar”   (dari 

Conan Doyle's The Sign of Four).

Kebanyakan   orang   mengatakan,   programming   dan   debugging   adalah   sama.   Bahwa 

programming merupakan suatu proses yang berangsur­angsur dari debugging sebuah 

program   sampai   akhirnya   menjadi   program   yang   diinginkan.   Artinya   bahwa   Anda 

memulai   program   kerja   dengan   melakukan   sesuatu,   membuat   modifikasi   kecil   lalu 

melakukan debugging sehingga Anda selalu memiliki program kerja.

Sebagai contoh, Linux adalah sistem operasi yang terdiri dari beribu baris kode akan 

tetapi itu awalnya berasal dari program sederhana Linus Tovards yang digunakan untuk 

mengeksplorasi Intel 3086 Chips. Menurut Larry Grandfield ” Satu dari Linus project 

adalah sebuah program yang berasal dari cetakan AAAA dan BBBBB.  Ini nantinya 

akan menjadi Linux”.(Panduan Pemakai Linux Beta versi 1).

Di bab selanjutnya Saya akan lebih menyarankan untuk mempelajari tentang debugging 

dan latihan program lainnya.

1.4 Bahasa Formal dan Natural

Bahasa   Natural   adalah   bahasa   yang   diucapkan   oleh   orang,   seperti   bahasa   Inggris, 

Spanyol,   dan   perancis.   Bahasa   Natural   tidak   dibuat   oleh   manusia   (walaupun   orang 

mencoba mengatakan demikian), bahasa natural tercipta secara alami.

21
Bahasa  Formal adalah bahasa yang di desain orang untuk aplikasi tertentu. Sebagai 

contoh,   notasi   matematika   menggunakan   bahasa   formal   yang   umumnya   baik   untuk 

menjelaskan   hubungan   antara   angka   dan   simbol.   Ahli   kimia   menggunakan   bahasa 

formal untuk merepresentasikan struktur molekul kimia dan banyak lagi.

Bahasa pemrograman adalah bahasa formal yang di desain untuk 

mengekpresikan suatu komputasi

Seperti   yang   disebutkan   diawal,   bahasa   formal   mempunyai   aturan   yang   tegas   pada 

syntax. Sebagai contoh, 3+3= 6 adalah pernyataan matematika yang syntaxnya  benar. 

Tetapi 3= 6$ bukan. Juga H2O adalah syntax yang benar secara kimia. Tapi 2Zz tidak 

benar.

Peranan syntax ada dua, sebagai tanda dan struktur.  Tanda adalah elemen dasar dari 

suatu   bahasa.   Seperti   kata   dan   angka   dan   unsur­unsur   kimia.   Satu   masalah   dengan 

3=+6$ bahwa $ bukanlah tanda yang benar secara matematika (sejauh yang saya tahu). 

2Zz salah karena tidak ada unsur dengan tanda Zz.

Yang   kedua   jenis   aturan   sintaksis   menyinggung   kepada   struktur   suatu   statemen, 

maksudnya suatu tanda diatur. Statemen 3=+6$ dari sudut bangunannya tidak benar, 

sebab Anda tidak bisa mempunyai suatu tanda pertambahan setelah suatu tanda sama 

dengan. Dengan cara yang sama, rumusan molekular harus mempunyai tulisan di bawah 

baris setelah nama unsur, yang sebelumnya tidak.

Ketika Anda membaca suatu kalimat di dalam Bahasa Inggris atau suatu statemen di 

dalam suatu bahasa formal, Anda harus menggambarkan ke luar apa struktur kalimat 

22
tersebut (walaupun di dalam suatu bahasa alami yang Anda lakukan ini tanpa disadari). 

Proses ini disebut parsing.

Sebagai contoh, ketika Anda mendengar kalimat, “Sepatu lain  jatuh," Anda memahami 

bahwa “sepatu lain" adalah subjek dan “jatuh" adalah kata kerja.  Sekali anda sudah 

menguraikan   suatu   kalimat,   anda   dapat   menggambarkan   apa   maknanya,   itu   adalah 

makna semantik dari sebuah kalimat. Asumsikan bahwa Anda mengetahui sepatu apa 

itu, dan apa makna jatuh, anda akan memahami implikasi yang umum dari kalimat ini.

Bagaimanapun bahasa alami dan formal mempunyai banyak fitur pada tanda, struktur, 

sintaksis dan semantik ada banyak perbedaan.

Ambiguitas:   Bahasa   alami   adalah   penuh   dengan   kerancuan,   yang   mana   orang 

berhadapan dengan dengan penggunaan tanda dan informasi lainnya. Bahasa  formal 

dirancang dengan hampir atau sama sekali tidak bersifat ambigu, yang berarti bahwa 

semua statemen persis mempunyai satu arti dengan mengabaikan konteks.

Redudancy: Dalam rangka mengejar kerancuan dan mengurangi salah paham, bahasa 

alami banyak mengandung redudancy. Sebagai hasilnya, bahasa alami sering bertele­

tele. Bahasa formal adalah lebih sedikit lebih ringkas dan tidak berlebih lebihan.

Harfiah: Bahasa alami penuh dengan idiom dan kiasan. Jika Saya mengatakan,sepatu 

lain   jatuh,"   kemungkinan  tidak   ada   sepatu   dan  tidak   ada   apapun   yang   jatuh.Bahasa 

formal persis seperti apa yang dikatakan. Orang berbicara tentang suatu bahasa alami 

sering   mempunyai   kesulitan   pada   waktu   menyesuaikan   ke   bahasa   formal.   Dalam 

beberapa hal perbedaan antara bahasa formal dan bahasa alami seperti perbedaan antara 

23
sebuah puisi dan prosa, tetapi:

Puisi: Kata­kata digunakan untuk bunyinya juga untuk maksud/artinya , dan syair/puisi 

yang utuh bersama­sama menciptakan suatu efek atau tanggapan emosional. Kerancuan 

sering merupakan kesengajaan.

Prosa:Arti   kata­kata   secara   harfiah   lebih   penting   dan   pemberdayaan   struktur   lebih 

berarti. Prosa jadilah lebih bisa dianalisa dibanding puisi, namun sering rancu.

Program:   Arti   dari   suatu   program   komputer   tidak   ambigu   dan   jelas,   dan   dapat 

dipahami seluruhnya oleh analisa tanda dan struktur.

Di   sini   adalah   beberapa   usul   untuk   membaca   program   (   dan   bahasa   formal   lain). 

Pertama, ingat bahwa bahasa formal jauh lebih tebal/padat dibanding   bahasa alami, 

sehingga memakan waktu lebih untuk memahaminya. Strukturnya juga sangat penting, 

jadi bukanlah gagasan yang baik jika membaca dari atas sampai ke bawah, dari kiri ke 

kanan.   Sebagai   gantinya   belajar   menguraikan   kalimat   program   dapat 

mengidentifikasikan     tanda   dan   menginterpretasikan   struktur.   Yang   akhirnya,   ingat 

bahwa   perihal   detil.   Hal­Hal   kecil   seperti   mengeja   kesalahan   dan   tanda   baca   tidak 

baik,dapat Anda hindari dari bahasa alami, dapat membuat suatu perbedaan besar di 

dalam suatu bahasa formal.

1.5 Program Pertama

Biasanya   program   pertama   orang­orang   pada   suatu   bahasa   baru   dinamakan   dengan 

“Hello World." sebab semuanya itu menampilkan “Hello world" Di dalam bahasa Java, 

programnya seperti :

24
class Hello {

// main: generate some simple output

public static void main (String[] args) {

System.out.println ("Hello, world.");

Sebagian   orang   menilai   mutu   suatu   bahasa   program   terlihat   dari   kesederhanaannya 

“Hello World" Program. Dengan standard ini, bahasa Java tidak melakukan seluruhnya 

dengan baik. Bahkan program yang paling sederhana berisi sejumlah code yang sulit 

dijelaskan pada para programmer pemula. Mari kita abaikan semuanya terlebih dahulu. 

Sekarang, saya akan menjelaskan beberapa.

Semua program terdiri dari definisi kelas, yang mempunyai format:

class CLASSNAME {

public static void main (String[] args) {

STATEMENTS

Di sini CLASSNAME menunjukkan bahwa suatu nama dapat anda tentukan sendiri. 

Nama kelas pada contoh ini adalah Hello.

25
Pada baris yang kedua, kata public static void anda abaikan dulu, tetapi perhatikan kata 

main. main adalah suatu nama khusus yang menandai tempat dimana program akan 

mulai. Ketika program berjalan, program akan mulai dengan mengeksekusi statemen di 

dalam main dan itu berlanjut sampai sampai akhir statemen, dan kemudian keluar.

Tidak ada batas jumlah dari statemen yang terdapat di dalam main, pada contoh hanya 

berisi   satu.   Ini   merupakan   suatu   statemen   cetakan,   maksudnya   bahwa   itu   mencetak 

suatu pesan pada layar, dengan kata lain berarti mengirimkan sesuatu ke printer. Dalam 

buku ini saya tidak akan banyak mengatakan tentang mengirimkan berbagai hal kepada 

printer. Tetapi akan mencetaknya pada layar.

Statemen   yang   mencetak   berbagai   hal   pada   layar   adalah   System.Out.Println,   Dan 

diantara tanda kurung adalah hal yang akan dicetak. Pada bagian akhir statemen ada 

suatu titik koma (;) , yang mana diperlukan pada ujung tiap­tiap statemen.

Ada   beberapa   lain   yang   anda   perlu   perhatikan   tentang   sintaksis   dari   program   ini. 

Pertama, bahasa Java menggunakan kurung kurawal ( { dan }) untuk mengolongkan 

sesuatu secara bersama. Kurung kurawal yang paling jauh ( baris 1 dan 8) berisi definisi 

kelas , dan bagian dalam berisi definisi dari main.

Perhatikan baris 3 mulai dengan //. Ini menandakan pada baris ini berisi komentar pada 

teks   Bahasa   Inggris   anda   dapat   menaruhnya     pada   pertengahan   program,   biasanya 

menjelaskan apa yang program kerjakan. Ketika compiler melihat tanda //, maka akan 

mengabaikan segalanya dari sana sampai akhir baris.

26
1.6 Daftar Kata

Problem­solving:   Proses   merumuskan   suatu   masalah,menemukan   suatu   solusi,   dan 

menyatakan solusi itu.

High­level language: Suatu bahasa program seperti bahasa Java yang dirancang untuk 

memudahkan manusia untuk membaca dan menulis.

Low­level   language:   Suatu   bahasa   program   yang   dirancang   untuk   memudahkan 

komputer   untuk   melaksanakannya.  Juga   disebut   ”bahasa   mesin"   atau   ”bahasa 

assembly”.

Bahasa formal: Bahasa yang sudah dirancang untuk mempresentasikan suatu gagasan 

matematika atau program komputer. Semua bahasa program adalah bahasa formal.

Bahasa alami: Bahasa orang yang manapun itu sudah terbentuk secra alami.

Portabilitas:   Suatu   properti   dari   suatu   program   yang   dapat   berjalan   lebih   dari   satu 

macam komputer.

Interpreted: Untuk mengeksekusi suatu program di dalam suatu high­level language 

menterjemahkannya perbaris pada waktu yang sama.

Compile: Untuk menterjemahkan suatu program di dalam suatu high­level language ke 

dalam suatu low­level­language, untuk kemudian di eksekusi.

Source   program:   Suatu   program   di   dalam   suatu   high­level   language   sebelum   di­

compile.

Object Code: Keluaran compiler, setelah menterjemahkan program itu.

Executable: Nama lain untuk object code yang siap untuk dieksekusi.

ByteCode: Semacam object code khusus digunakan untuk Program Java. Byte Code 

serupa   dengan   suatu   low­level   language,   tetapi   portable   sama   seperti   high­level 

language.

27
Statement: Bagian dari suatu program yang merupakan sesuatu yang akan dikan ketika 

program berjalan. Suatu cetakan statemen menyebabkan keluaran pada layar.

Comment: Bagian dari suatu program yang berisi informasi tentang program, tetapi itu 

tidak mempunyai efek ketika program berjalan.

Algorithm: Suatu proses umum untuk memecahkan suatu kategori permasalahan.

Bug: Suatu kesalahan di dalam suatu program.

Syntax: Struktur suatu program.

Semantic: Arti dari suatu program.

Parse: Untuk menguji dan menganalisis suatu struktur syntax sebuah program.

Syntax  error: Suatu kesalahan di dalam suatu program yang membuatnya mustahil 

untuk di parsing.

Exception:   Suatu   kesalahan   di   dalam   suatu   program   yang   membuatnya   gagal   pada 

waktu dijalankan. Biasa disebut run­time error.

Debugging: Proses untuk menemukan dan membuang ke tiga macam kesalahan.

1.7. Latihan

Latihan 1.1

Ilmuwan   Komputer   mempunyai   kebiasaan   menggunakan   kata­kata   Bahasa   Inggris 

untuk mengartikan sesuatu yang berbeda dengan maksud Bahasa Inggris secara umum. 

Sebagai contoh, didalam Bahasa Inggris, suatu pernyataan dan suatu komentar adalah 

hal hampir sama bagusnya, tetapi ketika kita sedang berbicara sekitar suatu program, 

mereka umumnya berbeda­beda.

Daftar kata pada akhir masing­masing bab dimaksudkan untuk menyoroti kata­kata dan 

ungkapan yang mempunyai arti khusus didalam ilmu pengetahuan komputer. Ketika 

anda melihat kata­kata yang telah dikenal, jangan berasumsi bahwa anda mengetahui 

28
apa artinya!

a. Didalam komputer jargon, apa perbedaan antara suatu statemen dan suatu komentar?

b. Apa artinya bahwa suatu program dikatakan portable ?

c. Apa yang dimaksud dengan executable?

Latihan 1.2

Sebelum   anda   melakukan   yang   lain,   cari   tahu   bagaimana   cara   menyusun   dan 

menjalankan   Program   Java   didalam   environtment   yang   anda   gunakan.   Beberapa 

environtment menyediakan contoh program yang serupa dengan contoh pada bagian 

1.5.

a. Ketik program ”Hello World”, kemudian compile dan Run.

b.Tambahkan suatu statemen yang dapat mencetak pesan kedua setelah “Hello World". 

Sesuatu yang lucu seperti, Anda apa kabar? Compile dan Run lagi.

c.Tambahkan suatu baris komentar pada program dimana saja dan Compile. Lalu Run 

lagi. Komentar yang baru mestinya tidak mempunyai effect pada program setelah di 

Run.

Latihan ini mungkin tampak sepele, tetapi itu adalah awal dari banyak program yang 

akan kita kerjakan nanti. Dalam mendebug dengan perceaa diri, anda harus mempunyai 

percaya   diri   pada   environment   pemrograman   anda.   Dalam   beberapa   environment, 

sangat mudah untuk kehilangan jejak program yang mana yang sedang dieksekusi, dan 

anda   mungkin   menemukannya   diri   berusaha   mendebug   suatu   program   ketika   anda 

menjalankan program yang lain. Menambahkan (dan mengubah) suatu cetakan statemen 

merupakan   hal   yang   sederhana   untuk   menetapkan   hubungan   antara   program   yang 

sedang anda perhatikan dan keluarannya ketika program diRun.

29
Latihan 1.3

Adalah   suatu   hal  baik  jika anda  melakukan  banyak  kesalahan,  sehingga   anda  dapat 

melihat apa yang salah dengan cara melihat pemberi tahu kesalahan pada compiler. 

Kadang­kadang compiler akan memberi tahu anda  tepatnya apa yang salah, dan anda 

harus  membereskan   kesalah  itu.   Kadang­kadang,  walaupun  demikian,   compiler   juga 

akan   memberi   tahu   banyak   kesalahan   yang   tidak   semestinya.   Anda   akan   sedikit 

memakai nalar ketika anda mempercayai compiler dan anda harus hati­hati.

a. Hapus salah satu dari kurung kurawal pembuka.

b. Hapus salah satu dari kurung kurawal yang terdekat.

c. Sebagai ganti main, tulis mian.

d. Hapus kata static.

e. Hapus kata public.

f. Hapus kata System.

g. Gantikan println dengan pintln.

h.Gantikan println dengan print. Yang ini adalah suatu hal ketat sebab merupakan suatu 

kesalahan logika, bukan kesalahan sintaksis. Statemen ”System.Out.Print” adalah 

legal tetapi mungkin iya atau mungkin bukan apa yang anda harapkan.

i. Hapus salah satu dari tanda kurung. Tambahkan lagi lebih dari itu.

30
Bab II 

Variabel dan Tipenya

2.1 Mencetak lebih banyak

Seperti yang telah saya sebutkan pada bab yang lalu, Anda dapat meletakkan sebanyak 

apapun statemen pada main. Sebagai contoh, untuk mencetak lebih dari satu baris :

class Hello {

// main: generate some simple output

public static void main (String[] args) {

System.out.println ("Hello, world.");  // print one line

System.out.println ("How are you?");  // print another

Juga, seperti yang anda lihat, adalah legal untuk menaruh komentar pada akhir suatu 

baris, seperti halnya sejajar dengan baris itu. Ungkapan yang nampak tanda kutipnya 

disebut “string”, sebab karena terdiri dari suatu urutan string huruf. sebetulnya, string 

bisa berisi kombinasi huruf, angka­angka, tanda baca, dan karekter khusus lainnya.

println   adalah   singkatan   dari   “print   line"   sebab   setelah   masing­masing   baris   itu 

ditambahkan suatu khusus khusu yang dinamakan newline, yang menyebabkan cursor 

untuk bergerak ke baris yang berikutnya. Setelah itu Println dilibatkan, teks yang baru 

muncul pada baris berikutnya.

Menampilkan   output   dari   banyak   cetakan   statemen   dalam   satu   baris   sangatlah 

31
bermanfaat. satu baris. Anda dapat mekannya command print berikut:

// main: generate some simple output

public static void main (String[] args) {

System.out.print ("Goodbye, ");

System.out.println ("cruel world!");

Dalam hal ini keluaran akan nampak   pada satu baris seperti Goodbye, cruel world!. 

Perhatikan bahwa ada suatu spasi antara kata “Goodbye” dan tanda kutip yang kedua. 

Spasi ini muncul pada Output, dan mempunyai efek pada program. Spasi yang muncul 

diluar tanda kutip biasanya tidak mempunyai efek pada program. Sebagai contoh, saya 

bisa sudah menulis :

class Hello {

public static void main (String[] args) {

System.out.print ("Goodbye, ");

System.out.println ("cruel world!");

Program ini akan dicompile dan diRun sama halnya sebelumnya. Tulisan pada bagian 

akhir   (   newlines)   juga   tidak  mempunyai   efek   pada   program,   maka   saya   bisa  sudah 

menulis :

32
class Hello { public static void main (String[] args) {

System.out.print ("Goodbye, "); System.out.println

("cruel world!");}}

Ini juga bisa, walaupun anda mungkin melihat bahwa program menjadi semakin sulit 

dan lebih sulit untuk membaca. Baris baru dan spasi bermanfaat untuk mengorganisir 

program anda secara visual, membuat program lebih mudah untuk membaca program 

itu dan menempatkan kesalahan sintax.

2.2 Variabel

Salah   satu   keunggulan   fitur   suatu   bahasa   pemrograman   adalah   kemampuan   untuk 

memanipulasi variabel. Suatu variabel adalah lokasi yang menyimpan suatu nilai. Nilai 

adalah berbagai hal yang dapat dicetak dan disimpan (kita akan lihat kemudian) yang 

dioperasikan.String yang telah kita cetak (" Hello, World.", " Goodbye", dll.) adalah 

nilai.

Dalam  menyimpan  suatu  nilai, anda  harus menciptakan suatu  variabel.  Karena nilai 

yang ingin kita simpan adalah string, maka kita akan mendeklarasikan variabel baru 

sebagai suatu string :

String fred;

Statemen ini merupakan suatu deklarasi, karena mendklarasikan variabel bernama

fred  yang   bertipe  string.   Masing­masing   variabel   mempunyai   suatu   tipe   yang 

menentukan     tipe   nilai   apa   yang   akan   disimpan.   Sebagai   contoh,   tipe  int    dapat 

menyimpan bilangan bulat, dan tidak mungkin akan menyimpan tipe string.

33
Anda   akan   melihat   bahwa   beberapa   tipe   dimulai   dengan   huruf   besar   dan   beberapa 

dengan   huruf   kecil..   Kita   akan   belajar   arti   dari   perbedaan   ini   nanti,   tetapi   untuk 

sekarang anda benar­benar perlu untuk berhati­hati. Ada tipe selain Int atau string, dan 

compiler akan menolak jika anda mencoba membuat sendiri tipe data.

Untuk membuat suatu variabel bilangan bulat, sintaknya seperti int bob; , dimana bob 

adalah nama yang dapat anda tulis sembarang. Secara umum, anda akan menulis suatu 

nama variabel yang mengindikasikan variabel yang ingin anda bentuk. Sebagai contoh, 

jika anda melihat deklarasi variabel ini:

String firstName;

String lastName;

int hour, minute;

Anda   mungkin   bisa   menerka­nerka   tentang   nilai   apa   yang   akan   disimpan   oleh   tipe 

tersebut. Contoh ini memperlihatkan sintak untuk medemonstrasikan berbagai variabel 

dengan   tipe   yang   sama:  hour  dan  minute  kedua­duanya   merupakan   bilangan   bulat 

( tipe int).

2.3 Assignment

Sejak kita sudah menciptakan beberapa variabel, kita ingin menyimpan suatu nilai pada 

variabel tersebut. Kita akan mekannya dengan Assignmen Statement.

fred = "Hello.";  // give fred the value "Hello."

34
hour = 11;  // assign the value 11 to hour

minute = 59;  // set minute to 59

Contoh ini menunjukkan tiga assignment, dan komentar menunjukkan tiga perbedaan 

cara orang menyatakan tentang assignment statement. Kosa katanya jadi meragukan di 

sini, tetapi gagasan secara langsung:

 ketika   anda   mendeklarasikan   suatu   variabel,   anda   menciptakan   suatu   nama 

untuk lokasi penyimpanan.

 Ketika anda mekan assignment terhadap suatu variabel, anda memberinya suatu 

nilai.

Suatu cara umum untuk mempresentasikan suatu variabel secara tertulis adalah dengan 

menggambarkan suatu kotak dengan nama variabel diluarnya dan nilai variabel pada 

didalamnya. Gambar ini menunjukkan efek dari ke tiga assignment statemen :

Untuk   masing­masing  variabel,  nama  variabel   nampak  di  luar     kotak  itu   dan  nilai 

nampak di dalam.

Pada umumnya, suatu variabel harus mempunyai tipe yang sama seperti meng assign 

nilai. Anda tidak bisa menyimpan suatu string didalam minute atau suatu bilangan bulat 

didalam fred.

Di sisi lain, aturan itu bisa meragukan, karena ada banyak cara yang dapat anda kan 

35
dalam   mengkonversi   nilai­nilai   dari   satu   tipe   ke   tipe   lain,   dan   Java   kadang­kadang 

mengkonversi  berbagai  hal   secara  otomatis.  Maka  sekarang  anda   perlu  ingat  aturan 

yang umum, dan kita akan memperbicangkannya secara khusus nanti.

Hal   lain   yang   meragukan   adalah   bahwa   beberapa  string  kelihatan   seperti   bilangan 

bulat, tetapi sesungguhnya bukan. Sebagai contoh,  fred  mengandung string   " 123", 

yang mana terdiri dari karakter 1, 2 dan 3, tapi itu tidak sama halnya seperti nomor 123.

fred = "123";  // legal

fred = 123;  // not legal

2.4 Mencetak Variabel

Anda   dapat   mencetak  nilai  suatu   variabel  menggunakan  perintah   yang  sama   seperti 

yang kita gunakan untuk mencetak Strings.

class Hello {

public static void main (String[] args) {

String firstLine;

firstLine = "Hello, again!";

System.out.println (firstLine);

Program ini menciptakan suatu variabel yang bernama  firstLine, meng assign nya ke 

36
dalam     nilai   "   Hello,   Again!"   dan   kemudian   mencetak   nilainya.   Ketika   kita 

memperbicangkan   tentang   “mencetak   suatu   variabel,"   kita   berarti   mencetak   nilai 

variabel  itu.  Untuk  mencetak  nama  suatu  variabel,  anda  harus  menaruhnya  didalam 

tanda kutip. Sebagai contoh: System.Out.Println (" Firstline");

Jika anda ingin lebih detail , anda bisa menulis :

String firstLine;

firstLine = "Hello, again!";

System.out.print ("The value of firstLine is ");

System.out.println (firstLine);

Keluaran dari program ini adalah :

The value of firstLine is Hello, again!

Saya  senang  untuk  mengatakan  bahwa  sintak  untuk  mencetak  suatu  variabel  adalah 

sama halnya dengan mengabaikan jenis variabel itu.

int hour, minute;

hour = 11;

minute = 59;

System.out.print ("The current time is ");

System.out.print (hour);

System.out.print (":");

System.out.print (minute);

37
System.out.println (".");

Keluaran dari program ini adalah :  The current time is 11:59.

PERINGATAN: Ini adalah praktek umum untuk menggunakan beberapa perintah print 

yang   diikuti   oleh  println,   untuk   meletakkan   berbagai   nilai   pada   Baris   yang   sama. 

Tetapi   anda   harus   hati­hati   perintah  println  pada   bagian   akhir.   Pada   banyak 

environment  keluaran   dari  print  disimpan   tanpa   dipertunjukkan   sampai   perintah 

println dilibatkan, di mana keseluruhan baris dipertunjukkan dengan segera. Jika anda 

menghilangkan println, program bisa berakhir tanpa pernah mempertunjukkan keluaran 

yang disimpan!

2.5 Keywords

Beberapa bagian yang lalu, saya berkata bahwa anda dapat membuat nama apapun yang 

anda butuhkan untuk variable, tetapi itu tidak selalu benar. Ada kata­kata tertentu yang 

tersedia pada Java sebab itu digunakan oleh compiler untuk menguraikan struktur dari 

program anda, dan jika anda menggunakannya sebagai nama variabel, akan menjadi 

kacau. Kata­kata ini disebut  keywords, meliputi  public,  class,  void,  int, dan banyak 

lagi yang lain.

Daftar yang lengkap ada tersedia pada :

http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html

Lokasi ini, yang disediakan oleh Sun, meliputi Dokumentasi Java yang akan mengacu 

38
pada keseluruhan isi buku.

Dengan menghafal daftar itu, saya jamin anda mendapat keuntungan dari fitur yang 

disediakan   pada   banyak   Java   Development   environment   :   Kode   yang   di   tampilkan. 

Dalam   mengetik,   bagian­bagian   berbeda   dari   program   anda   perlu   tampak   berbeda 

warnanya.   Sebagai   contoh,   kata   kunci   boleh   jadi   biru,   string   merah,   dan   lain   kode 

hitam. Jika anda mengetik suatu nama variabel dan warnya biru, awas! Anda mungkin 

menemukan hal yang  aneh  dari compiler itu.

2.6 Operator

Operator adalah lambang khusus yang digunakan untuk mempresentasikan perhitungan 

sederhana seperti penambahan dan perkalian. Kebanyakan dari operator didalam Java 

persisnya seperti apa yang anda inginkan, sebab itu adalah lambang matematika secara 

umum.   Sebagai   contoh,   operator   untuk   menambahkan   dua   bilangan   bulat   adalah   +. 

Yang   berikut   adalah   semua   ekpresi   yang   legal   menurut   Java   yang   mana   artinya 

kelihatan lebih jelas:

1+1  hour­1  hour*60 + minute  minute/60

Ungkapan   dapat   berisi   nama   dan   nomor   variabel.   Pada   setiap   kasus   nama   variabel 

digantikan dengan   nilai sebelum perhitungan nya     dikan. Penambahan, pengurangan 

dan   perkalian   semua   yang   anda   inginkan,   tetapi   anda   mungkin   dikagetkan   oleh 

pembagian. Sebagai contoh, program yang berikut:

int hour, minute;

hour = 11;

minute = 59;

39
System.out.print ("Number of minutes since midnight: ");

System.out.println (hour*60 + minute);

System.out.print ("Fraction of the hour that has passed: ");

System.out.println (minute/60);

akan menghasilkan keluaran yang berikut:

Number of minutes since midnight: 719

Fraction of the hour that has passed: 0

Baris yang pertama adalah apa yang kita harapkan, tetapi baris yang kedua adalah aneh. 

Nilai menit variabel adalah 59, dan 59 yang dibagi oleh 60 adalah 0.98333, bukan 0. 

Pertentangan ini disebabkan bahwa Java mekan pembagian dalam bilangan bulat.

Ketika   kedua  operand  adalah   bilangan   bulat   (operand  adalah   suatu   operasi   pada 

operator), hasilnya harus jadi suatu bilangan bulat, dan bilangan bulat bersifat selalu 

membulatkan   kebawah,   bahkan   pada   kasus   seperti   ini   dimana   bilangan   bulat   yang 

berikutnya menjadi sangat dekat.

Suatu   alternatif   yang   mungkin   dalam   hal   ini   adalah   untuk   mengkalkulasi   suatu 

persentase dibanding pecahan:

System.out.print ("Percentage of the hour that has passed: ");

System.out.println (minute*100/60);

Hasilnya :

40
Percentage of the hour that has passed: 98

Lagi­lagi hasil dibulatkan bawah, tetapi setidaknya sekarang jawabannya sudah benar. 

Dalam memperoleh jawaban yang lebih sayarat lagi, kita bisa menggunakan suatu tipe 

variable   berbeda,  yang   disebut  floating­point,  yang   mampu untuk   menyimpan  nilai 

yang kecil.Kita akan mempelajari itu pada bab berikutnya.

2.7 Operasi

Ketika lebih dari satu operator muncul pada suatu ekspresi, evaluasi bergantung pada 

nilai  precedence.   Suatu   penjelasan   lengkap   tentang   nilai   precedence   sangat   rumit, 

namun untuk mengetahuinya anda dapat memulai:

• Perkalian dan pembagian mempunyai kedudukan lebih tinggi ( dikan sebelum) 

penambahan   dan   pengurangan.   Maka  2*3­1  hasilnya  5,   bukan  4,   dan  2/3­1 

hasilnya ­ 1, bukan 1 ( ingat bahwa pembagian bilangan bulat 2/3 adalah 0).

• Jika operator mempunyai kedudukan yang sama maka akan dievaluasi dari kiri 

ke kanan. Maka didalam ungkapan ini  menit*100/60, perkalian dikan terlebih 

dulu, hasil dari  5900/60 adalah  98. Jika operasi dikan dari kanan ke kiri, hasil 

59*1 adalah 59, dan itu salah. 

• Kapanpun Jika anda ingin mengesampingkan ketentuan­ketentuan nilai precende 

(   atau   anda   tidak   tahu   pasti   apa   hasilnya)   anda   dapat   menggunakan   tanda 

kurung. Ungkapan didalam tanda kurung dievaluasi terlebih dahulu, maka 2* 

41
( 3­1)  4. Anda  dapat juga menggunakan tanda kurung untuk membuat suatu 

ungkapan lebih mudah untuk membaca, seperti di ( menit* 100) / 60,walaupun 

itu tidak mengubah hasil.

2.8 O perator pada  String

Secara umum anda tidak bisa melaksanakan operasi matematika pada String, sekalipun 

string  kelihatan   seperti   angka­angka.   Yang   berikut   adalah   tidak   benar   (jika   kita 

mengetahui bahwa fred mempunyai tipe string)

fred ­ 1  "Hello"/123  fred * "Hello"

Ngomong­ngomong,   dengan   memperhatikan   ekspresi   tersebut   dapatkan   anda 

menunjukkan bahwa  fred  adalah suatu  integer  atau  string? Tidak. Satu­Satunya cara 

mengetahui   jenis   suatu   variabel   adalah   dengan   melihat   tempat   dimana   variabel   itu 

dideklarasikan.

Menariknya, operator + dapat dikan pada string, walaupun itu tidak kan persis dengan 

apa yang anda harapkan. Untuk  string, operator + menghasilkan penggabungan, yang 

berarti   menggabungkan   dua  operand.   Sehingga   "   Hello,"+   "   World."   menghasilkan 

string   Hello,World. dan  fred+  "  ism" berarti menambahkan akhiran ism itu kepada 

ujung kata fred  apapun tipe fred ini dipakai sebagai format baru.

42
2.9 Ko m p osisi

Sejauh ini kita sudah melihat di unsur­unsur suatu variabel bahasa program, ungkapan, 

dan   statements   tertutup,   tanpa   membicarakan   tentang   bagaimana   cara 

menggabungkannya.

Salah satu cirri dari bahasa program paling bermanfaat   adalah kemampuan mereka 

untuk   mengambil   satu   bagian   blok   kecil   dan   menyusunnya.   Sebagai   contoh,   kita 

mengetahui bagaimana cara mengalikan angka­angka dan kita mengetahui bagaimana 

cara mencetaknya, itu dapat kita sayakan kedua­duanya pada waktu yang sama:

System.out.println (17 * 3);

Sebenarnya, saya seharusnya tidak mengatakan “pada waktu yang sama," karena pada 

kenyataannya perkalian harus terjadi sebelum pencetakan, tetapi intinya adalah bahwa 

ungkapan manapun menyertakan angka­angka, string, dan variabel, dapat digunakan di 

dalam suatu statemen cetakan. Kita telah melihat satu contoh:

System.out.println (hour*60 + minute);

Tetapi anda dapat juga menaruh ungkapan pada sembarang tempat pada sisi kanan dari 

suatu statemen tugas:

int percentage;

percentage = (minute * 100) / 60;

43
Kemampuan ini tidak lagi nampak sangat mengesankan sekarang, tetapi kita akan lihat 

contoh lain dimana komposisi memungkinkan untuk menyatakan perhitungan kompleks 

dengan rapi dan dengan singkat.

PERINGATAN:   Ada   batas   dimana   anda   dapat   menggunakan   ungkapan   tertentu; 

khususnya, dari sisi kiri dari suatu tugas statemen haruslah  nama suatu variabel, bukan 

suatu ekspresi. Itu disebabkan pada sisi yang kiri menandai adanya tempat penyimpanan 

hasil nantinya. Ungkapan tidak mempresentasikan tempat penyimpanan, hanya

nilai. Sehingga yang berikut adalah tidak benar: minute+1= hour;

2.10 Daftar kata

Variabel: Suatu nama tempat dimana suatu nilai disimpan. Semua variabel mempunyai 

suatu tipe, yang dideklarasikan ketika suatu variable dibuat.

Value:   Suatu   angka   atau   string   (atau   hal   alin   yang   dinamai   kemudian)   yang   dapat 

disimpan pada suatu variabel. Tiap­Tiap nilai kepunyaan satu tipe.

type:  Suatu  set  nilai.  Tipe  suatu  variabel  menentukan  dalam  penyimpanan  nilainya. 

Sejauh ini, tipe yang sudah kita lihat adalah  integer  ( int didalam Java) dan   (  string 

didalam Java.

Keyword: Suatu kata digunakan oleh compiler untuk menguraikan (kalimat) program. 

anda tidak bisa menggunakan kata kunci sepert public, class dan void sebagai nama 

variabel.

44
Statement:   Satu   baris   kode   yang   mempresentasikan   suatu   perintah   atau   tindakan. 

Sejauh ini, statemen yang sudah kita lihat adalah deklarasi, tugas, dan statemen cetakan.

Deklarasi:   Suatu   statemen   yang   menciptakan   suatu   variabel   baru   dan   menentukan 

tipenya

Assigment: Suatu statemen yang menugaskan suatu nilai kepada suatu variabel.

Expression: Suatu kombinasi variabel, operator dan nilai­nilai yang mempresentasikan 

hasil nilai tunggal. Ungkapan juga mempunyai tipe yang ditentukan oleh operator dan 

operand.

Operator: Suatu lambang khusus yang mempresentasikan suatu perhitungan sederhana 

seperti addition,multiplication atau penggabungan string.

Operands: Salah satu dari nilai­nilai dimana diatasnya suatu operator beroperasi.

Precedence: Kedudukan suatu operator ketika suatu operasi dievaluasi

Concatenate: Untuk menggabungkan ujung­ujung dua operand.

Komposisi: Kemampuan untuk mengkombinasikan statemen dan ekspresi sederhana ke 

dalam statemen campuran dan ekspresi­ekspresi untuk mempresentasikan perhitungan 

kompleks dengan singkat.

45
2.11 Latihan­latihan

Latihan 2.1

a. Ciptakan suatu program baru nama Date.Java. Copy atau ketik sesuatu seperti Hello, 

World" yakinkan anda dapat meng compile dan Run nya.

  b. Ikuti contoh didalam Bagian 2.4, tulis suatu program yang menciptakan variabel 

nama   hari,   tanggal/date,   bulan   dan   tahun.   hari   akan   berisi   hari   minggu   dan 

tanggal/date   akan   berisi   hari   pada   bulan   itu.   Apa   tipe   masing­masing   variabel? 

Berikan nilai untuk variabel yang  mempresentasikan tanggal/date sekarang.

  c.   Cetak   nilai   dari   tiap   variabel   sejajar   dengan   dirinya.   Ini   adalah   suatu   langkah 

intermediate   yang  bermanfaat  untuk  mengecek   yang  segalanya  yang  telah  dikan 

sejauh ini.

d. Modifikasi program itu sedemikian rupa sehingga dapat mencetak tanggal/date itu 

didalam Format standar Amerika:

Wednesday, February 17, 1999.

e. Modifikasi lagi program itu sedemikian rupa sehingga total keluarannya adalah:

American format:

Wednesday, February 17, 1999

46
European format:

Wednesday 17 February, 1999

Inti   dari   latihan   ini   adalah   untuk   menggunakan   penggabungan   string   untuk 

menampilkan   nilai­nilai   dengan   tipe   berbeda   (   int   dan   string),   dan   untuk   praktek 

mengembangkan   program   secara   berangsur­angsur   dengan   menambahkan   beberapa 

statemen pada waktu yang sama.

Latihan 2.2

a. Ciptakan suatu program baru yang dinamakan Time.Java. Mulai sekarang, saya tidak 

akan   mengingatkan   anda   untuk   mulai   dengan   suatu   yang   kecil,   bekerja   dengan 

program, tetapi anda sendiri yang mekannya.

 b. Ikuti contoh didalam Bagian 2.6, untuk menciptakan variabel nama jam, menit dan 

detik/second,   dan   meng   assign   nilainya   dengan   waktu   yang   sekarang.   Gunakan 

format 24 jam, sedemikian rupa sehingga pada 2pm nilai jam adalah 14.

 c. Buat program untuk mengkalkulasi dan mencetak banyaknya detik mulai dari tengah 

malam.

d. Buat program untuk mengkalkulasi dan mencetak banyaknya detik yang tersisa pada 

hari itu.

e. Buat program untuk mengkalkulasi  dan mencetak  persentase dari hari yang telah 

lewat.

47
f.   Ubah   nilai­nilai   jam,   menit   dan   detik   untuk   mencerminkan   waktu   yang   sekarang 

( saya berasumsi bahwa waktu telah berlalu), dan periksa untuk meyakinkan bahwa 

program dapat bekerja dengan tepat dengan nilai­nilai yang berbeda.

Inti dari latihan ini adalah untuk menggunakan sebagian dari operasi perhitungan, dan 

untuk memulai berpikir tentang campuran variabel seperti jam yang dipresentasikan 

dengan banyak nilai. Juga, anda mungkin menemukan permasalahan dalam menghitung 

persentase dengan  ints, yang mana adalah motivasi untuk belajar  floating point  pada 

yang berikutnya.

SYARAT: anda boleh menggunakan variabel tambahan untuk menyimpan nilai­nilai 

yang untuk sementara sepanjang perhitungan itu. Variabel seperti ini, digunakan pada 

komputasi tetapi tidak pernah dicetak yang terkadang disebut dengan intermediate atau 

variabel temporer.

48
BAB III

Method

3.1 Floating­point

Di  dalam bab  yang terakhir  kita mempunyai beberapa permasalahan  dengan  angka­

angka yang bukanlah bilangan bulat. Kita disibukkan dengan masalah untuk mengukur 

persentase   sebagai   pecahan,   tetapi   suatu   solusi   yang   lebih   umum   adalah   untuk 

menggunakan   angka­angka   floating­point,   yang   dapat   mempresentasikan   pecahan 

seperti halnya bilangan bulat. Didalam Java, tipe floating­point disebut double.

Anda dapat menciptakan variabel floating dan memberikan nilai dengan menggunakan 

Sintak yang sama yang]kita gunakan untuk tipe lain . Sebagai contoh:

double pi;

pi = 3.14159;

Ini juga benar untuk mempresentasikankan suatu variabel dan menugaskan suatu nilai 

kepadanya pada waktu yang sama:

int x = 1;

String empty = "";

double pi = 3.14159;

Sebenarnya, sintak ini adalah secara umum. Suatu kombanisi assigment dan deklarasi 

terkadang disebut suatu initialisasi. 

49
Walaupun   angka­angka   floating­point   bermanfaat,   namunn   sering   suatu   source 

membingungkan karena sepertinya ada tumpang­tindih antara bilangan bulat dan angka­

angka floating­point. Sebagai contoh, jika anda mempunyai nilai 1, yang merupakan 

suatu bilangan bulat, bilangan floating­point, atau kedua­duanya?

Pada   dasarnya,   Java   menilai  integer  itu   1   dan  floating­point  1.0,   sungguhpun 

sepertinya adalah jumlahnya sama. Tetapi tipenya berbeda, dan pada dasarnya, anda 

tidaklah diijinkan untuk meng assign  antara tipe. Sebagai contoh, yang berikut adalah 

tidak benar:

int x = 1.1;

Sebab variabel pada sisi kiri adalah suatu int dan nilai pada sisi kanan adalah suatu 

double. maka mudah untuk melupakan aturan ini, kususnya karena ada tempat dimana 

java akan secara otomatis mengkonversi dari satu tipe ke lain. Sebagai contoh:

double y = 1;

seharusnya secara teknis tidak benar, tetapi Java mengijinkan dengan mengubah int itu 

kepada suatu double secara otomatis. Kemudahan ini sangat menyenangkan, tetapi itu 

dapat menyebabkan permasalahan;

sebagai contoh:

double y = 1 / 3;

50
Anda   mungkin   mengharapkan   variabel   y   diberi   nilai     0.333333,   benar,   tetapi 

sesungguhnya  akan  menghasilkan  nilai  0.0. Alasan  adalah  bahwa  ekspresi  pada  sisi 

kanan   nampak   seperti   perbandingan   dua   bilangan   bulat,   maka   Java   mengerjakan 

pembagian bilangan bulat, yang menghasilkan bilangan bulat  0. yang dikonversi Untuk 

floating­point hasilnya 0.0.

Satu   cara   untuk   memecahkan   masalah   ini   (   saat   anda   menggambarkan   apa   artinya) 

adalah untuk ekspresi floating­point dari kanan. 

double y = 1.0 / 3.0;

disini y diset menjadi 0.333333, yang diharapkan.

Semua operasi yang telah kita lihat sejauh ini penambahan, pengurangan, perkalian,dan 

pembagian juga ada pada nilai floating­point, walaupun anda mungkin tertarik untuk 

mengetahui   bahwa   mekanisme   dasarnya   berbeda   sepenuhnya.   Pada   kenyataanya, 

prosesor mempunyai perangkat keras khusus hanya untuk mekan operasi floating­point.

3.2 Mengkonversi double ke int

Seperti saya sebutkan, Java mengkonversi  int  ke  double  secara otomatis jika perlu, 

sebab   tidak   ada   informasi   hilang   dari   konversi   itu.   Pada   sisi   lain,   mengubah   suatu 

double  ke suatu  int  memerlukan   penyelesaian.  Java tidak melaksanakan  operasi ini 

secara otomatis, sebagai programmer, anda  menyadari hilangnya sebagian jumlah dari 

angka itu.

Cara yang paling sederhana untuk mengkonversi suatu floating­point ke suatu bilangan 

51
bulat adalah menggunakan typecast. Dinamakan typecasting karena mengijinkan anda 

untuk mengambil suatu tipe nilai dan mengubahnya kedalam tipe lain (dalam pengertian 

mengubah tidak melempar).

Sayangnya, sintaks  untuk typecasting jelek:  anda menaruh nama  tipe didalam  tanda 

kurung dan menggunakannya sebagai suatu operator. Sebagai contoh,

int x = (int) Math.PI;

Operator int mempunyai efek mengikuti bilangan bulat, maka x menghasilkan nilai 3.

Typecasting  harus   didahulukan   sebelum   operasi   perhitungan,   maka   didalam   contoh 

yang berikut, nilai PI (22:7) menghasilkan pertama dikonversi ke suatu bilangan bulat , 

dan hasilnya adalah 60, bukan 62.

int x = (int) Math.PI * 20.0;

Mengubah ke suatu bilangan bulat selalu dibulatkan kebawah, sekalipun pecahannya 

0.99999999.

Dua properties ini  (precedence dan pembulatan) dapat membuat typecast kurang bagus.

3.3 Method Matematika

Di dalam matematika, anda mungkin sudah melihat fungsi seperti sin dan log, dan anda 

52
sudah mempelajari ekspresi seperti sin(∏/2) dan log(1/x). Pertama, anda mengevaluasi 

ekspresi didalam tanda kurung, yang mana disebut argumentasi fungsi. Sebagai contoh, 

∏/2 kira­kira 1.571, dan 1/x adalah 0.1 ( diasumsikan bahwa x 10).

Kemudian anda dapat mengevaluasi fungsi itu dengan menggunakan tabel  atau dengan 

mekan berbagai perhitungan. Sin 1.571 adalah 1, dan log 0.1 adalah ­1 ( diasumsikan 

bahwa log mengindikasikan bilangan pokok 10).

Proses ini dapat diterapkan berulang­kali untuk mengevaluasi ekspresi yang lebih rumit 

seperti   log(1/   sin(∏/2)).   pertama   kita   mengevaluasi   argumentasi   function,   lalu 

mengevaluasi  fungsi yang paling dalam, dan seterusnya.

Java   menyediakan   satu   set   built­in   fungsi   yang   mengandung   kebanyakan   operasi 

matematikan   yang   anda   tahu.   Fungsi   ini   disebut  methods.   Kebanyakan   method 

matematika beroperasi pada double.

Method   matemmatika   dilibatkan   menggunakan   suatu   sintaksis   yang   serupa   dengan 

perintah print yang kita lihat:

double root = Math.sqrt (17.0);

double angle = 1.5;

double height = Math.sin (angle);

Contoh yang pertama akar 17. Contoh yang kedua sinus 1.5, yang mana adalah nilai 

sudut variabel. Java berasumsi bahwa   nilai­nilai yang anda gunakan dengan sin dan 

53
fungsi trigonometric lain  ( cos, Tan) adalah didalam radian. Untuk mengkonversi dari 

derajat   ke   radian,   anda   dapat   membagi   dengan   360   dan   mengalikan   dengan   2. 

Untungnya, Java menyediakan ∏ sebagai nilai yang built­in:

PI (22:7) adalah dalam huruf besar. Java tidak mengenali Pi (22:7), Pi (22:7), atau pie.

Metoda bermanfaat lain didalam Claas adalah putaran, yang mengelilingi suatu nilai 

floating­point kepada bilangan bulat yang paling dekat dan kembalikan ke suatu int.

double degrees = 90;

double angle = degrees * 2 * Math.PI / 360.0;

int x = Math.round (Math.PI * 20.0);

Dalam hal ini perkalian dikan terlebih dulu, sebelum method dilibatkan. hasilnya adalah 

63 ( yang dibulatkan dari 62.8319).

3.4 Composition

Sama   halnya   dengan   fungsi   matematika,   Method   Java   dapat   composed,   maksudnya 

anda menggunakan satu ekspresi sebagai bagian dari yang lain. Sebagai contoh, anda 

dapat menggunakan ekspresi manapun sebagai suatu argumentasi ke suatu metoda:

double x = Math.cos (angle + Math.PI/2);

Statemen   ini   mengambil  nilai   Math.Pi,   membaginya   dengan   dua   dan  menambahkan 

hasilnya   kepada   nilai   variabel   angle.   Penjumlahan   kemudian   melewatkan   suatu 

54
argumentasi untuk method cos.(ingat PI (22:7) itu adalah nama suatu variabel, bukan 

method , maka tidak ada argumentasi, bukan pula argumentasi yang kosong()).

Anda dapat juga mengambil satu method dan melewatkannya pada argumentasi ke lain:

double x = Math.exp (Math.log (10.0));

Didalam   Java,   log   berfungsi   selalu   menggunakan   dasar   e,   maka   statemen   ini 

mengartikan dasar log e 10 dan kemudian menaikkan e. Hasilnya di assign ke x; saya 

berharap anda mengetahui apa artinya.

3.5 Menambahkan metode baru

Sejauh   ini   kita   hanya   menggunakan   metoda   yang   dibangun   dalam   Java,   tetapi 

memungkinkan untuk menambahkan metoda baru. Sebenarnya kita melihat satu metoda

  definisi:   main.   Method   dinamakan   main   khusus   menandai   di   mana   pelaksanaan 

program dimulai, tetapi sintak untuk yang main adalah sama dengan definisi metoda 

lain:

public static void NAME ( LIST OF PARAMETERS ) {

STATEMENTS

Anda dapat membuat nama apapun yang anda butuhkan untuk metoda anda, kecuali 

nama main atau keyword java lainnya. Daftar yang menginformasikan tipe parameter, 

55
bila ada, anda harus menyediakan untuk penggunaan fungsi yang baru.

 Parameter tunggal untuk main adalah String[] args, yang menunjukkan bahwa siapapun 

menggunakan main harus menyediakan suatu array String ( akan dipelajari pada Bab 

10).   Sepasang   metoda   yang   pertama   yang   akan   kita   tulis   tidak   punya 

parameters,sehingga sintaknya kelihatan seperti ini:

public static void newLine () {

System.out.println ("");

Method ini dinamai newLine, dan tanda kurung yang kosong menunjukkan bahwa ia 

tidak mengambil parameter apapun. Method itu hanya berisi statemen tunggal, yang 

mencetak suatu  string kosong  yang ditandai  oleh"". Pencetakan  suatu string  dengan 

tidak ada huruf didalamnya tidak akan nampak bermanfaat, kecuali ingat bahwa println 

melompati baris yang berikutnya setelah itu mencetak, maka statemen ini mempunyai 

efek melompati baris yang berikutnya.

  Didalam main kita dapat membuat method yang baru ini menggunakan sintak yang 

serupa  dengan memakai perintah Java yang sudah built­in :

public static void main (String[] args) {

System.out.println ("First line.");

newLine ();

System.out.println ("Second line.");

56
Keluaran dari program ini adalah

First line.

Second line.

Perhatikan spasi antara kedua bentuk. Akibatnya bagaimana jika kita ingin menambah 

spasi antara dua baris? Kita bisa memanggil method yang sama berulang­kali:

public static void main (String[] args) {

System.out.println ("First line.");

newLine ();

newLine ();

newLine ();

System.out.println ("Second line.");

Atau kita bisa menulis suatu metoda baru yang dinamakan threeLine yang mencetak 

tiga bentuk baru:

public static void threeLine () {

newLine (); newLine (); newLine ();

public static void main (String[] args) {

System.out.println ("First line.");

threeLine ();

57
System.out.println ("Second line.");

Anda perlu memperhatikan beberapa hal sekitar program ini:

Anda dapat memanggil prosedur yang sama berulang­kali. Sebenarnya, itu umumnya 

berguna bagi mekannya.

Anda   bisa   mempunyai   satu   method   memanggil   metoda   lain.   Dalam   hal   ini,   main 

meminta   threeLine   dan   threeLine   meminta   newLine.   Lagi­lagi   ini   umumnya 

bermanfaat.

Didalam threeLine saya menulis tiga statemen semua pada baris yang sama, yang mana 

secara   yg   sintak   benar   (ingat   bahwa   spasi   dan   baris   baru   pada   umumnya   tidak 

mengubah  arti dari  suatu  program). Di sisi lain, itu  suatu gagasan  yang baik  untuk 

menaruh  statemen   masing­masing   sejajar   dengan   barisnya,   untuk   membuat   program 

anda   mudah   dibaca.   Saya   terkadang   menggunakan   aturan   dalam   buku   ini   untuk 

menghemat ruang.

Sejauh ini, mungkin belum begitu jelas kenapa begitu berharga ini untuk menciptakan 

semua  metoda baru ini . sebenarnya, ada banyak pertimbangan, tetapi contoh ini hanya 

mempertunjukkan dua hal:

  1. Menciptakan suatu method baru memberi anda suatu kesempatan untuk memberi 

suatu   nama   kepada   satu   kelompok   statemen.   Method   dapat   menyederhanakan   suatu 

program dengan menyembunyikan suatu perhitungan kompleks di belakang perintah 

58
tunggal, dan dengan penggunaan kata Bahasa Inggris sebagai pengganti kode. Lebih 

jelasnya , newLine atau System.Out.Println("")?

 2. Menciptakan suatu method baru yang dapat membuat suatu program yang lebih kecil 

dengan menghilangkan kode berulang. Sebagai contoh, bagaimana cara anda mencetak 

sembilan baris baru berurutan? Anda bisa memanggil method threeLine tiga kali.

3.6 Class dan method

Dari   pengelompokkan   kode­kode   dari   bagian   yang   sebelumnya,   maka   keseluruhan 

definisi kelas kelihatan seperti ini:

class NewLine {

public static void newLine () {

System.out.println ("");

public static void threeLine () {

newLine (); newLine (); newLine ();

public static void main (String[] args) {

System.out.println ("First line.");

threeLine ();

System.out.println ("Second line.");

59
Baris yang pertama menunjukkan bahwa ini adalah definisi untuk suatu kelas yang baru 

yang dinamakan Newline. Suatu Class adalah suatu kumpulan dari suatu method yang 

berelasi.   Dalam   hal   ini,   kelas   yang   bernama   Newline   berisi   tiga   metoda,   yang 

dinamakan newLine, threeLine, dan main.

Class lain yang telah kita lihat adalah Math Kelas. Class itu berisi method yang bernama 

sqrt, sin, dan banyak yang lain. Ketika kita memanggil suatu fungsi matematika, kita 

harus   menetapkan   nama   Class   (Math)   dan   nama   fungsinya.   Itulah   mengapa   sintak 

berbeda untuk masing­masing method built­in dan metoda yang kita tulis:

Math.pow (2.0, 10.0);

newLine ();

Statemen yang pertama memanggil method pow didalam Class Math (Yang menaikkan 

kekuatan argumentasi yang pertama ke argumentasi yang kedua ). Statemen yang kedua 

meminta method newLine metoda, Java mengasumsikan (dengan tepat) didalam Class 

Newlines, yang mana sedang kita tulis.

Jika anda mencoba untuk memanggil suatu method dari Class yang salah, compiler akan 

menghasilkan suatu kesalahan. Sebagai contoh, jika anda ketik:

pow (2.0, 10.0);

Compiler kira­kira akan mengatakan, Tidak bisa menemukan suatu method bernama 

pow didalam Class Newline." Jika anda sudah melihat pesan ini, anda mungkin heran 

60
mengapa compiler mencari pow didalam Class yang didefinisikan. Sekarang anda sudah 

tahu.

3.7 Program dengan banyak method

Ketika   anda   memperhatikan   suatu   Class   yang   didefinisikan   yang   berisi   beberapa 

method,   ketika   dicoba   untuk   membacanya   dari   atas   sampai   ke   bawah,   namun 

nampaknya membingungkan, sebab itu bukanlah Order Of Execution dari program.

Eksekusi   selalu   dimulai   pada   awal   dari   statemen   dari  main,   dengan   mengabaikan 

dimana programnya (dalam hal ini saya dengan bebas menaruhnya pada bagian bawah). 

Statemen   dieksekusi   satu   per   satu   secara   berurutan,   sampai   anda   menjangkau   suatu 

method yang dituju. Method seperti suatu belokan didalam alur eksekusi. Setelah itu 

akan berlanjut ke statemen yang berikutnya, anda pertama akan kebaris yang pertama 

dari   metoda   yang   dilibatkan,   mengeksekusi   semua   statemen   disana,   dan   kemudian 

kembali dan mengambil lagi dimana anda berhenti.

Kelihatannya   cukup   sederhana,   namun   anda   harus   ingat   bahwa   satu   method   dapat 

memanggil method yang lain. Seperti itu, selagi masih pada main, kita mungkin harus 

berhenti   dan   melaksanakan   statemen   pada   threeLine.   Tetapi   ketika   kita   sedang 

melaksanakan   threeLine,   kita   mendapatkan   interupsi   tiga   kali   untuk   berhenti   dan 

melaksanakan newLine.

Pada bagian ini, newLine memanggil method println yang sudah built­in, yang berbelok 

ke  hal  lain. Kebetulan, Java sungguh ahli pada mengawasi dimana itu, maka ketika 

println   selesai,   lalu   mengambil   kembali   eksekusi   dimana   newLine   berhenti,   dan 

61
kemudian kembali lagi kepada threeLine, dan kemudian akhirnya kembali lagi kepada 

main sehingga program dapat berakhir.

Sebenarnya, secara teknis program tidak berakhir pada ujung main. Sebagai gantinya, 

eksekusi mengambil dimana program itu berhenti mengeksekusi yang melibatkan main, 

yang   merupakan   Interpreter   Java.   Interpreter   Java   mengasuh   macam   hal   suka 

menghapus window dan cleanup umum, dan kemudian program berakhir.

  Apa   hal   yang   tidak   baik   untuk   dikan   dalam   mempelajari   buku   ini?   Ketika   anda 

membaca   suatu   program,   jangan   membaca   dari   atas   sampai   ke   bawah.   Sebaiknya 

mengikuti alur pelaksanaan.

3.8 Parameter dan argumen

Sebagian dari method built­in yang sudah kita gunakan mempunyai parameter, yang 

bernilai bahwa  anda membiarkan method mekan pekerjaan itu. Sebagai contoh, jika 

anda   ingin   menetukan   30   Method   sinus   suatu   angka,   anda   harus   menandai   apa 

angkanya. lalu, sin mengambil suatu nilai  double sebagai parameter. Untuk mencetak 

suatu string, anda harus menyediakan string, yang mana println mengambil suatu String 

sebagai parameter.

Beberapa method mengambil parameter lebih dari satu, seperti pow, yang mengambil 

dua double, yaitu base dan eksponen. Perhatikan bahwa pada setiap kasus ini kita harus 

menetapkan tidak hanya berapa banyak parameter yang ada, tetapi juga tipe paremater. 

Maka   seharusnya   itu   tidak   mengejutkan   anda   ketika   anda   menulis   suatu   Class 

62
definition, daftar parameter menandai tipe parameter masing­masing. Sebagai contoh:

public static void printTwice (String phil) {

System.out.println (phil);

System.out.println (phil);

Metoda   ini   mengambil   parameter   tunggal   yang   dinamai   phil,   yang   mempunyai   tipe 

String.

Apapun parameternya (dalam posisi ini kita tidak menyatakan  apa parameternya), akan 

dicetak dua kali. Saya memilih nama phil untuk menyatakan pada anda bahwa nama 

yang  anda  beri suatu  parameter terserah anda,  tetapi secara umum    anda sebaiknya 

memilih sesuatu yang lebih ilustratif dibanding phil.

Untuk memanggil method ini, kita harus menyediakan suatu  String. Sebagai contoh, 

kita mungkin mempunyai suatu method main seperti ini:

public static void main (String[] args) {

printTwice ("Don't make me say this twice!");

String  yang anda buat disebut suatu argument, dan kita mengatakan bahwa argument 

diberikan pada method. Dalam hal ini kita   akan menciptakan suatu nilai  string  yang 

berisi   teks  "Don't   make   me   say   this   twice!"  dan   melewatkan   string   sebagai   suatu 

63
argumenti ke printTwice dimana, berlawanan dengan yang diinginkan, dan akan dicetak 

dua kali.

Sebagai   alternatif,   jika   kita   mempunyai   suatu   Variabel   String,   kita   bisa 

menggunakannya sebagai ganti suatu argument:

public static void main (String[] args) {

String argument = "Never say never.";

printTwice (argument);

Perhatikan sesuatu yang sangat penting disini: nama variabel yang kita lewatkan sebagai 

suatu argument ( argument) tidak mekan apa­apa terhadap parameter ( phil).

Saya katakan lagi bahwa :

Nama variabel yang kita lewatkan sebagai suatu argument tidak mekan apapun 

terhadap nama parameter.

Itu bisa sama atau bisa berbeda, tetapi penting untuk menyadari bahwa itu bukanlah hal 

yang sama, kecuali jika mempunyai nilai yang sama ( dalam hal ini string "  ("Don't 

make me say this twice!")

Nilai yang anda nyatakan sebagai suatu argumenti harus mempunyai tipe yang sama 

dengan parameter method yang anda panggil. Aturan ini sangat penting, tetapi hal ini 

64
sering membuat kita bingung pada Java untuk dua pertimbangan:

Ada beberapa metoda yang dapat menerima argumentasi dengan banyak tipe berbeda. 

Sebagai contoh, anda dapat mengirimkan tipe manapun untuk print dan println, dan itu 

akan selalu benar. Hal semacam ini  merupakan suatu exception,though.

Jika anda membuat kesalahan pada aturan, compiler sering menghasilkan suatu hal yang 

kacau   pada   pemberitahu   kesalahan.   sehingga,   Anda   sering   mendapati   bermacam 

kesalahan   argument   pada     method   ini   ,"   itu   mungkin   karena   efek   dari   tidak 

ditemukannya   suatu   metoda   dengan   nama   dan   tipe   itu.   Sekali   anda   menemukan 

pemberitahu   kesalahan   ini     maka   anda   akan   menggambarkan   tahu   bagaimana   cara 

menginterpretasikannya.

3.9 Stack diagram

Parameter   dan   variabel   lain   hanya   ada   di   dalam   methodnya   sendiri.   Di   dalam 

membatasi main, tidak ada hal seperti phil. Jika anda mencoba untuk menggunakan itu, 

compiler akan menganggapnya salah. Dengan cara yang sama, di dalam printTwice 

tidak ada hal seperti argument.

Satu cara untuk mengetahui dimana masing­masing variabel didefinisikan pada suatu 

stack diagram.

Stack Diagram untuk contoh yang sebelumnya kelihatan seperti ini:

65
Untuk masing­masing method ada suatu kotak abu­abu yang dinamakan   frame  yang 

berisi parameter method dan variabel lokal. Nama method nampak diluar frame. Seperti 

biasanya, nilai dari tiap variabel digambark di dalam suatu kotak dengan nama variabel 

di sampingnya.

3.10 Metode Dengan Banyak Parameter

Sintak   untuk   mendeklarasikan   dan   memanggil   method   dengan   berbagai   parameter 

adalah   suatu   sumber   kesalahan   pada   umumnya.   Pertama,   ingat   bahwa   anda   harus 

mendeklarasikan tipe tiap­tiap parameter. Sebagai contoh

public static void printTime (int hour, int minute) {

System.out.print (hour);

System.out.print (":");

System.out.println (minute);

Itu bisa jadi terkecoh untuk menulis int jam, menit, tetapi format ituhanya benar untuk 

mendeklarasikan variabel, bukan untuk parameter.

Sumber   kesalahan   umum   yang   lain   adalah   bahwa   anda   tidak   punya   sesuatu   untuk 

66
mendeklarasikan tipe argument. Yang berikut adalah salah!

int hour = 11;

int minute = 59;

printTime (int hour, int minute); // WRONG!

Dalam   hal   ini,   Java   dapat   mengatakan   bahwa   tipe   dari  hour  dan  minute  dengan 

memperhatikan deklarasinya. Juga tidak legal dan tidak benar memasukkannya ketika 

anda melewatkannya sebagi argument. Sintaksis yang benar adalah printTime (hour, 

minute).

Latihan 3.1 Gambar suatu frame stack yang menunjukkan status program ketika main 

memanggil printTime dengan argumentasi 11 dan 59.

3.11 Method dan hasilnya

Anda mungkin sudah memperhatikan sebagian dari method yang telah kita gunakan, 

seperti method Math, menghasilkan hasil. Method lain, seperti  println  dan  newLine, 

meng   eksekusi   beberapa   action   tetapi   mereka   tidak   mengembalikan   suatu   nilai.   itu 

memunculkan beberapa pertanyaan: 

• Apa yang terjadi jika anda meminta suatu method dan yang anda tidak mekan 

apapun dengan hasil (yaitu.anda tidak meng assign­nya pada suatu variabel atau 

menggunakannya sebagai bagian dari ekspresi yang besar)?

67
• Apa yang terjadi jika anda menggunakan suatu method print sebagai bagian dari 

suatu ekspresi seperti System.Out.Println (" boo!")+ 7?

• Dapatkah   kita   menulis   method   yang   menghasilkan   hasil,   atau   kita   tetap 

menggunakan newLine dan printTwice?

Jawaban   bagi   pertanyaan   ketiganya   adalah   ya,   anda   dapat   menulis   method   yang 

mengembalikan   nilai,"   dan   itu   akan   kita   pelajari   dalam   2   bab.   Saya   akan 

meninggalkannya  untuk   anda   coba   jawab.   Sebenarnya,   kapan   saja   anda   mempunyai 

suatu pertanyaan tentang apa yang legal dan illegal lebih baik jika mencobanya pada 

compiler.

3.12 Daftar kata

floating­point: Suatu jenis variabel ( atau nilai) yang dapat berisi pecahan seperti halnya 

bilangan bulat. Didalam Jawa tipe ini disebut double.

Class: Suatu koleksi yang dinamai method. Sejauh ini, kita sudah menggunakan Class 

Math  dan   Class  System,   dan   kita   sudah   menulis   Classs   dengan   nama  Hello  dan 

Newline.

method:   Penamaan   suatu   urutan   statemen   yang   melaksanakan   beberapa   fungsi 

bermanfaat. Metoda boleh atau boleh tidak mengambil parameter, dan boleh atau boleh 

tidak menghasilkan suatu hasil.

Parameter: Suatu potongan informasi yang anda menyediakan untuk memanggil suatu 

68
metohd. 

Parameter adalah seperti variabel didalamnya nilai­nilai dan mempunyai tipe.

Argument: Suatu nilai yang anda sediakan ketika anda memanggil suatu method. Nilai 

ini harus mempunyai tipe yang sama parameter yang bersangkutan. 

invoke: Menyebabkan suatu method untuk dieksekusi

3.13 Latihan

Latihan 3.2

Latihan ini adalah untuk mempraktekkan membaca kode dan untuk meyakinkan bahwa 

anda memahami alur eksekusi melalui suatu program dengan berbagai method.

a. Apa keluaran program yang berikut? Perhatikan dimana ada spasi dan dimana ada 

baris baru.

SYARAT: mulai dengan menguraikan kata­kata apa ping dan baffle yang kan ketika itu 

dilibatkan.

b. Gambar suatu diagram stack yang menunjukkan status program pertama kali  ping 

dilibatkan.

69
public static void zoop () {

baffle ();

System.out.print ("You wugga ");

baffle ();

public static void main (String[] args) {

System.out.print ("No, I ");

zoop ();

System.out.print ("I ");

baffle ();

public static void baffle () {

System.out.print ("wug");

ping ();

public static void ping () {

System.out.println (".");

Latihan 3.3 

Latihan ini adalah untuk meyakinkan bahwa anda memahami bagaimana cara menulis 

dan memanggil method yang mengambil parameter.

a. Tulis baris yang pertama suatu metoda nama zool yang mengambil tiga parameter: 

suatu int dan dua String.

70
b.   Tulis   satu   baris   kode   yang   memanggil   zool,   ketika   melewatkan   suatu   argument 

dengan nilai 11, nama binatang kesayangan anda yang pertama, dan nama jalan yang 

ada ditempat anda ketika anda dibesarkan.

Latihan 3.4

Tujuan  latihan ini adalah untuk mengambil  kode dari  suatu latihan sebelumnya dan 

mengemasnya   didalam   suatu   method   yang   mengambil  parameter.   Anda   perlu   mulai 

bekerja menemukan solusi dari Latihan 2.1.

a.   Tulis   suatu   method   untukmemanggil   printAmerican   yang   mengambil   day,   date, 

month dan years sebagai parameter dan dicetak didalam Format Amerika.

b. Uji method anda dengan memanggilnya dari  main dan  melewatkan argument yang 

sesuai.

Keluarannya harus terlihat ( kecuali date boleh berbeda):

Wednesday, September 29, 1999

c. Anda sudah mempunyai debug printAmerican, tulis method lain untuk memanggil 

printEuropean yang dicetak didalam Format Eropa.

Latihan 3.5

Banyak perhitungan dapat dinyatakan dengan singkat menggunakan “multadd" operasi, 

71
yang   mengambil   tiga   operand   dan   menghitung   a*b+   c.   Beberapa   prosessor 

menyediakan     implementasi   perangkat   keras   dari   operasi   ini   untuk   angka­angka 

floating­point.

a. Buat suatu program baru dengan nama Multadd.Java.

b.   Tulis  suatu  method  dengan  nama  multadd  yang  mengambil tiga  double  sebagai 

parameter dan cetak multadditionation nya 

c.   Tulis   suatu   method  main  yang   menguji   multadd   dengan   memanggilnya   dengan 

beberapa parameter sederhana, seperti 1.0, 2.0, 3.0, dan kemudian cetak hasilnya, dan 

harus 5.0.

d. Juga didalam main, gunakan multadd untuk menghitung nilai­nilai yang berikut:

e. Tulis suatu method yang bernama yikes yang mengambil double sebagai parameter 

dan gunakan multadd untuk mengkalkulasi dan cetak

SYARAT: Method Math untuk menaikkan nilai e  adalah Math.Exp.

72
Didalam bagian yang terakhir, anda mendapat kesempatan untuk menulis suatu method 

yang memanggil suatu method yang anda tulis.Kapan saja anda mekannya, merupakan 

suatu gagasan baik untuk menguji method yang pertama secara hati­hati sebelum anda 

memulai menulis yang kedua. Selain itu, anda mungkin menemukan cara mekan 

debugging dua method pada waktu yang sama,yang bisa jadi sangat sulit. Salah satu 

tujuan dari latihan ini adalah untuk mempraktekkan pattern­matching: kemampuan 

untuk mengenali suatu masalah spesifik sebagai suatu kategori permasalahan umum.

73
BAB 4

Kondisional dan rekursi

4.1 Operator modulus

Operator Modulus bekerja pada bilangan bulat dan menghasilkan sisa   ketika operan 

yang pertama dibagi oleh yang kedua. Di (dalam) Java, operator modulus adalah suatu 

tanda persen,%. Sintaksis persisnya sama halnya untuk lain operator:

int quotient = 7 / 3;

int remainder = 7 % 3;

Operator  yang pertama,  pembagian   bilangan bulat, menghasilkan  2. Operator  yang 

kedua  menghasilkan 1. Dengan demikian, 7 yang dibagi oleh 3 adalah 2 dengan sisa 1. 

Operator   modulus   ternyata   adalah   anehnya   bermanfaat.   Sebagai   contoh,   anda   dapat 

memeriksa apakah satu bilangan; jumlah adalah dapat dibagi oleh lain: jika x% y adalah 

nol,   kemudian   x   dapat   dibagi   dengan   y.   Juga,   anda   dapat   menggunakan   operator 

modulus untuk mengetahui digit paling kanan dari suatu bilangan. Sebagai contoh, x% 

10 menghasilkan digit x paling kanan (di (dalam) basis 10). Dengan cara yang sama x% 

100 menghasilkan dua digit terakhir.

4.2 Percabangan

Dalam menulis program yang betul betul fungsionalt, kita hampir selalu memerlukan 

kemampuan  untuk   memeriksa  kondisi­kondisi  tertentu   dan  merubah  aliran  program. 

Pernyataan   percabangan   memberi   [kita/kami]   kemampuan   ini.   Format   yang   paling 

74
sederhana adalah if statemen:

if (x > 0) {

System.out.println ("x is positive");

Ungkapan di (dalam) tanda kurung disebut kondisi. Jika benar, kemudian statemen di 

(dalam) tanda­kurung dieksekusi. Jika kondisi tidaklah benar, tidak dilakukan apapun.

Kondisi dapat berisi operator perbandingan apapun, kadang­kadang disebut relational 

operator:

x == y // x equals y

x != y // x is not equal to y

x > y // x is greater than y

x < y // x is less than y

x >= y // x is greater than or equal to y

x <= y // x is less than or equal to y

Walaupun operasi ini mungkin dikenal baik oleh anda, sintaks Java menggunakannya 

sedikit berbeda dari lambang matematika seperti=,  ≠  dan  ≤. Suatu kesalahan umum 

adalah untuk menggunakan = tunggal sebagai ganti suatu ==. Ingat bahwa = adalah 

operator tugas, dan == adalah suatu operator perbandingan. Juga, tidak ada hal seperti 

=< atau =>. 

Dua   sisi   suatu   kondisi   operator   harus   memiliki   tipe   yang   sama.   Anda   hanya   dapat 

membandingkan int ke int dan double dengan double . Sungguh sial, dalam posisi ini 

75
anda tidak bisa bandingkan string sama sekali! Ada suatu [jalan/cara] untuk bandingkan 

string tetapi kita tidak takkan membahasnya pada bab ini.

4.3 Eksekusi Alternatif

Bentuk   kedua   dari  percabangan  adalah   pelaksanaan   alternatif,   di   mana   ada   dua 

kemungkinan, dan kondisi menentukan yang mana yang akan dieksekusi.

Sintaks nya seperti di bawah ini:

if (x%2 == 0) {

System.out.println ("x is even");

} else {

System.out.println ("x is odd");

Jika sisa ketika x dibagi oleh 2 adalah nol, kita mengetahui bahwa x menjadi genap, dan 

kode ini mencetak suatu pesan. Jika kondisi adalah salah, statemen cetakan yang kedua 

akan dieksekusi. Karena kondisi harus salah atau benar, maka salah satu dari alternafif 

akan dieksekusi.

Jika anda berpikir mungkin akan sering mengecek genap atau ganjil,   anda mungkin 

ingin “membungkus" kode atas dalam suatu method, sebagai berikut:

public static void printParity (int x) {

if (x%2 == 0) {

System.out.println ("x is even");

} else {

76
System.out.println ("x is odd");

Sekarang anda mempunyai suatu metoda nama printParity yang akan mencetak suatu 

pesan sesuai untuk bilangan bulat apapun. Di (dalam) metode “main”  anda akan 

memanggil metoda ini sebagai berikut:

printParity (17);

Selalu   ingat   bahwa   ketika   anda   mengeksekusi   suatu   metoda,   anda   tidak   harus 

mendeklarasikan tipe argumen yang anda sediakan. Java dapat mengetahui tipe data 

tersebut secara otomatis. Anda seharusnya penulisan seperti:

int number = 17;

printParity (int number); // WRONG!!!

4.4 Percabangan Berantai

Kadang­kadang anda ingin melihat kemungkinan sejumlah kondisi­kondisi terkait dan 

memilih   salah   satu   dari   beberapa   tindakan.   Satu   cara   untuk   melakukan   ini   adalah 

dengan rangkaian if dan else seperti berikut:

if (x > 0) {

System.out.println ("x is positive");

} else if (x < 0) {

system.out.println ("x is negative");

77
} else {

System.out.println ("x is zero");

Rantai   ini   dapat   sepanjang   yang   anda   inginkan,   walaupun   pada   akhirnya   akan   sulit 

dibaca. Satu cara untuk membuat [mereka/nya] lebih mudah untuk dibaca adalah untuk 

menggunakan standard indentasi [seperti/ketika] dipertunjukkan contoh ini. Jika anda 

meletakkan semua statement dan kurung kurawal dalam satu baris, anda memiliki lebih 

sedikit kemungkinan untuk membuat kesalahan sintaks dan anda dapat menemukan nya 

dengan lebih cepat.

4.5 Percabangan Bersarang

Sebagai   tambahan   terhadap   yang   percabangan   berantai,   anda   dapat   juga   membuat 

percabangan bersarang di dalam yang lain. Kita bisa menulis contoh yang sebelumnya 

dengan:

if (x == 0) {

System.out.println ("x is zero");

} else {

if (x > 0) {

System.out.println ("x is positive");

} else {

System.out.println ("x is negative");

78
Sekarang ada suatu percabangan luar yang berisi dua cabang. Cabang yang pertama 

berisi   suatu   statemen   cetakan   sederhana,   tetapi   cabang   yang   kedua     berisi   yang 

pernyataan bersyarat lain, yang mempunyai dua cabang. Kebetulan, dua   cabang itu 

adalah   kedua­duanya   statemen   cetakan,   walaupun   mereka   mungkin   bisa   juga 

pernyataan bersyarat yang lain.

Perhatikan   lagi   indentasi   membuat   struktur   lebih   enak   dibaca,   tetapi   meskipun 

demikian,   percabangan   bersarang   lebih   susah   dibaca   dengan   cepat.   Secara   umum, 

merupakan suatu ide yang baik untuk menghindari nya ketika anda bisa.

Di   lain   pihak   ,   struktur   tersarang   macam   ini     adalah   umum,   dan   kita   akan   segera 

melihatnya lagi.

4.6 The  return statement

Statemen kembalian   mengijinkan anda untuk mengakhiri pelaksanaan suatu metoda 

sebelum   anda   menjangkau   akhir   pernyataan.   Satu   alasan   untuk   menggunakan   nya 

adalah jika anda mendeteksi suatu kondisi kesalahan:

public static void printLogarithm (double x) {

if (x <= 0.0) {

System.out.println ("Positive numbers only, please.");

return;

double result = Math.log (x);

System.out.println ("The log of x is " + result);

79
Terdapat suatu metoda bernama printLogarithm yang mengambil suatu tipe data double 

bernama   x   sebagai   parameter.   Hal   yang   mula­mula   ia   kerjakan   adalah   memeriksa 

apakah   x   kurang   dari   atau   sama   dengan   nol,   dalam   hal   ini   ia     mencetak   suatu 

pemberitahu kesalahan dan kemudian menggunakan pernyataan return untuk keluar dari 

metode.   Alir   pelaksanaan   dengan   seketika   kembali   ke   pemanggil   dan   sisa   metoda 

tidaklah dieksekusi.

Saya menggunakan suatu nilai floating point pada sisi kanan kondisi sebab ada suatu 

variabel floating point pada sisi kiri.

4.7 Konversi Tipe

Anda mungkin ingin tahu bagaimana anda suatu pernyataan seperti "The log of x is " + 

result, bisa dieksekusi tanpa kesalahan padahal salah satu operan adalah suatu String 

dan lain adalah double. Dalam hal ini Java secara cerdas mengubah double menjadi 

String  sebelum mengerjakan penggabungan String.

Hal macam ini  adalah contoh suatu masalah umum di (dalam) merancang suatu bahasa 

program, bahwa ada suatu konflik antar[a] formalisme, yaitu kebutuhan bahasa formal 

untuk  mempunyai aturan sederhana dengan sedikit eksepsi , dan kenyamanan, yang 

merupakan kebutuhan bahasa program agar mudah digunakan dalam praktek.

Yang lebih sering terjadi adalah kenyamanan lah yang menang, yang biasnaya baik 

untuk para programmer ahli, tetapi tidak baik untuk para programmer pemula. Dalam 

buku   ini   saya   sudah   mencoba   untuk   menyederhanakan   berbagai   hal   dengan 

menekankan aturan  dan penghilangan banyak perkecualian.

80
Meskipun demikian, ada baiknya untuk mengetahui bahwa kapan saja anda mencoba 

menambahkan dua variabel,  jika salah satu dari mereka adalah suatu String, maka Java 

akan mengkonversi yang lain menjadi String dan melakukan penggabungan String. Apa 

pendapat anda jika anda

melakukan suatu operasi antara suatu bilangan bulat dan suatu floating point?

4.8 Recursion

Saya  menyebutkan pada  bab yang terakhir  bahwa diperbolehkan  satu metoda untuk 

memanggil metode yang lain, dan kita sudah melihat beberapa contoh menyangkut itu. 

Saya   lupa   untuk   menyebutkan   bahwa   juga   diperbolehkan   suatu   metoda   untuk 

memanggil   dirinya   sendiri.   Mungkin   tidak   jelas   mengapa   itu   suatu   hal   baik,   tetapi 

ternyata itu adalah salah satu dari  hal yang yang menarik dan ajaib yang suatu program 

dapat lakukan.

Sebagai contoh, lihat di metoda yang berikut:

public static void countdown (int n) {

if (n == 0) {

System.out.println ("Blastoff!");

} else {

System.out.println (n);

countdown (n­1);

81
Nama   metoda   adalah   countdown   dan   mengambil   bilangan   bulat   tunggal   sebagai 

parameter. Jika parameter adalah nol, ia encetak kata “Blasto." jika tidak ia  mencetak 

bilangan bulat tersebut dan memanggil suatu metoda countdown kembali dengan n­1 

sebagai argumen.

Apa yang terjadi jika kita memanggil metoda ini, di (dalam) main:

countdown (3);

Eksekusi countdown dimulai dengan n=3, dan karena n bukanlah nol, ia mencetak nilai 

3, dan kemudian memanggil dirinya sendiri...

Pelaksanaan   countdown   dimulai   dengan   n=2,   dan   karena   n   bukanlah   nol,    

ia mencetak nilai  2, dan kemudian memanggil dirinya sendiri...

 Pelaksanaan countdown dimulai dengan n=1, dan

 karena n bukanlah nol, ia mencetak nilai 1, dan kemudian 

 memanggil [dirinya] sendiri...

 Pelaksanaan countdown dimulai dengan n=0, dan

 karena n adalah nol, ia mencetak kata “Blastoff" 

   kemudian kembali pada metode yang memanggilnya.

Countdown yang mendapat n=1 kembali (return).

Countdown yang mendapat n=2 kembali (return).

Countdown yang mendapat n=3 kembali (return).

Dan kemudian anda adalah ke main. Sehingga total keluaran kelihatan seperti:

82
1

Blastoff!

Sebagai contoh kedua, mari kita lihat lagi di metoda newLine dan threeLine.

public static void newLine () {

System.out.println ("");

public static void threeLine () {

newLine (); newLine (); newLine ();

Walaupun metode di atas dapat bekerja , mereka tidak akan banyak berguna jika saya 

ingin mencetak 2 baris atau 106. Suatu alternatif lebih baik adalah dengan

public static void nLines (int n) {

if (n > 0) {

System.out.println ("");

nLines (n­1);

Program ini sangat serupa; sepanjang n adalah lebih besar dari nol, ia mencetak satu 

newline,   dan   kemudian   memanggil   dirinya   sendiri   untuk   mencetak   n­1   tambahan 

newlines. Sehingga, total jumlah newlines yang dicetak adalah 1+ ( n­1), yang adalah 

sama dengan n.

83
Proses   suatu   pemanggilan   metoda   terhadap   dirinya   sendiri   disebut   recursion,   dan   . 

Metode seperti itu disebut recursive.

4.9 Diagram Stack Untuk Metode Rekursif

Di   (dalam)   bab   yang   sebelumnya   kita   menggunakan   suatu   diagram   stack   untuk 

menampilkan status suatu program selama pemanggilan suatu metoda. Diagram yang 

sama  dapat membuat lebih mudah untuk

 menginterpretasikan suatu metoda rekursif.

Ingat   bahwa   setiap   kali   suatu   metoda   dipanggil   ia   menciptakan  instance  baru   yang 

berisi variabel lokal dan parameter baru. Gambar berikut adalah diagram stack untuk 

countdown, dengan n= 3:

Terdapat  satu   instance  main  dan  empat  instance  countdown,   masing­masing  dengan 

suatu nilai berbeda untuk parameter n. Stack terbawah, countdown dengan

 n=0 adalah kasus dasar. Sehingga ia tidak membuat suatu panggilan rekursif, jadi  tidak 

ada   lagi   instance   countdown.  Main  adalah   kosong   sebab  main  tidak   mempunyai 

84
parameter atau variabel lokal apapun.

Latihan   4.1  Gambar  suatu  diagram   stack  yang  menunjukkan   status  program  setelah 

main memanggil nLines dengan parameter n=4, tepat sebelum instansce nLines terakhir 

dikembalikan.

4.10 Konvensi dan Divine Law

Di dalam bagian terakhir, saya menggunakan ungkapan “by convention“ beberapa kali 

untuk   menandai   (adanya)   keputusan   disain   sewenang­wenang   tanpa   pertimbangan 

penting, tetapi hanya dikatakan berdasarkan konvensi.

Di (dalam) kasus ini,   adalah suatu keuntungan untuk terbiasa dengan konvensi dan 

menggunakannya, sehingga akan membuat program anda lebih mudah untuk dipahami 

oleh orang lain. Dan penting pula untuk membedakan antara ( sedikitnya) tiga macam 

aturan:

Divine   Law:   Ini   adalah   ungkapan   saya   untuk   menandai   aturan   yang   benar   karena 

beberapa   prinsip   logika   atau   matematika,   maka   itu   adalah   benar   juga   untuk   bahasa 

program (atau sistem formal) apapun. Sebagai contoh, tidak ada cara untuk menentukan 

ukuran dan penempatan suatu kotak menggunakan lebih sedikit dari empat potongan 

informasi. Contoh lain adalah bahwa menambahkan bilangan bulat adalah komutatif. 

Hal ini adalah bagian dari definisi penambahan dan sama hal nya dengan Java.

Rules Of Java: Ini adalah peraturan tentang semantik dan yang syntactic Java yang 

tidak bisa anda langgar, sebab program yang dihasilkan tidak akan bisa dikompilasi atau 

dijalankan. Sebagai contoh, fakta bahwa lambang “+” menghadirkan penambahan dan 

85
penggabungan String. 

Gaya Dan Konvensi: Ada banyak aturan yang tidaklah dipaksa oleh compiler, tetapi itu 

adalah   penting   untuk   penulisan   program   yang   benar,   sehingga   dapat   didebug   dan 

dimodifikasi, dan dapat dibaca orang lain. Contoh nya adalah indentasi dan penempatan 

kurung kurawal, dan konvensi untuk menamai variabel, metoda dan kelas.

Selagi saya adalah pada topik, anda sudah mungkin mengerti mulai sekarang bahwa 

nama kelas selalu mulai dengan huruf besar, tetapi variabel dan metoda mulai dengan 

huruf kecil. Jika nama lebih dari satu kata, maka anda biasanya membuat huruf pertama 

setiap kata dengan huruf besar, seperti di newLine dan printParity. 

4.11 Daftar Kata 

modulus: Suatu operator yang bekerja pada bilangan bulat dan menghasilkan sisa   

ketika satu bilangan dibagi oleh lain. Di (dalam) Java hal ini ditandai  dengan 

tanda persen(%).

conditional: Suatu blok statemen yang boleh atau tidak boleh dieksekusi  tergantung 

pada suatu kondisi.

chaining:   Suatu   cara   untuk   menggabungkan   beberapa   pernyataan   bersyarat   dalam  

suatu urutan.

nesting:   Meletakkan   pernyataan   bersyarat   di   dalam   satu   atau   kedua   cabang   dari  

pernyataan bersyarat lain.

coordinate:   Suatu   variabel   atau   nilai   yang   menunjukkan   lokasi   dari   jendela   grafis  

dua dimensi.

pixel: satuan koordinat dalam komputer

86
bounding box: cara umum untuk menentukan koordinat suatu area segi­empat.

typecast  :  operator yang mengkonversi dari satu tipe data   ke tipe data yang lain.  

Di dalam Java dengan tipe data dalam tanda kurungs seperti (int).

interface: Deskripsi tentang parameter yang dibutuhkan oleh suatu metode dan  tipe 

data nya

prototype:   Suatu   cara   untuk   menggambarkan   metode   menggunakan   sintaks   yang  

mirip Java.

recursion:   Proses   yang   memanggil   metoda   yang   sama   dengan   yang   sekarang  

dieksekusi.

infinite recursion: Suatu metoda yang memanggil dirinya sendiri secara berulang tanpa 

pernah berhenti. Hal seperti ini biasanya menghasilkan StackOver FlowException.

fractal:   Semacam   gambaran   yang   adalah   didefinisikan   secara   berulang,   sedemikian 

sehingga   masing­masing   bagian   dari   gambar   adalah   suatu   versi   yang   lebih   kecil 

keseluruhan.

4.12 Latihan

Latihan 4.2 

Jika anda diberi tiga tongkat, anda mungkin bisa atau tidak bisa menyusun nya dalam 

suatu segi tiga. Sebagai contoh, jika salah adalah 12 inci dan yang lain  adalah satu inci 

,jelas   bahwa   anda   tidak   akan   bisa   membuat   ketiganya   menjadi   segitiga.   Berapun 

panjangnya, ada suatu test sederhana untuk melihat apakah mungkin untuk membentuk 

suatu segi tiga:

“Jika terdapat dari ketiga tongkat tersebut yang panjang nya lebih besar dari jumlah dua 

87
yang   lain,  maka   anda   tidak   dapat   membentuknya   menjadi   segitiga,   jika  tidak   maka 

mereka dapat dibentuk sebagai segitiga" 

Tulis suatu metoda bernama isTriangle yang mengambil  tiga bilangan bulat sebagai 

argumen, dan itu mengembalikan true/false,  tergantung apakah anda bisa membentuk 

nya menjadi  segitiga 

Tujuan latihan ini adalah untuk menggunakan pernyataan bersyarat untuk menulis suatu 

metoda yang mengembalikan suatu nilai.

Latihan 4.3 

Latihan ini meninjau aliran eksekusi program dengan berbagai metoda. Baca kode yang 

berikut dan jawab pertanyaan di bawah.

public class Buzz {

public static void baffle (String blimp) {

System.out.println (blimp);

zippo ("ping", ­5);

public static void zippo (String quince, int flag) {

if (flag < 0) {

System.out.println (quince + " zoop");

} else {

System.out.println ("ik");

baffle (quince);

System.out.println ("boo­wa­ha­ha");

88
}

public static void main (String[] args) {

zippo ("rattle", 13);

a.   Tulis   angka   1   di   sebelah  statement  program   yang   akan   pertama   kali   dieksekusi. 

Perhatikan untuk membedakan hal yang merupakan statement dari hal yang bukan.

 b. Tulis nomor 2 disamping statement yang dieksekusi pada kali kedua , dan seterusnya 

sampai akhir program [itu]. Jika suatu statemen dieksekusi lebih dari sekali, itu bisa 

berakhir dengan billangan lebih dari satu disampingnya.

 c. berapa nilai blimp ketika baffle dieksekusi?

 d. Apa yang keluaran program ini?

Latih 4.4 

Sajak pertama nyanyian “ 99 Bottles of Beer” adalah:

99 bottles of beer on the wall, 99 bottles of beer, ya’ take one down, ya’

pass it around, 98 bottles of beer on the wall.

Sajak berikutnya serupa kecuali banyak botol lebih sedikit satu setiap sajak, sampai 

sajak  terakhir:

No bottles of beer on the wall, no bottles of beer, ya’ can’t take one down,

ya’ can’t pass it around, ’cause there are no more bottles of beer on the

wall!

 Dan kemudian nyanyian berakhir.

89
Tulis   suatu   program   yang   mencetak   keseluruhan   lirik   lagu     “   99   Bottles   of   Beer”. 

Program   anda   harus  berisi   metode  rekursif   yang  bukan   merupakan   hal   yang   susah, 

mungkin anda juga ingin menulis metode tambahan untuk memisahkan fungsi fungsi 

utama program.

Ketika   anda     menulis   kode,   anda   akan   mungkin   ingin   mengujinya   dengan   ejumlah 

bilangan kecil seperti “3 Bottles Of Beer."

Tujuan   latihan   ini   adalah   untuk   mengambil   suatu   masalah   dan   memecahkannya   ke 

dalam permasalahan lebih kecil, dan untuk memecahkan permasalahan kecil dengan 

menulis metode sederhana yang dapat didebug dengan mudah.

Latihan 4.5 

Apa yang program yang berikut?

public class Narf {

public static void zoop (String fred, int bob) {

System.out.println (fred);

if (bob == 5) {

ping ("not ");

} else {

System.out.println ("!");

public static void main (String[] args) {

90
int bizz = 5;

int buzz = 2;

zoop ("just for", bizz);

clink (2*buzz);

public static void clink (int fork) {

System.out.print ("It's ");

zoop ("breakfast ", fork) ;

public static void ping (String strangStrung) {

System.out.println ("any " + strangStrung + "more ");

Latihab 4.6 

Teorema Fermat yang menyatakan bahwa tidak ada bilangan bulat a, b, dan c sehingga

kecuali kasus ketika n= 2.
 

Tulis   suatu   metoda   bernama  checkFermat  yang   mengambil   empat   bilangan   bulat 

sebagai parameter a, b, c dan n yang memeriksa untuk melihat apakah teori Fermat 

benar. Jika n adalah lebih besar dari 2 dan

ternyata adalah benar an+ bn= cn, program akan mencetak “Teori,

 Fermat adalah salah!" Jika tidak program akan mencetak “Tidak ia betul."

91
Anda   perlu   berasumsi   bahwa   terdapat   suatu   metoda   bernama   raiseToPow   yang 

mengambil dua bilangan bulat sebagai argumen dan argumen kedua sebagai pangkat 

argumen pertama. Sebagai contoh: 

int x = raiseToPow (2, 3);

akan memasukkan nilai 8 ke dalam x, karena 23=8

92
Bab 5

Fruitful methods

5.1 Nilai Kembalian

Beberapa metode bawaan yang telah kita gunakan, seperti fungsi Math, telah 

menghasilkan hasil. Tujuan dari pemanggilan metode adalah untuk menghasilkan 

sebuah nilai baru, yang biasanya kita masukkan pada sebuah variabel yang merupakan 

bagian dari sebuah ekspresi. Misalnya

double e = Math.exp (1.0);

double height = radius * Math.sin (angle);

Tetapi sejauh ini semua metode yang telah kita tulis adalah metode dengan kembalian 

void; yaitu metode yang tidak mengembalikan nilai. Ketika anda memanggil metode 

void, ia hanya terdiri atas satu baris, tanpa pemberian nilai ke dalam satu variabel. 

nLines (3);

g.drawOval (0, 0, width, height);

Pada bab ini, kita akan menulis metode yang mengembalikan nilai, yang saya sebut 

sebagai “fruitful methods”, untuk nama yang lebih baik. Contoh yang pertama adalah 

area, yang mengambil double sebagai parameter, dan mengembalikan luas lingkaran 

dengan radius yang diberikan:

public static double area (double radius) {

   double area = Math.PI * radius * radius;

   return area;

Hal pertama yang harus anda perhatikan adalah awal dari definisi metode adalah 

93
berbeda. Sebagai ganti public static void, yang menunjukkan metode void, kita 

menggunakan  public static double, yang menunjukkan nilai kembalian dari metode ini 

adalah double. Saya masih belum menjelaskan apa itu public static tapi tenanglah. 

Juga perhatikan bahwa baris terakhir adalah bentuk alternatif dari pernyataan return 

yang juga terdapat nilai yang akan dikembalikan. Pernyataan tersebut berarti, “kembali 

secepatnya dari metode ini dan gunakan nilai berikut sebagai nilai kembalian.” Nilai 

yang disediakan bisa lebih kompleks, jadi kita bisa menulis metode lebih singkat:

public static double area (double radius) {

  return Math.PI * radius * radius;

Di lain pihak, variabel sementara seperti area lebih membuat debugging jadi lebih 

mudah. Pada kedua kasus, tipe nilai kembalian pada pernyataan return harus sesuai 

dengan tipe kembalian metode. Dengan kata lain, ketika anda mendeklarasikan bahwa 

nilai kembalian adalah double, anda membuat janji bahwa metode ini betul betul akan 

menghasilkan double. Jika anda mencoba return dengan tanpa nilai, atau nilai dengan 

nilai yang berbeda, kompiler akan memaksa anda mengubahnya (menampilkan 

kesalahan).

Kadang kadang berguna juga untuk memiliki beberapa statemen return, satu di setiap 

cabang kondisi: 

public static double absoluteValue (double x) {

  if (x < 0) {

    return ­x;

94
  } else {

    return x;

  } 

Karena statemen return ada pada kondisi alternatif, maka hanya satu yang akan 

dieksekusi. Meskipun sah untuk memiliki lebih dari satu statemen return dalam satu 

metode, harus selalu anda ingat bahwa segera setelah dieksekusi, metode akan berhenti 

tanpa mengeksekusi pernyataan yang ada di bawah nya lagi. 

Kode yang ada setelah sebuah pernyataan return, atau dimana pun dimana tidak akan 

pernah dieksekusi, disebut dead code. Beberapa kompiler akan memperingatkan anda 

jika ada bagian kode yang mengalami hal ini. 

Jika anda meletakkan statemen return di dalam percabangan, anda harus menjamin 

bahwa setiap jalan yang mungkin pada program akan mencapai statemen return. 

Misalnya 

public static double absoluteValue (double x) {

  if (x < 0) {

    return ­x;

  } else if (x > 0) {

    return x;

  }                          // WRONG!!

progam di atas tidak sah karena jika x sama dengan  0, maka tidak ada kondisi yang 

benar dan metode akan kembali tanpa mencapai statemen return. Pesan kompiler untuk 

hal seperti ini adalah  “return statement required in absoluteValue,” yang adalah pesan 

95
memusingkan mengingat telah ada dua statemen return. 

5.2 Pengembangan Program

Pada titik ini anda seharusnya telah bisa untuk melihat pada metode Java yang lengkap 

dan melaporkan apa yang mereka kerjakan. Tetapi mungkin belum jelas bagaimana cara 

menulis nya. Saya akan menyarankan satu teknik yang saya sebut “incremental 

development”. 

Sebagai contoh, bayangkan anda ingin mencari jarak antara dua titik, dengan koordinat 

(x1,y1) dan (x2,y2). Dengan rumus berikut 

Langkah pertama adalah memikirkan bagaimana metode distance akan terlihat pada 

Java. Dengan kata lain apa saja input dan apa saja output nya. 

Pada kasus ini, dua titik adalah parameter, dan sudah jamak untuk mewakili nya dengan 

4 double, meskipun kita akan lihat nanti terdapat objek Point pada Java yang dapat kita 

gunakan. Nilai kembalian adalah jarak, yang akan berupa double juga. 

Selanjutnya kita dapat menulis garis besar metode sebagai berikut:

public static double distance

             (double x1, double y1, double x2, double y2) {

  return 0.0;

96
Nilai kembalian return 0.0;  dibutuhkan agar program dapat dikompilasi. Pada tahap 

ini program tidak melakukan apapun yang berguna, tapi akan lebih baik untuk mencoba 

mengkopilasi sehingga kita bisa mengetahui jika terdapat syntaks yang error sebelum 

kita membuatnya menjadi lebih rumit. 

Untuk menguji metode yang baru, kita harus menggunakannya dengan nilai contoh 

pada metode main:

double dist = distance (1.0, 2.0, 4.0, 6.0);

Saya memilih nilai nilai ini sehingga jarak horizontal adalah 3 dan jarak vertikal adalah 

4. maka hasilnya akan menjadi 5. Ketika anda menguji sebuah metode akan berguna 

jika mengetahui jawaban yang benar. 

Ketika kita telah mengecek sintaks pada definisi metode, kita bisa memulai menambah 

baris kode. Setelah setiap tahap perubahan , kita mengkompilasi lagi dan menjalankan 

program. Dengan cara ini, kita mengetahui dengan tepat dimana masalah yang terjadi 

(jika terdapat error)­­ yang pasti pada baris terakhir yang kita tambahkan.

Langkah berikut pada komputasi adalah untuk mencari jarak antara x2­x1 dan y2­y1. 

Saya akan menyimpan nilai nilai itu pada variabel sementara bernama dx dan dy. 

public static double distance

             (double x1, double y1, double x2, double y2) {

  double dx = x2 ­ x1;

  double dy = y2 – y1;

  System.out.println ("dx is " + dx);

  System.out.println ("dy is " + dy);

97
  return 0.0;

Saya menambahkan pernyataan cetak yang membuat saya bisa melihat nilai yang ada 

sebelum diproses (jika anda menggunakan IDE (Integrated Development Environment) 

anda bisa melakukan hal ini tanpa System.out.println dengan fitur debugger, catatan 

penerjemah). Sebagaimana yang telah saya sebutkan, saya telah mengetahui bahwa nilai 

nilai tersebut adalah 3 dan 4.

Ketika metode telah diselesaikan saya akan menghapus statemen cetak tersebut. Kode 

seperti ini disebut scaffolding, karena akan membantu dalam membuat program, tapi 

bukan merupakan bagian produk akhir. Kadang kadang merupakan hal yang baik untuk 

tidak menghapus kode scaffold, tetapi hanya dibuat komentar, hanya jika kira kira anda 

akan membutuhkannya lagi. 

Langkah berikut pada pengembangan adalah memangkatkan dx dan dy. Kita bisa 

menggunakan metode Math.pow, tetapi akan lebih mudah dan cepat jika hany 

mengalikannya dengan dirinya sendiri. 

public static double distance

                 (double x1, double y1, double x2, double y2) {

      double dx = x2 ­ x1;

      double dy = y2 ­ y1;

      double dsquared = dx*dx + dy*dy;

      System.out.println ("dsquared is " + dsquared);

      return 0.0;

   }

98
Lagi, saya akan mengkompilasi dan menjalankan program pada tahap ini dan mengecek 

nilai (yang seharusnya 25).

Langkah terakhir adalah menggunakan Math.sqrt yaitu metode untuk menghitung dan 

mengembalikan hasil. 

public static double distance

             (double x1, double y1, double x2, double y2) {

  double dx = x2 ­ x1;

  double dy = y2 ­ y1;

  double dsquared = dx*dx + dy*dy;

  double result = Math.sqrt (dsquared);

  return result;

lalu pada metode main, kita lalu akan mengecek nilai dari hasil metode di atas. 

Semakin anda berpengalaman dalam pemrograman, anda akan makin mahir dan bisa 

menulis dan mendebug program lebih dari satu baris setiap kali. Namun demikian 

proses pengembangan secara bertahap ini bisa menghemat banyak waktu debugging.

Hal kunci pada proses adalah:

● Mulai dengan program yang bisa bekerja dan buat perubahan bertahap yang 

kecil. Jika terjadi kesalahan, anda akan mengetahui dengan tepat di aman ia 

terjadi.

● Gunakan variabel sementara untuk menyimpan nilai (nilai yang bukan hasil 

akhir) jadi anda bisa mencetak dan mengeceknya. 

99
● Ketika program bekerja, anda mungin ingin menghapus beberapa baris 

scaffolding atau menggabungkan beberapa baris/pernyattan menjadi satu tetapi 

hanya jika itu tidak membuat program sulit untuk dibaca. 

5.3 Komposisi

Seperti yang telah anda ketahui, ketika anda mendefinisikan sebuah metode, anda bisa 

menggunakannya sebagai bagian dari ekspresi, dan anda bisa membangun metode baru 

menggunakan metode yang telah ada. Misalnya, bagaimana jika seseorang memberikan 

anda dua titik, titik pusat dari lingkaran dan sebuah titik dari keliling, dan bertanya 

tentang luas lingkaran.

Jika titik tengah disimpan pada variabel xc dan yc, dan titik keliling adalah xp dan yp. 

Langkah pertama adalah mencari jari jari lingkaran, yang merupakan jarak antara dua 

titik. Untungnya, kita memiliki sebuah metode, distance yang melakukan: 

double radius = distance (xc, yc, xp, yp);

Langkah kedua adalah mencari luas lingkaran dengan jari jari yang ada, dan 

mengembalikannya

double area = area (radius);

return area;

Dengan menggabungkan semua nya ke dalam sebuah metode, maka kita dapatkan: 

public static double fred

             (double xc, double yc, double xp, double yp) {

   double radius = distance (xc, yc, xp, yp);

   double area = area (radius);

   return area;

100
}

Nama metode ini adalah fred, yang mungkin kelihatan ganjil. Saya akan menjelaskan 

pada bagian berikutnya.

Variabel sementara radius dan area berguna untuk pengembangan dan debugging, tetapi 

ketika   program   telah   bekerja   kita   bisa   membuat   nya   lebih   singkat   dengan 

menggabungkan pemanggilan metode. 

public static double fred

(double xc, double yc, double xp, double yp) {

return area (distance (xc, yc, xp, yp));

5.4 Overloading

Pada bagian sebelumnya anda mungkin menyadari bahwa fred dan area melakukan hal 

yang sama, mencari luas lingkaran tetapi dengan dua parameter yang berbeda. Untuk 

area, kita harus menyediakan radius; untuk fred kita harus menyediakan dua titik.

Jika   kedua   metode   melakukan   hal   yang   sama,   merupakan   hal   yang   lazim   untuk 

memberikan nama yang sama. Dengan kata lain, akan lebih baik jika  fred  bernama 

area. 

Memiliki lebih dari satu metode dengan nama yang sama, yang disebut  overloading, 

adalah sah dalam Java. Jadi kita bisa menamai fred dengan:

public static double area(double x1, double y1, double x2, double y2) {

   return area (distance (xc, yc, xp, yp));

101
Ketika anda memanggil metode yang dioverloading, Java mengetahui versi yang mana 

yang   anda   inginkan   dengan   melihat   pada   argumen   yang   anda   sediakan.   Jika   anda 

menulis 

double x = area (3.0);

Java   akan   mencari   metode   yang   bernama   area   yang   menggunakan   satu   parameter 

double   sebagai   argumen,   jadi   ia   akan   menggunakan   versi   yang   pertama.   Yang 

mengartikan argumen sebagai radius. Jika anda menulis:

double x = area (1.0, 2.0, 4.0, 6.0);

Maka Java akan menggunakan versi yang kedua. 

Banyak perintah bawaan Java yang dioverloading, yang berati ada versi yang berbeda 

beda yang menerima jumlah dan tipe parameter yang berbeda. Misalnya, ada versi print 

dan println yang menerima satu parameter dengan tipe apapun. Pada kelas Math, ada 

versi abs yang bekerja pada double dan ada juga yang bekerja untuk int. 

Meskipun overloading adalah metode yang berguna, ia seharusnya dipakai dengan hati 

hati. Anda mungkin menemukan diri anda pusing sendiri jika anda mencoba mendebug 

satu versi metode padahal sebenarnya anda menggunakan versi yang berbeda. 

Sebenarnya. Hal ini mengingatkan saya salah satu aturan dari debugging:  yakinkan 

bahwa   versi   program   yang   anda   perbaiki   adalah   versi   program   yang   sedang 

berjalan!  Kadang­kadang  anda   mungkin  menemukan   diri  anda  membuat   perubahan 

setelah perubahan yang lain pada suatu program, dan melihat hal yang sama setiap kali 

anda   menjalankannya.   Ini   adalah   tanda   peringatan   untuk   satu   alasan   atau   yang   lain 

bahwa   anda   tidak   menjalankan   versi   program   yang   sedang   anda   perbaiki.   Untuk 

102
mengeceknya,   letakkan  print   (tidak   menjadi   masalah   apa   yang   anda   cetak)   dan 

yakinkan bahwa program mencetak pernyataan print tersebut. 

5.5 Ekspresi Boolean

Sebagian besar operasi yang telah kita lihat menghasilkan nilai dengan tipe yang sama 

dengan operan nya. Misalnya + operator mengambil dua int dan menghasilkan sebuah 

int atau dua double yang menghasilkan sebuah double.

Pengecualian yang telah kita lihat adalah operator relasional, yang membandingkan int 

dan float dan mengembalikan apakah true atau false. True dan false adalah nilai khusus 

dalam Java. Keduanya merupakan tipe data boolean. 

Ekspresi boolean dan variabel bekerja seperti hal nya tipe yang lain:

boolean fred;

fred = true;

boolean testResult = false;

Contoh   pertama   adalah   deklarasi   variabel   sederhana;   contoh   kedua   adalah   sebuah 

penugasan,  dan contoh   ketiga adalah  kombinasi dari   deklarasi dan  penugasan,  yang 

kadang kadang disebut inisialisasi. Nilai true dan false adalah kata kunci dalam Java, 

jadi mereka mungkin tampil dengan warna yang berbeda, tergantung pada lingkungan 

pengembangan anda. 

Sebagaimana yang telah saya sebutkan, hasil dari operator kondisional adalah booean, 

jadi anda bisa menyimpan hasil pembandingan pada sebuah variabel:

boolean evenFlag = (n%2 == 0);  // true if n is even

103
boolean positiveFlag = (x > 0); // true if x is positive

dan menggunakannya sebagai bagian dari pernyataan kondisional:

if (evenFlag) {

  System.out.println ("n was even when I checked it");

Variabel   yang   digunakan   pada   cara   ini   sering   disebut   sebagai  flag,   karena   ia 

menunjukkan ada atau tidak adanya suatu kondisi. 

5.6 Operator Logika 

Ada tiga operatot logika pada Java: AND, OR, NOT, yang memiliki simbol &&, ||, 

dan  !.   Sematik  (arti) dari   operator  operator ini   sama  dengan  arti nya  dalam  bahasa 

Inggris. Misalnya x>0 d && x<10 berarti benar hanya jika x lebih besar dari 0 dan lebih 

kecil dari 10.

evenFlag || n%3 ==0  benar jika salah satu dari kedua kondisi benar, jika evenFlag 

bernilai benar atau n habis dibagi 3. 

NOT operatir memiliki efek untuk menegasikan atau menginvers ekspresi boolean, jadi 

!evenFlag bernilai benar jika evenFlag bernilai false, atau jika n bernilai ganjil. 

Operator logika sering menyediakan cara untuk menyederhanakan pernyataan kondisi 

bersarang. Misalnya   bagaimana  anda  menulis kode  di  bawah ini   menggunakan satu 

kondisional.

if (x > 0) {

  if (x < 10) {

    System.out.println ("x is a positive single digit.");

104
  }

5.7 Metode Boolean

Metode dapat mengembalikan nilai boolean seperti hal nya tipe yang lain, yang sering 

menyembunnyikan pengetesan kompleks di dalam metode. Misalnya 

  public static boolean isSingleDigit (int x) {

    if (x >= 0 && x < 10) {

       return true;

    } else {

       return false;

    }

  }

Nama  metode adalah  isSingleDigit.  Cara  yang umum untuk  memberi  nama metode 

boolean seperti pertanyaan ya/tidak (yes/no question). Tipe kembalian adalah boolean 

yang berarti setiap pernyataan kembalian harus menyediakan ekspresi boolean. 

Kode nya sendiri  sama saja, meskipun akan lebih panjang sedikit dari seharusnnya. 

Ingat bahwa ekspresi x>=0 && x<10 memiliki tipe boolean, jadi tidak ada yang salah 

dengan mengembalikannya secara langsung, dan menghindari pernyataan menggunakan 

if. 

public static boolean isSingleDigit (int x) {

  return (x >= 0 && x < 10);

Pada metode main anda bisa memanggil metode dengan cara yang biasa:

105
boolean bigFlag = !isSingleDigit (17);

System.out.println (isSingleDigit (2));

Baris pertama menugaskan nilai true pada bigFlag dengan alasan 17 bukan angka satu 

digit.  Baris kedua mencetak  true  karena 2 adalah bilangan satu digit. Benar bahwa 

println dioverloading untuk juga menangani boolean.

Cara   yang   paling   umum   untuk   menggunakan   metode   boolean   adalah   di   dalam 

pernyataan kondisional

if (isSingleDigit (x)) {

  System.out.println ("x is little");

} else {

  System.out.println ("x is big");

5.8 Lagi tentang Rekursi 

Sekarang kita memiliki metode yang mengembalikan nilai, anda mungkin tertarik untuk 

mengetahui bahwa kita telah memiliki bahasa pemrograman yang lengkap, yang saya 

maksudkan bahwa segala hal yang dapat dihitung dapat diekspresikan dalam bahasa ini. 

Semua program yang telah ditulis dapat ditulis kembali menggunakan fitur fitur bahasa 

yang   telah   kita   gunakan   sejauh   ini   (sebenarnya,   kita   juga   membutuhkan   beberapa 

perintah untuk mengontrol alat seperti keyboard, mouse, dan diks). 

Membuktikan   klaim   ini   bukanlah   pekerjaan   yang   mudah   .   Hal   ini   pertama   kali 

diselesaikan oleh Alan Turing, salah satu  computer scientisct  pertama(beberapa orang 

akan   beargumen   bahwa   ia   adalah   seorang   matematikawan,   tetapi   banyak  computer  

scientist  yang memulai sebagai matematikawan). Hal ini disebur sebagai thesis Turing. 

106
Jika anda belajar tentang teori komputasi anda akan memiliki kesempatan untuk melihat 

pembuktian ini. 

Untuk memberikan anda ide apa yang bisa anda lakukan dengan alat yang telah kita 

pelajari sejauh ini, mari kita melihat pada beberapa metode untuk mengevaluasi definisi 

fungsi   rekursif   matematika.   Definisi   rekursif   sama   dengan   definisi   melingkar,   yaitu 

definisi yang berisi apa yang didefinisikan. 

Jika anda melihat pada definisi faktorial, anda mungkin mendapatkan seperti:

0! = 1

n! = n ∙ (n − 1)!

(Faktorial biasanya disimbolkan dengan !, jangan bingung dengan operaror ! Pada Java 

yang berarti NOT.) definisi ini menyatakan bahwa faktorial 0 adalah 1, dan faktorial 

nilai yang lain, adalah n dikalikan dengan faktorial dari n­1. Jadi 3! adalah 3 kali 2!, 

dimana 2! faktorial adalah 2 kali 1!, yang merupakan 1 kali 0!. Sehingga didapatkan 3! 

sama dengan 3 kali 2 kali 1 kali 1 yang menghasilkan 6. 

Jika   anda   bisa   menulis   definisi   rekursif   dari   sesuatu,   anda   biasanya   dapat   menulis 

program   Java   untuk   menghitungnya.   Langkah   pertama   adalah   untuk   membuktikan 

parameter apa yang akan dimiliki fungsi tersebut, dan apa nilai kembaliannya. Dengan 

sedikit   pemikiran,   anda   bisa   menyimpulkan   bahwa   faktorial   menggunakan   bilangan 

bulat sebagai parameter dan juga mengembalikan bilangan bulat:

public static int factorial (int n) {

Jika argumen sama dengan 0, maka akan mengembalikan 1:

107
public static int factorial (int n) {

  if (n == 0) {

    return 1;

  }

Jika tidak, ini adalah bagian yang menarik, kita harus membuat pemanggilan rekursif 

untuk mencari nilai faktorial n­1, dan kemudian mengalikannya dengan n.

public static int factorial (int n) {

  if (n == 0) {

    return 1;

  } else {

    int recurse = factorial (n­1);

    int result = n * recurse;

    return result;

  }

Jika kita melihat pada aliran eksekusi pada program, maka akan serupa dengan metode 

nLines pada bab sebelumnya, jika kita memanggil faktorial dengan nilai 3:

Karena 3 tidak sama dengan 0, kita mengambil cabang kedua dan menghitung faktorial 

dari n­1....

Karena   2   tidak   sama   dengan   0,   kita   mengambil   cabang   kedua   dan  

menghitung faktorial dari n­1....

Karena 1 tidak sama dengan 0, kita mengambil cabang 

kedua dan menghitung faktorial dari n­1....

108
Karena 0 sama dengan 0, kita mengambil 

cabang pertama dan mengembalikan nilai 1 tanpa 

memanggil metode rekursif.

Nilai kembalian 1 dikalikan dengan n, yaitu 1, dan hasilnya 

dikembalikan

Nilai kembalian 1 dikalikan dengan n, yaitu 2, dan hasilnya 

dikembalikan.

Nilai kembalian 2 dikalikan dengan n, yaitu 3, dan hasilnya adalah 6. dikembalikan 

pada main, yang memanggil faktorial(3).

Berikut ini diagram stack untuk urutan pemanggilan fungsi di atas:

Nilai kembalina dipelihatkan dilewatkan kembali pada stack.

Perhatikan   bahwa   pada  instance  terakhir   dari   faktorial,   variabel   lokal  recurse  dan 

result tidak ada karena ketika n=0 cabang yang menciptakan mereka tidak dieksekusi.

5.9 Leap of faith

Mengikuti   aliran   eksekusi   adalah   salah   satu   cara   untuk   membaca   program,   tetapi 

109
sebagaimana telah anda lihat pada bagian sebelumnya, hal ini akan sulit untuk beberapa 

jenis program. Sebagai alternatif kita bisa menggunakan cara “leap of faith.” Ketika 

anda   melihat   pemanggilan   metode,   sebagai   ganti   mengikuti   aliran   eksekusi,   anda 

mengasumsikan bahwa metode bekerja dengan benar dan mengembalikan nilai yang 

cocok.

Sebenarnya,   anda   telah   mempraktekkan   “leap   of   faith”   ketika   anda   menggunakan 

metode   bawaan.   Ketika   anda   menggunakan   metode   Math.cos   atau   drawOval.   Anda 

tidak perduli dengan implementasi metode ini. Anda hanya berasumsi bahwa metode ini 

bekerja, karena orang yang menulis metode ini adalah programmer yang baik. Ketika 

kita telah yakin bahwa metode ini benar dengan mencoba dan menguji kode—kita bisa 

menggunakan metode ini tanpa melihat kode itu kembali. 

Hal   yang  sama   berlaku   ketika   anda   memanggil  salah   satu   metode  kepunyaan   anda. 

Misalnya pada bagian 5.7 kita menulis metode isSingleDigit yang menghitung apakah 

sebuah bilangan ada diantara 0 dan 9. 

Hal yang sam dengan program rekursif. Ketika anda melihat pada pemanggilan rekursif. 

Sebagai ganti melihat pada aliran program, anda harus berasumsi bahwa pemanggilan 

rekursif bekerja dengan baik (menghasilkan nilai yang benar), dan lalu tanyakan pada 

diri   anda,   “Asumsikan   bahwa   saya   bisa   mencari   faktorial   n­1,   dapatkah   saya 

menghitung faktorial n?” Pada kasus ini, jelas bahwa anda bisa, dengan mengalikannya 

dengan n.

Tentu, merupakan hal yang aneh untuk mengasumsikan metode bekerja dengan benar 

ketika kita belum selesai menuliskannya, tetapi itulah mengapa kita menyebutnya “leap 

110
of faith”

5.10 Satu Contoh Lagi

Pada   contoh   sebelumnya   saya   menggunakan   variabel   sementara   untuk   mengetahui 

langkah,   dan   untuk   membuat   kode   lebih   mudah   untuk     didebug,   tetapi   saya   bisa 

menghemat beberapa baris: 

public static int factorial (int n) {

  if (n == 0) {

    return 1;

  } else {

    return n * factorial (n­1);

  }

Dari   sekarang   saya   akan   menggunakan   versi   yang   lebih   singkat,   tetapi   saya 

merekomendasikan   anda   untuk   menggunakan   versi   yang   lebih   eksplisit   ketika 

mengembangkan   kode.   Ketika   anda   telah   membuat   nya   bekerja,   anda   bisa 

menciutkannya

Setelah   faktorial,   contoh   klasik   tentang   definisi   rekursif   fungsi   matematika   adalah 

fibonacci. Yang memiliki definisi berikut:

f ibonacci(0) = 1

f ibonacci(1) = 1

f ibonacci(n) = f ibonacci(n − 1) + f ibonacci(n − 2);

Diterjemahkan ke Java sehingga menjadi 

public static int fibonacci (int n) {

111
  if (n == 0 || n == 1) {

    return 1;

  } else {

    return fibonacci (n­1) + fibonacci (n­2);

  }

Jika anda mencoba untuk mengikuti aliran eksekusi, bahkan dengan nilai yang kecil, 

kepala anda akan meledak. Tetapi menurut prinsip “leap of faith”, jika kita berasumsi 

bahwa dua pemanggilan rekursif (ya, anda bisa melakukan dua pemanggilan rekursif) 

bekerja   dengan   benar,   maka   dengan   jelas   kita   bisa   mendapatakan   hasil   yang   benar 

dengan menambahkan keduanya. 

5.11 Daftar Kata

return type : Bagian deklarasi metode yang menunjukkan nilai dengan tipe apa  yang 

akan dikembalikan

return value : Nilai yang disediakan sebagai hasil dari pemanggilan metode. 

dead code : Bagian program yang tidak akan pernah dieksekusi, sering terjadi  arena 

diletakkan setelah return

scaffolding  :   kode   yang   digunakan   selama   pengembangan   program   tetapi   bukan  

merupakan bagian dari versi akhir

void  :   tipe   Kembalian   khusu   yang   menunjukkan   metode   void;   yaitu   metode   yang  

tidak mengembalikan nilai. 

overloading  :   Memiliki   lebih   dari   satu   metode   dengan   nama   yang   sama   tetapi  

parameter yang berbeda. Ketika anda memanggil metode yang  dioverloading. 

Java mengetahui versi mana yang digunakan dengan  melihat   pada   argumen   yang 

112
anda sediakan

boolean : Tipe variabel yang hanya bisa berisi dua nilai true dan false

operator kondisional : operator yang membandingkan dua nilai dan  menghasilkan 

nilai boolean yang menunjukkan hubungan antara kedua  operan.

Operator logika : operator yang menggunakan nilai boolean dan menghasilkan  nilai 

boolean. 

Inisialisasi  :   pernyataan   yang   mendeklarsikan   variabel   baru   dan   menugaskan   nilai  

ke dalam nya pada waktu yang sama. 

5.12 Latihan 

latihan 5.1 

Tulis sebuah metode yang bernam isDivisible yang mengambil dua bilangan bulat n dan 

m mengembalikan nilai true jika n habis dibagi m dan false jika tidak.

Latihan 5.2

apakah keluaran dari program berikut? Tujuan dari latihan ini adalah untuk melatih 

anda mengerti tentang operator logika dan aliran eksekusi pada metode.

public static void main (String[] args) {

    boolean flag1 = isHoopy (202);

    boolean flag2 = isFrabjuous (202);

    System.out.println (flag1);

    System.out.println (flag2);

    if (flag1 && flag2) {

        System.out.println ("ping!");

    }

    if (flag1 || flag2) {

113
        System.out.println ("pong!");

    }

public static boolean isHoopy (int x) {

    boolean hoopyFlag;

    if (x%2 == 0) {

        hoopyFlag = true;

    } else {

        hoopyFlag = false;

    }

    return hoopyFlag;

public static boolean isFrabjuous (int x) {

    boolean frabjuousFlag;

    if (x > 0) {

        frabjuousFlag = true;

    } else {

        frabjuousFlag = false;

    }

    return frabjuousFlag;

latihan 5.3 

Jarak antara dua titik (x1,y1) dan (x2,y2) adalah 

114
Tulislah metode bernama distance yang mengambil empat double sebagai parameter 

x1,y1, x2, y2 dan mencetak jarak antara titik.

Anda harus berasumsi terdapat metode yang bernam sumSquares yang menghitung dan 

mengembalikan jumlah dari kuadrat argumen nya sebagai contoh: 

double x = sumSquares(3.0, 4.0);

akan menugaskan 25 ke x. 

Tujuan dari latihan ini adalah menulis metode baru dengan menggunakan metode yang 

sudah ada. Anda harus hanya menulis satu metode : distance. Anda tidak harus menulis 

sumSquares atau main dan anda tidak harus memanggil distance

Latihan 5.4 

Tujuan dari latihan ini adalah untuk mempraktekkan sintaks dari “fruitful methods”

a) Cari   solusi   anda   sendiri   untuk   latihan   3.5   dan   pastikan   anda   masih   bisa 

mengkompilasi dan menjalankannya.

b) Ubahlah multadd menjadi metode yang mengembalikan nilai, jadi sebagai ganti 

mencetak hasilnya, ia akan mengembalikannya.

c) Di mana saja di dalam program multadd dipanggil, ganti pemanggilannya jadi 

ia menyimpan hasilnya dalam variabel dan/atau mencetak hasil

d) Ubah juga yikes dengan cara yang sama.

Latihan 5.5 

Tujuan   dari   latihan   ini   adalah   untuk   menggunakan   diagram   stack   untuk   mengerti 

tentang pengeksekusian dari program rekursif. 

public class Prod {

115
    public static void main (String[] args) {

        System.out.println (prod (1, 4));

    }

    public static int prod (int m, int n) {

        if (m == n) {

            return n;

        } else {

            int recurse = prod (m, n­1);

            int result = n * recurse;

            return result;

        }

    }

a. gambar diagram stack yang menunjukkan keadaan program sesaat sebelum instance 

terakhir prod selesai. Apakah keluaran dari program?

b. Jelaskan dengan beberapa kata apa yang sebenaranya dilakukan prod.

c. tulis kembali prod tanpa menggunakan variabel sementara recurse dan result.

Latihan 5.6 

Tujuan latihan ini adalah untuk menerjemahkan definisi rekursif ke dalam metode Java. 

Fungsi Ackerman didefinisikan untuk bilangan bulat non negatif  sebagai berikut:

116
Tulis metode bernama ack yang mengambil dua int sebagai parameter, menghitung dan 

mengembalikan nilai dari fungsi Ackerman. 

Uji implementasi anda dengan memanggilnya dari metode  main  dan mencetak nilai 

kembaliannya. 

Peringatan: nilai keluaran akan bertambah besar dengan cepat. Anda harus mencobanya 

untuk  nilai m dan n (tidak lebih dari 2). 

Latihan 5.7 

a. Buat program bernama Recurse.java dan tulis metode metode berikut: 

// first: kembalikan karakter pertama dari String yang diberikan

public static char first (String s) {

    return s.charAt (0);

// last: kembalikan String baru yang berisi semua kecuali huruf pertama dari

// String yang diberikan

public static String rest (String s) {

    return s.substring (1, s.length());

// length: kembalikan panjang dari string yang diberikan

public static int length (String s) {

    return s.length();

b. Tulis beberap kode pada main yang mengetes setiap metode metode ini. Anda harus 

117
yakin bahwa mereka bisa bekerja dengan baik dan anda bisa mengerti apa yang mereka 

kerjakan.

c. Tulis metode yang bernama  printString  yang mengambil String sebagai parameter 

dan mencetak huruf huruf dari String tersebut satu setiap baris. Metode ini harus lah 

merupakan metode void. 

d. Tulis metode yang bernama  reverseString  yang mengambil sebuah String sebagai 

parameter dan mengembalikan String baru. String yang baru harus berisi huruf huruf 

yang sama dengan parameter nya tetapi dengan urutan yang terbalik. Misalnya keluaran 

kode di bawah 

String backwards = reverseString ("Allen Downey");

System.out.println (backwards);

adalah 

yenwoD nellA

Latihan 5.8 

a. Buat program bernama Sum.java tulis dua metode di bawah

public static int methOne (int m, int n) {

  if (m == n) {

    return n;

  } else {

    return m + methOne (m+1, n);

  }

public static int methTwo (int m, int n) {

  if (m == n) {

118
    return n;

  } else {

    return n * methTwo (m, n­1);

  }

b. Tulis beberapa baris pada main untuj menguji metode metode ini. Panggil mereka 

beberapa kali dengan nilai yang berbedam dan lihat apa yang anda dapatkan. Dengan 

beberapa kombinasi dari pengetesan, cari tahu apa yang dilakukan metode ini dan beri 

mereka nama yang sesuai. Tambahkan komentar yang menjelaskan fungsi nya

c.   Tambahkan   pernyataan  println  pada   awal   metode   sehingga   mereka   mencetak 

argumen setiap kali dipanggil. Teknik ini berguna untuk mendebug program rekursif, 

karena ia mendemontrasikan aliran eksekusi. 

Latihan 5.9 

Tulis metode rekursif bernama power yang mengambil double x dan sebuah integer n 

dan   mengembalikan  xn..  Petunjuk:  definisi  rekursif   dari   power(x,n)=x*power(x,n­10, 

juga ingat bahwa apapun yang dipengkatkan 0 adalah 1.

Latihan 5.10 

(latihan ini berdasarkan pada halaman 44 buku Structure and Intepetation of Computer  

Programs karangan Abelson dan Sussman)

Algoritma   berikut   dikenal   sebagai   algoritma   Euclid.   Algoirtma   ini   berdasarkan   dari 

observasi   bahwa,  jika   r   adalah  sisa   ketika  a   dibagi  dengan   b   maka   faktor   pembagi 

terbesar(fpb) dari a dan b sama dengan faktor pembesar dari b dan r. sehingga bisa 

dinyatakan dengan persamaan

gcd(a,b)=gcd(b.r)

119
Yang   sukses   untuk   mengurangi   masalah   penghitungan   GCD   (   Greatest   Common 

Divisor) contoh penerapan algoritma, 

gcd(36, 20) = gcd(20, 16) = gcd(16, 4) = gcd(4, 0) = 4

Yang menghasilkan GCD dari 36 dan 20 adalah 4. Dapat diperlihatkan bahwa untuk 

berapapun angka awal, pengurangan berulang menghasilkan pasangan dimana bilangan 

yang kedua adalah 0. dan GCD adalah nomor yang lain pada pasangan itu. 

Tulis sebuah metode bernama gcd yang mengambil dua parameter bilangan bulat dan 

menggunakan   algoritma   Euclid   untuk   menghitung   dan   mengembalikan   greatest 

common divisor (gcd)/Faktor Persekutuan Terbesar (FPB) dari kedua bilangan. 

120
Bab 6

Iterasi

6.1 Multiple Assignment

Saya   belum  pernah   mengatakan   hal   ini   sebelumnya,   tapi   adalah   sesuatu   yang   legal 

dalam   Java   untuk   membuat   lebih   dari   satu  assignment  terhadap   satu   variabel   yang 

sama.   Akibat   yang   akan   timbul   dengan   adanya  assignment  berganda   ini   adalah 

terjadinya penggantian nilai lama dari suatu variabel dengan nilai yang baru.

Perhatikan contoh berikut ini:
int fred = 5;
System.out.print(fred);
fred = 7;
System.out.println(fred);

Output   dari   program   ini   adalah   57.  Kok   bisa?  Ini   terjadi  karena   pada   kesempatan 

pertama   kita   mencetak   nilai   5   menggunakan   metode  print  sedangkan   pada 

kesempatan berikutnya kita mencetak nilai 7 menggunakan metode println .

Karena sifat  multiple  assigment  inilah saya mendeksripsikan bahwa variabel­variabel 

dalam Java merupakan penampung (container) untuk  nilai­nilai. Ketika Anda memberi 

(assign)  sebuah nilai untuk suatu variabel, Anda berarti mengubah isi dari  container  

tersebut, perhatikan gambar di bawah ini:
int fred = 5; fred  5

fred = 7; fred  5  7

Ketika   terjadi  multiple  assignment  terhadap   suatu   variabel,   adalah   penting   untuk 

121
membedakan antara sebuah pernyataan assignment dengan sebuah pernyataan equality  

(kesamaan).   Karena   Java   menggunakan   simbol   “  =  ”   sebagai   simbol  assignment, 

terkadang kita sering tergoda untuk menganggap pernyataan seperti  a   =   b  sebagai 

pernyataan equality. Padahal bukan!

Untuk   memperjelas   masalah   ini,   simaklah   beberapa   sifat   berikut:  equality  bersifat 

komutatif, sementara assignment tidak. Sebagai contoh, dalam lingkungan matematika; 

jika  a   =   7  maka  7   =   a. Namun tidak dalam lingkungan Java! Jika  a   =   7;  

merupakan   pernyataan   yang   legal   maka   pernyataan   sebaliknya,   yaitu  7   =   a;  

tidaklah demikian. 

Lebih   jauh   lagi,   dalam   matematika,   sebuah   pernyataan   yang   bersifat  equality  akan 

selalu benar untuk selamanya. Sebagai contoh, jika a   =   b sekarang, maka  a  akan 

selalu   sama   dengan  b.   Dalam   Java,   sebuah   pernyataan  assignment  memang   dapat 

membuat dua variabel bernilai sama, tapi keadaannya tidak akan sama dengan apa yang 

telah terjadi dalam dunia matematika.

int a = 5;
int b = a;  // a dan b sekarang sama
a = 3;   // a dan b sekarang tidak lagi sama
Baris   terakhir   kode   di   atas   memang   mengubah   nilai   variabel  a,   tapi   tidak   dengan 

variabel  b. Nilai  b  masih tetap sama dengan nilai variabel  a  yang pertama, yaitu  5. 

Dalam   lingkungan   bahasa   pemrograman   lain,   sebuah   simbol   alternatif   lain   sering 

digunakan sebagai simbol pernyataan assignment. Misalnya: “ <­  ”  atau     " :=  ". 

Hal ini dilakukan sebagai langkah antisipasi untuk mencegah kerancuan.    

Meskipun  multiple  assignment  seringkali   berguna,   Anda   harus   tetap  hati­hati   dalam 

menggunakannya. Jika nilai dari suatu variabel selalu berubah­ubah pada lokasi/bagian 

yang   berbeda­beda   di   dalam   program,   maka   Anda   akan   menemui     kesulitan   ketika 

hendak men­debug dan membaca kodenya.

122
6.2 Iterasi 

Salah   satu   fungsi   komputer   yang   paling   sering   dimanfaatkan   manusia   adalah   untuk 

melakukan sesuatu (baca: tugas) yang sifatnya berulang­ulang. Mengulang­ulang tugas 

yang sama atau identik tanpa melakukan satu kesalahan pun adalah sesuatu yang dapat 

dikerjakan dengan sangat baik oleh komputer, tapi tidak oleh manusia.

Kita   telah   melihat   program­program   yang   menggunakan   teknik   rekursi   untuk 

melakukan   perulangan,   seperti  nLines  dan  countdown .   Bentuk   perulangan 

seperti inilah yang disebut dengan iterasi, dan Java menyediakan beberapa fitur bahasa 

yang dapat memudahkan kita untuk membuat program­program yang iteratif.  

Dua fitur yang akan kita lihat pertama adalah pernyataan while dan pernyataan for .

6.3 Pernyataan While 

Dengan  pernyataan  while , kita dapat  menulis ulang  countdown  dengan cara 

sebagai berikut:
public static void countdown (int n)
{
while (n > 0)
{
System.out.println (n);
n = n ­ 1;
}
System.out.println ("Blastoff!");
}

Anda dapat menulis pernyataan  while  ini laiknya menulis kalimat dalam Bahasa 

Inggris. Maksudnya, kode di atas dapat dibaca dengan kalimat seperti ini, "While n is 

123
greater than zero, continue printing the value of n and then reducing the value of n by 1. 

When   you   get   to   zero,   print   the   word   Blastoff!".   Dalam   Bahasa   Indonesia   berarti 

kalimatnya akan menjadi seperti ini, "Selama n masih lebih besar daripada 0, teruslah 

mencetak nilai n, kemudian kurangi nilai n dengan 1.  Ketika Anda sudah sampai pada 

nilai 0, cetaklah kata Blastoff!".

Untuk lebih jelasnya, berikut ini merupakan alur eksekusi yang terjadi dalam kode di 

atas:

1. Cek/Evaluasi   syarat   (condition)   yang   berada   dalam   tanda   kurung,   apakah 

bernilai true  atau false .

2. Jika syarat itu bernilai  false , Java akan keluar (exit) dari pernyataan while 

tersebut lalu melanjutkan eksekusi ke pernyataan selanjutnya.

3. Jika syarat tersebut bernilai  true , Java akan mengeksekusi setiap pernyataan 

yang berada dalam kurung kurawal, lalu kembali ke langkah nomor 1.

Bentuk   aliran   program   seperti   inilah   yang   disebut  loop  (baca:   putaran   atau   siklus). 

Disebut demikian karena pernyataan pada langkah yang ketiga akan membuat program 

kembali   lagi   ke   bagian   atas   dari   program   itu   sendiri.   Perhatikan   bahwa   jika   syarat 

langsung bernilai false  pada saat masuk ke dalam loop, pernyataan yang berada di 

dalam   loop   tersebut   tidak   akan   dieksekusi.   Pernyataan   yang   berada   di   dalam   loop 

biasanya disebut body (badan) dari loop.

Badan   loop   harus   merubah   nilai   dari   satu   atau   lebih   variabel   sehingga   syarat   yang 

dievaluasi akan sampai pada nilai false  dan loop pun akan berakhir. Jika tidak, loop 

tersebut   akan   melakukan   putaran   eksekusi   selamanya.   Keadaan   inilah   yang   disebut 

dengan infinite loop (baca: putaran tanpa batas). Contoh infinite loop dalam kehidupan 

sehari­hari yang mungkin sering kita ditemui adalah instruksi dalam kemasan shampoo, 

"Cuci rambut Anda, bilas dengan air, lalu ulangi."

124
Dalam kasus countdown , kita dapat membuktikan bahwa loop pasti akan dihentikan 

karena kita tahu bahwa nilai dari variabel n  adalah nilai yang terbatas (finite). Di situ 

kita dapat melihat bahwa nilai n  akan semakin mengecil setiap kali melewati loop (tiap 

iterasi). Keadaan ini tentu akan membawa kita kepada nilai  n  yang sama dengan 0. 

Namun   dalam   kasus­kasus   loop   lainnya,   terkadang   tidaklah   mudah   untuk 

mengatakannya. Perhatikan contoh berikut ini:
public static void sequence (int n) {
while (n != 1) {
System.out.println (n);
if (n%2 == 0) {  // n is even
n = n / 2;
} else {  // n is odd
n = n*3 + 1;
}
}
}

Syarat loop di atas adalah n  !=  1, jadi loop akan terus diproses sampai nilai variabel 

n = 1 . Kondisi ini akan menyebabkan syarat bernilai false .

Dalam   tiap   iterasinya,   program   akan   mencetak   nilai   dari  n  sekaligus   memeriksa 

apakah nilai n  tersebut termasuk genap atau ganjil. Jika n termasuk genap, maka nilai 

n  akan dibagi dengan 2. Tapi jika termasuk ganjil, maka nilai n  akan diganti dengan 

nilai dari n*3   +   1. Sebagai contoh, jika nilai awal (argumen yang dilewatkan dalam 

metode sequence ) sama dengan 3, maka hasil yang akan dicetak adalah 3,   10,  


5, 16, 8, 4, 2.
Karena   nilai   n   kadang   bertambah   dan   kadang   menurun,   tidak   ada   bukti   yang   kuat 

bahwa n akan sama dengan 1, atau dengan kata lain agar proses dalam program dapat 

125
dihentikan.   Untuk   beberapa   nilai   n,   kita   dapat   membuktikan   bahwa   terminasi 

(penghentian)  terhadap  program akan  terjadi.  Sebagai   contoh,  jika nilai      awal  dari 

metode tersebut adalah bilangan yang termasuk kelipatan 2, maka nilai n  akan selalu 

genap setiap kali melintasi loop, sampai kita sampai ke nilai  n   =   1. Dalam contoh 

sebelumnya kita dapat melihat manakala nilai n  telah sama dengan 16  maka nilai n 

berikutnya pasti akan membawa variabel  n  ke  1  (16,   8,   4,   2,   1). catatan: 

angka 1  tidak dicetak dalam output.

Nilai­nilai lain (selain kelipatan 2) tentunya tidak dapat dimasukkan ke dalam bentuk 

umum   seperti   di   atas.   Pertanyaan   menariknya   adalah;   dapatkah   kita   membuktikan 

bahwa program di atas pasti akan dapat dihentikan (terminate) untuk semua nilai  n? 

Sampai sejauh ini, belum ada yang dapat membuktikan kebenaran pertanyaan di atas!

6.4 Tabel

Salah   satu   manfaat   loop   yang   paling   baik   adalah   untuk   membuat   (generate)   dan 

mencetak tabel data. Sebagai contoh, sebelum komputer dapat digunakan sebaik seperti 

sekarang, orang­orang harus menghitung logaritma, sinus, cosinus, serta fungsi­fungsi 

matematika lainnya menggunakan tangan (baca: manual).

Untuk membuat pekerjaan­pekerjaan di atas menjadi lebih mudah, dibuatlah beberapa 

buku yang berisi tabel­tabel panjang yang dapat membantu kita untuk melihat nilai­nilai 

dari beberapa fungsi. Untuk membuat tabel­tabel ini dibutuhkan waktu yang lama. Dan 

membosankan!  Akibatnya,   hasilnya   pun   terkadang   akan   dipenuhi   banyak  error 

(kesalahan). 

Ketika komputer telah muncul beserta monitornya, salah satu reaksi awal yang muncul 

adalah,   "Hebat!   Kita   dapat   menggunakan   komputer   untuk   membuat   tabel­   tabel, 

sehingga tidak akan ada kesalahan lagi". Euforia ini secara umum memang akhirnya 

terbukti, tapi ini hanyalah secuil kemampuan saja dari begitu banyak hal yang dapat 

126
dilakukan   dengan   komputer.   Setelah   komputer   (juga   kalkulator   digital)   digunakan 

secara luas oleh banyak kalangan, tabel­tabel tersebut menjadi barang kuno. 

Setidaknya bisa dikatakan hampir demikian. Karena untuk beberapa operasi, komputer 

juga  masih menggunakan tabel­tabel untuk melihat  jawaban yang paling mendekati, 

untuk kemudian kembali lagi menggunakan komputer ketika hendak memperbaiki nilai 

pendekatan tersebut. Dalam beberapa kasus, pernah terjadi kesalahan fatal dalam tabel­

tabel   yang   dibuat   menggunakan   komputer.   Kasus   populer   menyangkut   ini   adalah 

kesalahan prosessor Intel Pentium generasi awal dalam melakukan operasi pembagian 

(division) untuk nilai floating­point.

Meskipun sebuah "tabel logaritma" tidaklah terlalu penting lagi seperti beberapa tahun 

yang lalu, tapi kita masih dapat  menggunakannya sebagai contoh yang bagus  untuk 

menunjukkan bagaimana cara iterasi bekerja. Program berikut ini akan mencetak urutan 

nilai­nilai di kolom bagian kiri dan logaritmanya di kolom bagian kanan:
double x = 1.0;
while (x < 10.0) {
System.out.println (x + " " + Math.log(x));
      x = x + 1.0;
}

Output dari program ini tampak sebagai berikut:
1.0  0.0
2.0  0.6931471805599453
3.0  1.0986122886681098
4.0  1.3862943611198906
5.0  1.6094379124341003
6.0  1.791759469228055
7.0  1.9459101490553132

127
8.0  2.0794415416798357
9.0  2.1972245773362196

Dengan melihat nilai­nilai di atas, bisakah Anda memberi tahu default nilai basis dari 

fungsi log yang digunakan oleh Java?

Karena nilai kelipatan 2 memiliki peran yang penting dalam ilmu komputer, terkadang 

kita ingin menemukan logaritma dengan nilai basis 2. Untuk menemukannya, kita bisa 

menggunakan formula berikut ini:
log 2 x = log e x/log e 2
Ubahlah pernyataan print  dalam kode di atas sehingga menjadi seperti berikut ini:
   System.out .print ln(x  + " "  +  
Math.log(x)/M ath.lo g(2.0) );  

pernyataan di atas akan menghasilkan:
1.0  0.0
2.0  1.0
3.0  1.5849625007211563
4.0  2.0
5.0  2.321928094887362
6.0  2.584962500721156
7.0  2.807354922057604
8.0  3.0
9.0  3.1699250014423126

Dari hasil di atas kita dapat melihat bahwa 1, 2, 4, dan 8 merupakan bilangan kelipatan 

2. Ini karena logaritma mereka yang berbasis 2 menghasilkan bilangan dengan nilai 

pembulatan   (rounded).   Jika   kita   ingin   menemukan   logaritma   dari   bilangan­bilangan 

lainnya selain 2, kita dapat memodifikasi program tersebut dengan cara seperti di bawah 

128
ini;
double  x =  1.0;
 while  (x <  100.0)  {
 System.out.p rintln  (x  + " "  + Math.log(x)  /  
Math.log(2.0) );
 x =  x * 2.0;
}

Ketimbang selalu menambahkan sesuatu ke variabel x  setiap kali melewati loop yang 

akan menghasilkan deret aritmatika, sekarang kita akan mengalikan variabel x dengan 

sesuatu sehingga menghasilkan deret geometri. Berikut ini  merupakan hasil dari kode 

di atas:
1.0   0.0
2.0   1.0
4.0   2.0
8.0   3.0
16.0  4.0
32.0  5.0
64.0  6.0

Tabel logaritma mungkin sudah tidak terlalu berguna untuk saat ini, tapi untuk seorang 

ilmuwan komputer (computer scientist), mengetahui bilangan kelipatan 2 atau pangkat 2 

adalah   wajib!   Jika   kamu   sedang   dalam   keadaan  idle  (baca:   malas   atau  bete), 

berusahalah   utuk   mengingat   bahwa   bilangan   berpangkat   atau   kelipatan   2   dalam 

komputer hanya akan sampai pada angka 65536 (ini adalah hasil dari 216).

6.5 Tabel Dua Dimensi

Sebuah tabel berdimensi dua adalah sebuah tabel yang di dalamnya terdapat nilai­nilai 

129
yang berada dalam perpotongan (interseksi) antara satu baris dan satu kolom.  Contoh 

yang   baik   untuk   memperlihatkan   tabel   ini   adalah   tabel   perkalian   (multiplication). 

Anggap saja Anda ingin mencetak tabel perkalian untuk nilai 1 sampai dengan 6. 

Cara yang bagus untuk memulaiya adalah dengan menulis sebuah loop sederhana yang 

mencetak kelipatan 2, semua dalam 1 baris.
int i = 1;
    while (i <= 6) {
    System.out.print (2*i + " ");
    i = i + 1;
}
System.out.println ("");

Baris  pertama menginisialisasi  sebuah variabel, yakni  i. Variabel ini akan bertugas 

sebagai counter, atau variabel untuk melakukan loop. Ketika loop dieksekusi, nilai dari 

i akan terus naik mulai dari 1 hingga 6. Ketika i sama dengan 7, loop akan dihentikan. 

Setiap   melewati  loop,   kita  mencetak  nilai   dari  2   *   i  diikuti  dengan   tiga  spasi. 

Karena   kita   menggunakan   perintah  print  ketimbang  println ,   semua   output 

akan dicetak dalam satu baris yang sama.

Seperti   yang   sudah   saya   singgung   dalam   bagian   2.4,   dalam   beberapa   lingkungan 

pemrograman,   output   dari   perintah  print  akan   terus   disimpan   dalam   memori 

sampai perintah  println  dipanggil. Jika program sudah berhenti, tapi Anda lupa 

memanggil perintah  println , Anda mungkin tidak akan pernah melihat nilai yang 

disimpan tersebut.

Output dari program di ini adalah:
2   4   6   8   10   12

So   far,   so   good.   Tahap   berikutnya   adalah   membuat   suatu   bentuk   enkapsulasi   dan 

130
generalisasi.

6.6 Enkapsulasi dan Generalisasi

Enkapsulasi (encapsulation) berarti mengambil beberapa bagian dari kode yang sudah 

ditulis   untuk   kemudian   mengemasnya   (wrap­it­up)   dalam   sebuah   metode.   Kita 

sebelumnya sudah melihat dua contoh enkapsulasi. Pertama, ketika kita menulis metode 

printParity  dalam bagian 4.3 dan isSingleDigit  dalam bagian 5.7.

Generalisasi berarti mengambil satu hal yang spesifik dari suatu bagian kode dalam 

metode, misalnya mencetak kelipatan 2, untuk kemudian membuatnya menjadi lebih 

umum.   Dalam   kasus   ini   berarti   dengan   cara   membuat   kode   tersebut   agar   dapat 

mencetak nilai kelipatan dari n.
public static void printMultiples (int n) {
int i = 1;
     while (i <= 6) {
     System.out.print (n*i + " ");
     i = i + 1;
     }
   System.out.println ("");
}

Untuk mengenkapsulasi, yang saya lakukan hanyalah menambah sesuatu dalam baris 

pertama.   Dalam   hal   ini   saya   menambahkan   nama   metode,   parameter,   dan   tipe 

pengembalian.   Sedangkan   untuk   menggeneralisasi,   yang   saya   lakukan   adalah 

mengganti nilai 2 dengan parameter n.

Jika saya memanggil metode ini dengan argumen 2 maka saya akan mendapatkan hasil 

yang sama dengan program sebelumnya. Dengan argumen 3, hasil yang akan  kita lihat 

131
adalah sebagai berikut:
3   6   9   12   15   18
dan dengan argumen 4, outputnya adalah sebagai berikut:
4   8   12   16   20   24
Mulai   sekarang,   Anda   mungkin   sudah   dapat   menerka   bagaimana   cara   kita   untuk 

membuat   tabel   perkalian:   kita   akan   memanggil  printMultiples  secara 

berulang­ulang dengan argumen yang berbeda­beda. Tidak hanya itu, di sini kita juga 

akan menggunakan loop yang berbeda untuk melakukan iterasi ke dalam baris­baris 

tersebut.
int i = 1;
    while (i <= 6) {
    printMultiples (i);
    i = i + 1;
}

Pertama­tama, perhatikan betapa miripnya loop ini dengan yang berada dalam metode 

printMultiples .   Saya   hanya   mengganti   perintah  print  dengan   sebuah 

pemanggilan metode. Cool!

Output dari program ini adalah sebagai berikut:
1  2  3  4  5  6
2  4  6  8  10  12
3  6  9  12  15  18
4  8  12  16  20  24
5  10  15  20  25  30
6  12  18  24  30  36

Bagaimana? Tampak seperti tabel perkalian bukan? Meskipun bentuknya juga kelihatan 

132
agak­agak miring sedikit. Jika bentuk­bentuk seperti ini mengganggu Anda, Java telah 

menyediakan   metode­metode   yang   dapat   memberi   Anda   kendali   lebih   baik   atas 

masalah­masalah output, tapi saya belum mau bertamasya ke sana sekarang. Tunggu ya!

6.7 Metode

Dalam bagian sebelumnya saya menyebutkan, "semua kebaikan yang dapat diberikan 

oleh metode." Sebelumnya, mungkin Anda akan bertanya­tanya, apa saja sih kebaikan­

kebaikan yang dimaksud? Berikut ini adalah beberapa alasan mengapa metode­metode 

tersebut mempunyai posisi yang sangat penting:

• Dengan   memberi   sebuah   nama   untuk   satu   set   perintah­perintah/pernyataan 

tertentu, Anda telah membuat program Anda semakin mudah untuk dibaca   dan 

diperiksa (debug).

• Memecah   program   Anda   yang   panjang   ke   dalam   beberapa   metode   dapat 

memudahkan   Anda   untuk   membaginya   ke   dalam   beberapa   bagian     terpisah. 

Dengan   keadaan   seperti   ini,   Anda   dapat   memeriksa   bagian­bagian   tersebut 

dalam lingkungan yang terisolir (bebas dari bagian lainnya). Untuk kemudian 

merangkainya kembali dalam program "besar" yang Anda inginkan.

• Metode dapat memfasilitasi rekursi sekaligus iterasi.

• Metode   yang   dirancang   dengan   sangat   baik   biasanya   dapat   digunakan   oleh 

program­program lainnya. Sekali saja Anda mampu menulis dan memeriksanya 

dengan baik, otomatis Anda akan dapat menggunakannya kembali. 

6.8 Enkapsulasi .... sekali lagi!

Untuk  mendemonstrasikan  enkapsulasi lagi, Saya akan mengambil kode dari  bagian 

sebelumnya lalu membungkusnya dalam sebuah metode:
public static void printMultTable () {

133
   int i = 1;
   while (i <= 6) {
   printMultiples (i);
   i = i + 1;
   }
}

Proses   yang   sedang   saya   demonstrasikan   adalah   sebuah   strategi   pengembangan 

(development plan) yang umum digunakan. Anda mengembangkan suatu kode secara 

bertahap   dengan   cara   menambah   beberapa   baris   dalam   bagian  main  atau   bagian 

lainnya,   lalu   ketika   Anda   tahu   bahwa   proses   ini   bekerja   dengan   baik,   Anda   lalu 

mengambil dan memasukkannya ke dalam sebuah metode. 

Alasan mengapa cara ini bermanfaat untuk Anda adalah karena terkadang Anda tidak 

mengetahui secara pasti kapan Anda akan membagi program Anda secara terpisah ke 

dalam   beberapa   metode   sekaligus.   Pendekatan   dengan   model   seperti   ini   dapat 

memudahkan Anda untuk melakukan proses perancangan yang beriring /berbarengan 

dengan proses pembuatan program.     

6.9 Variabel Lokal

Saat ini, mungkin Anda sedang kebingungan memikirkan tentang bagaimana sebuah 

variabel   yang   sama,   yakni   i,   dapat   digunakan   oleh   dua   metode   yang   berhubungan 

sekaligus   pada   saat   yang   bersamaan   (printMultiples  dan 

printMultTable ). Bukankah sebelumnya saya tidak pernah mengatakan kepada 

Anda bahwa Anda hanya dapat mendeklarasikan sebuah variabel satu kali saja? Dan 

tidakkah hal yang demikian dapat menimbulkan masalah ketika salah satu dari metode 

tersebut   mengganti   nilai   dari   variabel   miliknya   yang   kita   permasalahkan   tersebut? 

134
Heeee ... bingung ya ....

Jawaban untuk kedua pertanyaan tersebut adalah "tidak," karena variabel i di metode 

printMultiples  dan  i  dalam  printMultTable  adalah  dua variabel  

yang tidak sama. Mereka memang mempunyai dua nama yang sama, tapi mereka tidak 

mengacu kepada satu lokasi penyimpanan yang sama. Oleh karena itulah, mengubah 

nilai salah satu dari mereka tidak akan memberi pengaruh apapun kepada nilai yang 

lainnya.

Variabel­variabel yang dideklarasikan di dalam sebuah metode disebut  variabel lokal 

karena   mereka   terlokalisasi   dalam   metodenya   masing­masing.   Anda   tidak   dapat 

mengakses sebuah variabel lokal dari luar metode yang menjadi "rumahnya". Namun 

Anda dapat memiliki lebih dari satu variabel dengan nama yang sama asalkan mereka 

tidak berada dalam satu metode yang sama.

Adalah sebuah ide yang brillian untuk tetap menggunakan nama­nama variabel yang 

berbeda meskipun variabel­variabel itu tidak berada dalam satu metode yang  sama. Ini 

semata­mata dilakukan untuk menghindari kebingungan. Namun dalam beberapa kasus, 

terkadang akan lebih baik jika kita menggunakan nama variabel yang sama. Sebagai 

contoh,   adalah   sebuah   tradisi   atau   keumuman   dalam   dunia   pemrograman   untuk 

menggunakan nama­nama variabel seperti i, j, dan k sebagai nama­nama variabel untuk 

loop. Jika Anda bersikeras untuk menghindari penggunaan ketiga variabel ini dalam 

sebuah metode hanya karena Anda telah menggunakannya di metode lainnya, mungkin 

Anda justru akan membuat program tersebut semakin sulit untuk dibaca.

6.10 Generalisasi. Sekali lagi dengannya ....

Sebagai satu contoh generalisasi lagi, silahkan membayangkan sebuah program yang 

dapat mencetak tabel perkalian dengan ukuran berapapun, tidak hanya berupa tabel 6 x 

135
6.   Anda   dapat   menambahkan   sebuah   parameter   ke   dalam   metode 

printMultTable :
public static void printMultTable (int high) {
   int i = 1;
   while (i <= high) {
   printMultiples (i);
   i = i + 1;
  }
}

Saya   mengganti   nilai   6   dengan   paramater   yang   saya   namai;  high .   Jika   saya 

memanggil printMultTable  dengan argumen 7, saya akan mendapatkan output 

sebagai berikut:
1 2 3 4 5 6
2 4 6 8 10 12
3 6 9 12 15 18
4 8 12 16 20 24
5 10 15 20 25 30
6 12 18 24 30 36
7 14 21 28 35 42

Keren bukan?  Kecuali bahwa mungkin saya menginginkan hasil di atas agar tampak 

lebih   kotak   (jumlah   baris   dan   kolom   yang   sama;   7   x   7   bukan   7   x   6).   Untuk 

mewujudkannya,   saya   harus   menambahkan   parameter   lain   dalam   metode 

printMultiples ,   untuk   menspesifikasikan   berapa   jumlah   kolom   yang   harus 

dimiliki oleh tabel tersebut.

Agar Anda lebih waspada, saya juga akan menamai parameter ini dengan nama high. 

136
Hal  ini  akan  menunjukkan  kepada  Anda  semua  bahwa  dua  atau  lebih metode  yang 

berbeda dapat memiliki parameter­parameter dengan nama yang sama (persis seperti 

variabel­variabel lokal):
public   static   void   printMultiples   (int   n,   int   high)  
{
   int i = 1;
   while (i <= high) {
   System.out.print (n*i + " ");
   i = i + 1;
  }
  newLine ();
}

public static void printMultTable (int high) {
   int i = 1;
   while (i <= high) {
   printMultiples (i, high);
   i = i + 1;
  }
}

Perhatikan   bahwa   ketika   saya   menambahkan   sebuah   parameter   baru,   saya   harus 

mengubah baris pertama dari metode tersebut (antarmuka atau prototipenya). Selain itu, 

saya   juga   harus   mengubah   tempat   di   mana   metode   itu   dipanggil   dalam   metode 

printMultTable . Seperti yang diharapkan, program ini mampu membuat sebuah 

tabel 7 x 7 yang tampak lebih "kotak":
1 2 3 4 5 6 7
2 4 6 8 10 12 14

137
3 6 9 12 15 18 21
4 8 12 16 20 24 28
5 10 15 20 25 30 35
6 12 18 24 30 36 42
7 14 21 28 35 42 49

Ketika Anda telah menggeneralisasi sebuah metode dengan tepat, terkadang Anda akan 

menjumpai program yang Anda hasilkan ternyata memiliki kapabilitas atau kemampuan 

yang   tidak   persis   seperti   Anda   harapkan.   Sebagai   contoh,   Anda   mungkin 

memperhatikan   bahwa   tabel   perkalian   yang   kita   buat   sebelumnya   memiliki   sifat 

simetris. Hal ini terjadi karena sifat komutatif dalam perkalian yakni ab   =  ba . Jadi, 

semua entri yang berada dalam tabel akan dicetak 2 kali.  Anda dapat menghemat tinta 

dengan   cara   mencetak   tabel   tersebut   setengah   dari   ukuran   normalnya.   Untuk 

melakukannya,   Anda   cukup   mengganti   sebuah   baris   dalam   metode 

printMultTable . Ubahlah perintah:
printMultiples(i, high);
menjadi

  printMultiples(i, i);

dengan pengubahan ini Anda akan mendapatkan hasil sebagai berikut:
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
6 12 18 24 30 36
7 14 21 28 35 42 49

138
Saya   akan   tinggalkan   bagian   ini   khusus   untuk   Anda   agar   Anda   dapat   menemukan 

bagaimana program tersebut dapat menghasilkan output yang sedemikian rupa.

6.11 Daftar Kata­Kata

Istilah Arti
Loop Sebuah pernyataan yang dieksekusi berulang­ulang selama atau 

sampai beberapa syarat/keadaan (condition) dipenuhi.
Infinite loop Sebuah loop yang syarat/kondisinya selalu bernilai benar.

Body Pernyataan yang berada dalam loop.

Iterasi Proses satu kali eksekusi yang terjadi dalam badan (body) loop, 

termasuk di dalamnya adalah pengecekan nilai syarat/kondisi.
Enkapsulasi Membagi sebuah program yang besar dan kompleks ke dalam 

komponen­komponen kecil (seperti metode) untuk kemudian 

mengisolasinya dari komponen­komponen lainnya (contoh, 

dengan cara menggunakan variabel lokal).
Variabel lokal variabel yang dideklarasikan di dalam sebuah metode dan eksis 

hanya di dalam metode tersebut. Variabel lokal tidak dapat 

diakses dari luar metode yang menjadi "rumah" mereka. 

Variabel ini juga tidak akan berinterferensi (bertabrakan) 

dengan metode­metode lainnya.
Generalisasi Mengganti sesuatu yang spesifik  tapi tidak penting (misalnya 

nilai   konstan)   dengan   sesuatu   yang   lebih   cocok/tepat   secara 

umum (seperti variabel atau parameter). Generalisasi membuat 

kode  lebih fleksibel, memungkinkan untuk digunakan kembali, 

dan terkadang lebih mudah dan nyaman untuk dibaca.
Development plan Suatu proses untuk mengembangkan sebuah program. Dalam 

139
Istilah Arti
bab ini, saya  mendemonstrasikan sebuah teknik pengembangan 

yang berbasis pada pengembangan kode untuk melakukan 

sesuatu yang sederhana, khusus, lalu mengenkapsulasi dan 

menggeneralisasinya. Dalam bagian 5.2 saya 

mendemonstrasikan sebuah teknik yang saya sebut 

pengembangan bertingkat. Di bab­bab akhir saya akan 

menunjukkan teknik pengembangan yang lain.

6.12 Latihan

Latihan 6.1
public  static  void  main  (String[]  args)  {
   loop  (10);
}

public  static  void  loop  (int  n) {


   int  i =  n;
   while  (i  > 0)  {
       System.out.pr intln  (i);
       if (i%2  ==  0) {
           i  = i/2;
       } else  {
           i  = i+1;
       }
   }
}

a) Buatlah sebuah tabel yang dapat menunjukkan nilai dari variabel i dan n selama loop 

sedang dieksekusi. Tabel tersebut harus berisi satu kolom untuk setiap variabel dan 

140
satu baris untuk setiap iterasi.

b) Apa output dari program ini?

Latihan 6.2

a) Enkapsulasilah fragmen kode di bawah ini, kemudian ubahlah bentuknya ke dalam 

metode yang menggunakan sebuah variabel bertipe String sebagai argumennya dan 

mengembalikan (tapi bukan mencetak) nilai terakhir dari count.

b) Dalam sebuah kalimat, deskripsikan secara abstrak apa yang telah dihasilkan oleh 

metode buatan Anda tersebut.

c) Asumsikan bahwa Anda telah menggeneralisasi metode berikut ini sehingga ia dapat 

digunakan untuk semua String. Menurut Anda, kira­kira apa lagi yang dapat Anda 

lakukan sehingga metode tersebut dapat lebih tergeneralisasi?
String  s =  "((3 +  7) *  2)";
int len  = s.length  ();
int i  = 0;
int count  =  0;

while  (i <  len) {


    char  c  = s.charAt(i);

    if  (c ==  '(')  {


count  =  count  + 1;
    }  else  if (c  == ')')  {
          count  =  count  ­ 1;
    }
    i  = i +  1;
}
System.out.pr intln  (count);

141
Latihan 6.3

Misalkan Anda diberi sebuah bilangan, misalkan  a, lalu Anda ingin menemukan nilai 

akarnya. Salah satu cara yang dapat digunakan adalah dengan menebak mentah­mentah 

nilai tersebut dengan sebuah bilangan misalkan, xo. Lalu, menaikkan tingkat kebenaran 

bilangan tersebut dengan menggunakan rumus berikut ini:
x1  = ( x 0  +  a/x 0 ) /2                   (6.2)
Sebagai contoh, jika kita hendak menemukan akar dari 9. Kita bisa memulai tebakan 

kita dengan xo = 6, kemudian x1 =  (6 + 9/6) / 2  = 15 / 4 = 3.75. Lihat, mulai mendekati 

bukan?

Kita dapat mengulangi prosedur ini, dengan menggunakan x1 untuk menghitung nilai x2, 

x2 untuk x3, lalu seterusnya. Dalam contoh yang kita gunakan, berarti x2 = 3.075 dan x3 

= 3.00091. Begitu seterusnya, sampai mendekati nilai pendekatan yang kita tetapkan.

Buatlah sebuah metode dengan nama squareRoot yang menggunakan sebuah variabel 

bertipe  double  sebagai   parameter   dan   mengembalikan   sebuah   nilai   pendekatan   dari 

parameter  tersebut,   dengan   menggunakan   algoritma  di   atas   tentunya.   Anda   dilarang 

menggunakan metode Math.sqrt yang merupakan  metode bawaan (built­in) Java.

Gunakan  a/2  sebagai   nilai   awal   tebakan   Anda.   Metode   Anda   harus   melakukan 

perulangan   (iterasi)   sampai   metode   ini   menghasilkan   dua   nilai   pendekatan   yang 

berurutan   dan   juga   memiliki   selisih   kurang   dari   0.0001.   Anda   dapat   menggunakan 

metode Math.abs untuk menghitung nilai mutlak.

Latihan 6.4

Dalam   latihan   5.9   kita   telah   menulis   sebuah   versi   rekursif   untuk   mencari   bilangan 

pangkat (power) yang menggunakan variabel  x  bertipe  double  dan  n  bertipe  integer 

142
serta   mengembalikan   nilai  xn.   Sekarang,   tulislah   sebuah   metode   iteratif   untuk 

melakukan hal yang sama.

Latihan 6.5

Bagian 5.10 memperlihatkan sebuah metode rekursif yang menghitung nilai dari fungsi 

faktorial. Tulislah sebuah versi iteratif dari metode faktorial.

Latihan 6.6

Salah satu cara untuk menghitung ex adalah dengan menggunakan bentuk ekspansi tak 

hingga berikut ini:
e x  = 1 + x + x 2
/2! + x 3 /3! + x 4 /4! + ....   (6.3)

Jika variabel loop kita namai dengan i, maka urutan term yang ke­i akan sama dengan 

xi/i!.

a) Buatlah sebuah metode dengan nama  myexp  yang mampu menjumlahkan  n  term 

pertama dari bentuk di atas. Anda dapat menggunakan metode factorial dari bagian 

5.10 atau versi iteratifnya. Terserah! 

b) Anda dapat membuat metode ini lebih efisien jika saja Anda sadar bahwa dalam 

setiap   iterasi,   nilai   numerator   dari   term   sama   dengan   nilai  predecessor­nya 

(sebelumnya) dikali dengan x, sementara denominatornya adalah sama dengan nilai 

predecessor­nya  dikali   dengan  i.   Gunakan   hasil   analisa   ini   untuk   meniadakan 

penggunaan Math.pow dan factorial, lalu periksalah kembali dengan cermat bahwa 

Anda masih tetap akan mendapatkan hasil yang sama.

c) Buatlah sebuah metode dengan nama check, yang menggunakan sebuah parameter, 

yakni  x. Metode Anda ini akan memiliki kemampuan untuk mencetak nilai dari  x, 

Math.exp(x)  dan  myexp(x)  untuk   berbagai   variasi   nilai  dari  x.  Hasil   yang   akan 

143
ditampilkan harus tampak seperti berikut:
1.0    2.708333333333333    2.718281828459045

Petunjuk: Anda dapat menggunakan String "\t" untuk mencetak sebuah karakter tab 

diantara kolom­kolom dalam tabel tersebut.

d) Ubah­ubahlah   (variasikan)   nilai­nilai   term   (argumen   kedua   yang   dikirimkan   oleh 

metode check kepada myexp), lalu lihatlah pengaruhnya terhadap akurasi dari hasil 

tersebut. Cocokkan nilai ini hingga nilai yang diperkirakan (estimasi) sesuai dengan 

jawaban ketika x sama dengan 1.

e) Tulislah sebuah loop dalam main yang memanggil metode check dengan nilai 0.1, 

1.0, 10.0, dan 100.0. Lihat bagaimana akurasi (ketepatan) dari hasil yang ditampilkan 

ketika nilai  x  juga bervariasi. Bandingkan jumlah digit dari  agreement  ketimbang 

membandingkan perbedaan antara nilai aktual dan nilai perkiraan.

f) Tambahkan   sebuah   loop   dalam  main  yang   berfungsi   untuk   memeriksa  myexp 

dengan nilai  ­0.1, ­1,0, ­10.0,  dan  ­100.0. Berilah tanggapan untuk ketepatan yang 

dihasilkan.

Latihan 6.7

Salah satu cara yang digunakan untuk mengevaluasi bentuk  e^(­x^2)  adalah dengan 

menggunakan bentuk ekspansi tak­hingga berikut:
e^(­x^2)  =   1­2 x  +   3x 2/ 2!   ­  4x 3 /3!   +   5x 4 /4!­   ......  
(6.4)

Dengan kata lain, kita perlu menambahkan beberapa term dimana term yang ke­i akan 

sama   dengan  (­1)i  (i+1)   xi  /   i!.   Buatlah   sebuah   metode   dengan   nama  Gauss  yang 

menggunakan  x  dan  n  sebagai   argumen.   Metode   ini   akan   mengembalikan   nilai 

penjumlahan   dari  n­term   pertama.   Anda   tidak   diperkenankan   untuk   menggunakan 

metode factorial atau pow.

144
Bab 7

String

7.1 Memanggil metode dalam objek

Dalam   Java   dan   bahasa   pemrograman   berorientasi   objek   lainnya,   objek   merupakan 

koleksi   dari   data   dan   sekumpulan   metode   yang   saling   berkaitan.       Metode­metode 

digunakan   untuk   melakukan   operasi­operasi   tertentu   dalam   objek,   mengerjakan 

perhitungan dan terkadang memodifikasi data milik objek itu sendiri. 

Diantara semua tipe data yang telah kita bahas sampai saat ini, hanya String yang dapat 

dikategorikan sebagai suatu objek. Berdasarkan pengertian objek yang telah kita ungkap 

di atas, mungkin di antara Anda akan ada yang bertanya, “data apa yang dimiliki oleh 

suatu String yang juga berstatus objek?” dan “metode­metode apa saja yang dapat kita 

panggil untuk memfungsikan objek­objek yag berupa  String?”

Data yang terkandung dalam objek String adalah huruf­huruf dari string itu sendiri. 

Sebenarnya ada cukup banyak metode yang dapat  digunakan  untuk mengoperasikan 

atau   beroperasi   dalam   objek­objek   String,   tapi   di   buku   ini   Saya   hanya   akan 

menggunakan beberapa di antaranya saja. Sisanya dapat Anda simak   dalam halaman 

berikut:

 http://java.sun.com/javase/6/ docs/api/java/lang/String.html
   

Metode pertama yang akan kita bahas adalah charAt. Metode ini dapat Anda gunakan 

untuk   mengambil/mengekstrak   huruf­huruf   yag   berada   dalam   sebuah   String.   Untuk 

menyimpan hasil pengambilan tersebut, kita membutuhkan sebuah variabel yang dapat 

menyimpan huruf­huruf tersebut sebagai sebuah satuan tersendiri (kebalikan dari String 

itu sendiri yang merupakan sekumpulan item­item yang berurutan). Satu satuan huruf 

145
itu   disebut   sebagai  karakter  (character),   dan   tipe   data   yang   digunakan   untuk 

menyimpannya disebut dengan char.

char  bekerja dengan cara yang sama seperti tipe data­tipe data yang sudah kita lihat 

sebelumnya:
char fred = 'c';
   if (fred == 'c') {
   System.out.println (fred);
}

Nilai  karakter tampil dalam kurungan tanda petik satu  'c'. Ini berbeda dengan nilai 

variabel bertipe data String yang diapit dengan tanda petik ganda ( “ ” ). Nilai variabel 

bertipe data char hanya boleh mengandung satu huruf atau satu simbol saja. Berikut ini 

adalah cara menggunakan metode charAt:
String fruit = "banana";
char letter = fruit.charAt(1);
System.out.println (letter);

Sintaks fruit.charAt mengindikasikan bahwa Saya sedang memanggil metode charAt 

dalam sebuah objek yang bernama fruit. Argumen yang Saya lewatkan (pass) untuk 

metode  ini  adalah 1. Hal ini  mengindikasikan  kepada Anda  bahwa saya  tampaknya 

ingin mengetahui huruf pertama dari string tersebut. Hasilnya adalah sebuah karakter 

yang saya simpan dalam sebuah variabel bertipe data char, yakni letter. Ketika saya 

mencetak nilai variabel letter itu, saya pun terkejut:

Hei .... bukankah a itu huruf kedua? Anda juga mungkin akan terkejut, kecuali kalau 

Anda adalah seorang Computer Scientist. Untuk beberapa alasan tertentu, para ilmuwan 

146
komputer cenderung untuk memulai perhitungan dari 0. huruf yang berada pada urutan 

ke­0 dalam string “banana” adalah b. sedangkan urutan yang ke­1 adalah a, urutan ke­2 

adalah n, dst. Jadi, jika Anda menginginkan huruf yang berada pada urutan ke­0 dari 

sebuah   string,   Anda   harus   menggunakan   0   sebagai   argumen   yang   Anda   lewatkan. 

Simaklah kode berikut ini:

  char letter = fruit.charAt(0);

7.2 Length

Metode kedua untuk String yang akan kita bahas adalah length. Metode ini berfungsi 

untuk mengembalikan jumlah karakter yang menyusun suatu string. sebagai contoh:

int length = fruit.length();

length tidak membutuhkan argumen apapun. Hal ini dapat dilihat dari tanda “ ( ) ” yang 

memang tidak terisi dengan apapun. Metode ini akan mengembalikan nilai yang bertipe 

integer,   dalam   kasus   di   atas,   nilai   yang   dikembalikan   adalah   6.   Perhatian!     Adalah 

sesuatu yang legal dalam Java untuk menamai sebuah variabel dengan nama yang sama 

seperti   nama   metode.   Namun   Anda   harus   tetap   hati­hati   karena   hal   ini   dapat 

menimbulkan kebingungan untuk pengguna yang sedang membaca kode tersebut. 

Untuk mencari nilai akhir dari sebuah string, terkadang Anda mungkin akan tergoda 

untuk melakukan sesuatu seperti yang tampak dalam dua baris berikut:
int length = fruit.length();
char last = fruit.charAt(length); // wrong!!

Itu tidak akan berhasil. Mengapa? Karena memang tidak ada huruf ke­6 dalam string 

“banana”. Ingat! Kita melakukan perhitungan dari angka 0. Jadi, string yang memiliki 6 

huruf akan diurut menggunakan nomor urutan 0 hingga 5, bukan 1 hingga 6. Untuk 

mendapatkan   karakter   terakhir,   Anda   harus   mengurangkan   length   dengan   angka   1. 

Perhatikan kode berikut:

147
int length = fruit.length();
char last = fruit.charAt(length ­ 1);

7.3 Traversal

Pola/hal   umum   yang   sering   dijumpai   dalam   bentuk­bentuk   string   adalah   kegiatan 

berikut; mulailah dari awal, pilihlah setiap karakter secara bergantian, lakukan sesuatu 

terhadap   karakter   itu,   lalu   lanjutkan   hingga   karakter   terakhir.   Pola   pemrosesan   ini 

dikenal   dengan   sebutan   traversal.   Cara   alami   untuk   meng­enkode   sebuah   traversal 

adalah dengan menggunakan pernyataan while:
int index = 0;
while (index < fruit.length()) {
 char letter = fruit.charAt (index);
 System.out.println (letter);
 index = index + 1;
}

Loop   di  atas   akan  men­traverse  string   dan  mencetak   setiap   huruf  dalam  satu  baris. 

Perhatikan   bahwa   syarat   yang   digunakan   dalam   kode   di   atas   adalah   index   < 

fruit.length(). Artinya, ketika index sama dengan panjang dari string, syarat tersebut 

akan   bernilai   false.   Akibatnya,   badan   dari   loop   itu   tidak   akan   dieksekusi.   Karakter 

terakhir yang kita akses adalah karakter dengan urutan fruit.length() ­ 1.

Nama dari variabel loop adalah index. Satu index merupakan suatu variabel atau nilai 

yang digunakan untuk menentukan satu anggota dari sebuah himpunan berurutan (baca: 

himpunan   karakter   yang   berada   dalam   string).   Index   ini   akan   menentukan   karakter 

mana   (baca:   nama   karakter   tersebut)   yang   Anda   inginkan.   Himpunan   ini   haruslah 

merupakan suatu himpunan berurutan agar setiap huruf dapat memilki index dan setiap 

index dapat mengacu kepada satu karakter saja.

148
Sebagai   latihan,   tulislah   sebuah   metode   yang   menggunakan   String   sebagai   sebuah 

argumen   dan   yang   mampu   mencetak   semua   huruf   dalam   posisi   yang   berkebalikan 

(backwards). Cetak semua huruf tersebut dalam satu baris tampilan saja.

 7.4 Run­Time errors

Kembali lagi ke bagian 1.3.2, di sana saya telah menyinggung sedikit mengenai run­

time errors. Istilah ini digunakan untuk menunjukkan suatu error dalam program yang 

tidak akan ditampilkan kecuali kalau program itu telah dijalankan (running). Dalam 

Java, run­time error disebut juga dengan exceptions.

Sejauh ini, Anda mungkin belum terlalu sering melihat run­time errors. Maklum saja, 

ini karena kita memang belum banyak mengerjakan sesuatu yang dapat menyebabkan 

terjadinya runtime errors itu sendiri. Nah, sekaranglah saatnya. Jika Anda menggunakan 

perintah charAt lalu pada saat yang bersamaan Anda juga menggunakan sebuah index 

yang bernilai negatif atau lebih besar dari length­1, maka Anda akan menjumpai sebuah 

exceptions. Dalam kasus ini; StringIndexOutOf BoundsException. Cobalah dan lihat 

bagaimana exceptions ini bekerja.

Jika program Anda menyebabkan terjadinya suatu exceptions, maka program tersebut 

akan   mencetak   sebuah   pesan   error   yang   mengindikasikan   tipe   exceptions   sekaligus 

lokasi terjadinya error tersebut dalam program Anda.

7.5 Membaca Dokumentasi

Jika   Anda   mengunjungi   situs 

http://java.sun.com/javase/6/docs/api/java/lang/String.html,  lalu   Anda   mengklik   link 

charAt, Anda akan mendapatkan dokumentasi yang tampak (mungkin mirip) seperti di 

bawah ini:
public  char  charAt(int  index)

149
Returns  the  character  at  the  specified  index.
An index  ranges  from  0  to length()  ­ 1.
Parameters:  index  ­ the  index  of the  character.
Returns:  the  character  at the  specified  index  of  this  
string.
     The  first  character  is  at index  0.
Throws:   StringIndexOut OfBoun dsExce ption   if   the   index   is  
out of  range.

Baris pertama adalah prototipe milik metode charAt yang berisi nama dari metode ini, 

tipe data dari parameter dan nilai pengembalian yang digunakan.

Baris   berikutnya   menginformasikan   manfaat/fungsi   dari   metode.   Berikutnya, 

merupakan informasi mengenai parameter­parameter  dan nilai pengembalian. Dalam 

kasus   ini,   penjelasan   yang   diberikan   mungkin   terkesan   berulang­ulang,   tapi 

dokumentasi seperti inilah yang merupakan bentuk standar dokumentasi dalam Java. 

Baris   terakhir   akan   menjelaskan   kepada   kita   mengenai   exceptions,   kalau   memang 

benar­benar ada, yang dapat disebabkan karena penggunaan metode ini.

7.6 Metode indexOf

Dalam beberapa hal, indexOf dapat disebut sebagai lawan (anti) dari metode charAt. 

Alasannya? Ini karena charAt bekerja dengan cara mengambil nilai sebuah index lalu 

mengembalikan   karakter   yang   diacu   (diindeks)   pada   indeks   tersebut.   Sementara 

indexOf   bekerja   dengan   cara   mengambil   sebuah   karakter   lalu   mengembalikan   nilai 

indeks tempat dimana karakter tersebut berada.

charAt akan gagal manakala indeks yang dimintanya berada di luar jangkauan. Hal ini 

akan menyebabkan terjadinya exceptions pada program. Lain dengan metode indexOf 

yang akan mengalami kegagalan jika karakter yang diminta tidak berada dalam string 

yang dimaksud. Pada saat kasus seperti ini terjadi, metode ini akan mengembalikan nilai 

150
­1. 
String fruit = "banana";
int index = fruit.indexOf('a');
Kode   di   atas   digunakan   untuk   menemukan   indeks   (lokasi)   huruf   '   a   '   dalam   string 

“banana”. Menariknya, huruf yang kita inginkan ternyata muncul sebanyak 3 kali. Jadi, 

metode ini (seharusnya Anda juga) mungkin akan mengalami “kebingungan” karena 

tidak tahu harus mengembalikan nilai indeks yang mana untuk huruf ' a '. Dalam kasus­

kasus seperti inilah terkadang sebuah dokumentasi menjadi sangat bermanfaat. Bila kita 

mengacu pada informasi dalam dokumentasi, kita akan tahu bahwa metode indexOf 

akan mengembalikan nilai indeks dari kemunculan karakter ' a ' yang pertama kali (a 

diindeks pada urutan yang pertama. Ingat, Java memulai indeks dari urutan 0 bukan 1). 

Untuk menemukan indeks dari kemunculan berikutnya, ada versi alternatif dari metode 

indexOf  (penjelasan lebih lanjut  mengenai kasus  overloading semacam ini,  silahkan 

membuka kembali bagian 5.4). Kita membutuhkan argumen kedua yang akan berfungsi 

untuk menginformasikan lokasi pada string dimana kita akan memulai pencarian. Jika 

kita memanggil
int index = fruit.indexOf('a', 2);
kode   ini   akan   mulai  melakukan   pencarian   pada   huruf   yang   berada  di   urutan   kedua 

(sekali lagi ingat, dalam Java ini berarti huruf ' n ' bukan ' a '), dan akan langsung 

menemukan karakter a yang kedua pada indeks ketiga. Jika huruf yang dicari tepat 

berada pada indeks dimana kita memulai pencarian, maka indeks ini sendirilah yang 

menjadi jawaban (nilai yang dikembalikan oleh indexOf). Dus, 
int index = fruit.indexOf('a', 5);
akan   mengembalikan   nilai   5.   Kalau   kita   membaca   kembali   dokumentasi   resmi 

mengenai   metode   ini,   mungkin   tidak   ada   salahnya   jika   kita   sedikit   bereksperimen 

dengan   cara   memberikan   nilai   indeks­mulai   pencarian   yang   lebih   besar   ketimbang 

151
jangkauan string yang kita maksudkan:
Metode   indexOf   mengembalikan   nilai   indeks   dari 
karakter   pertama   yang   berada   dalam   string   yang 
direpresentasikan   melalui   objek   yang   lebih   besar 
atau   sama   dengan   indeks­mulai,   atau   ­1   jika 
karakter   yang   dimaksud   tidak   berada   dalam   string 
tersebut.

indexOf returns the index of the rst occurrence of 
the character in the character sequence represented 
by   this   object   that   is   greater   than   or   equal   to 
fromIndex, or ­1 if the character does not occur.

Salah satu cara untuk mengetahui maksud 'aneh' dokumentasi di atas adalah dengan 

menguji­cobanya. Berikut hasil uji coba saya:

● Jika   indeks­mulai   lebih   besar   atau   sama   dengan   length(),   hasil   yang   akan 

dikembalikan   adalah   ­1.   Hasil   ini   mengindikasikan   bahwa   huruf   yang 

dicari/diinginkan tidak berada dalam indeks yang lebih besar daripada indeks­

mulai.

● Jika indeks­mulai bernilai negatif, hasilnya adalah 1. hasil ini mengindikasikan 

bahwa kemunculan pertama huruf yang dicari berada dalam indeks yang lebih 

besar daripada nilai indeks­mulai.

Jika  Anda  membaca  ulang dokumentasi tersebut, Anda  akan  memahami bahwa dua 

keadaan di atas memang sesuai dengan definisi yang ada dalam dokumentasi. Meskipun 

mungkin definisi tersebut awalnya tidaklah terlalu jelas. Nah, karena kita semua sudah 

mengetahui   cara   kerja   indexOf   dengan   benar,   sekarang   barulah   kita   bisa 

152
menggunakannya dalam program­program yang akan kita buat.

7.7 Looping dan Counting

Program berikut ini akan menghitung frekwensi kemunculan huruf ' a ' dalam string:

String fruit = "banana";
int length = fruit.length();
int count = 0;

int index = 0;
while (index < length) {
if (fruit.charAt(index) == 'a') {
count = count + 1;
}
index = index + 1;
}
System.out.println (count);

Program   ini   menunjukkan   sebuah   istilah   populer   dalam   dunia   pemrograman,   yakni 

counter.   Variabel   count   awalnya   diinisialisasi   dengan   nilai   0   lalu   kemudian   secara 

bertahap akan dinaikkan nilainya tiap kali program menemukan ' a '. Ketika kita keluar 

dari loop, count akan berisi nilai yang berupa jumlah total ' a ' yang ditemukan dalam 

string. 

Sebagai latihan awal, enkapsulasilah kode ini ke dalam sebuah metode dengan nama 

countLetters. Lalu generalisasilah kode itu sehingga dapat menerima string dan huruf 

sebagai argumen­argumen.

Untuk   latihan   yang   kedua,   tulis­ulanglah   metode   itu   dengan   memasukkan   indexOf 

153
untuk   mencari   letak   huruf   yang   diinginkan   ketimbang   melakukan   pemeriksaaan 

karakter­karakter tersebut satu­per­satu.

7.8 Operator Increment dan Decrement

Sebelum kita pergi lebih jauh, ada baiknya jika kita pahami terlebih dahulu apa yang 

dimaksud dengan increment dan decrement. 

● Increment berarti  menaikkan/menambahkan  nilai suatu variabel dengan nilai 

satu (1) secara berulang­ulang sampai syarat yang ditetapkan bernilai false.

● Decrement berarti  menurunkan/mengurangi  nilai suatu variabel dengan nilai 

satu (1) secara berulang­ulang sampai syarat yang ditetapkan bernilai false.

Baik increment maupun decrement sebenarnya hanya operator biasa. Namun, dalam 

Java, keduanya memang mendapatkan operator khusus, yakni ' ++ ' untuk increment 

dan ' ­­ ' untuk decrement. Operator ++ akan menambahkan satu (1) untuk nilai yang 

sedang disimpan oleh suatu variabel yang bertipe int atau char. Sementara operator ' ­­ ' 

akan mengurangi satu. Keduanya tidak dapat digunakan untuk variabel bertipe double, 

boolean, atau String. 

Secara  teknis,   adalah   legal   dalam  Java   untuk   meng­increment   suatu   variabel,   untuk 

kemudian langsung menggunakannya dalam sebuah ekspresi. Sebagai   contoh, Anda 

boleh membuat ekspresi seperti berikut:
System.out.println (i++);
Melihat ekspresi seperti ini, hasil yang akan ditampilkan tentunya belum jelas, apakah 

increment   yang   kita   lakukan   akan   bekerja   sebelum   nilai   tersebut   dicetak   ataukah 

sesudahnya.  Mengingat ekspresi­ekspresi seperti ini dapat menimbulkan kebingungan, 

saya tidak menganjurkan kepada Anda untuk memakainya. Dan untuk membuat Anda 

lebih tidak ingin memakainya, saya tidak akan memberi tahu Anda hasil ekspresi di 

atas. Namun jika Anda sungguh­sungguh hendak mengetahuinya, coba saja sendiri!

154
Menggunakan operator increment, kita dapat menulis ulang letter­counter:
int index = 0;
while (index < length) {
if (fruit.charAt(index) == 'a') {
count++;
}
index++;
}
Anda akan menjumpai pesan error jika menulis ekspresi seperti di bawah ini:
index = index++; // WRONG!!
Sayangnya,   ekspresi   tersebut   dianggap   legal   secara   sintaks.   Jadi,   kompiler   Java 

mungkin tidak akan memberikan peringatan untuk Anda sebelumnya. Dampak yang 

timbul dari pernyataan ini adalah tidak berubahnya nilai variabel index yang seharusnya 

hendak kita ubah. Kesalahan seperti ini terkadang menjadi bug yang sulit untuk dilacak 

keberadaannya.

Ingatlah, Anda dapat menulis ekspresi 

index = index + 1; 

atau 

index++;

tapi sebaiknya jangan sampai mencampur/menggabungnya.

7.9 Strings are Immutable

Ketika Anda melihat­lihat kembali dokumentasi untuk metode String, Anda mungkin 

akan memperhatikan metode toUpperCase dan toLowerCase. Metode ini sering menjadi 

biang masalah. Kok bisa? Karena keduanya tampak seolah­olah telah mengubah string 

yang sudah ada ke bentuk lainnya. Padahal, sebenarnya tidak ada satupun metode yang 

dapat mengubah suatu string, karena string memang bersifat  immune  alias tidak bisa 

155
diubah­ubah. 

Simak yang berikut ini! Ketika Anda memanggil toUpperCase dalam sebuah String, 

Anda akan mendapatkan sebuah String  baru  (untuk sementara anggap saja demikian) 

sebagai hasil dari nilai yang dikembalikan oleh metode. Sebagai contoh:
String name = "Alan Turing";
String upperName = name.toUpperCase ();
Setelah baris kedua dieksekusi, upperName akan berisi nilai “ALAN TURING”, tapi 

tidak juga, karena sebenarnya variabel name masih berisi “Alan Turing”.

7.10 Strings are Incomparable

Terkadang   ada   saat­saat   dimana   membandingkan   dua   string   merupakan   hal   yang 

penting. Perbandingan ini digunakan misalnya; untuk melihat apakah dua string yang 

dibandingkan  tersebut   sama   ataukah   tidak,  atau   untuk   melihat   string   manakah  yang 

berada   di   depan   string   lainnya   bila   dilihat   secara   alfabetis   (in   alphabetical   order). 

Senang   rasanya   jika   kita   dapat   menggunakan   operator­operator   perbandingan   yang 

sudah ada, seperti == dan >, tapi sayang, Java tidak mengizinkannya.

Untuk membandingkan String, kita harus menggunakan metode equals dan compareTo. 

Contoh: 
String name1 = "Alan Turing";
String name2 = "Ada Lovelace";

if (name1.equals (name2)) {
System.out.println ("The names are the same.");
}

int flag = name1.compareTo (name2);
if (flag == 0) {

156
System.out.println ("The names are the same.");
} else if (flag < 0) {
System.out.println ("name1 comes before  
name2.");
} else if (flag > 0) {
System.out.println ("name2 comes before  
name1.");
}

Sintaks   yang   Anda   lihat   di   atas   mungkin   kelihatan   aneh   (yaa,   gitu   deh).   Untuk 

membandingkan dua string, Anda harus memanggil sebuah metode melalui salah satu 

string itu lalu melewatkan yang lainnya sebagai argumennya.

Nilai   kembalian  dari   metode equals  terkesan  lugas  dan jelas;  true  jika  kedua  string 

berisi karakter­karakter yang sama, dan false jika tidak.

Namun     nilai   yang   dikembalikan   oleh   compareTo   terkesan   agak   ganjil   alias   aneh. 

Parameter yang dibandingkan adalah karakter pertama dalam string saja. Jika kedua 

string   itu   sama,   maka   nilai   kembalian   adalah   0.   Jika   string   pertama   (string   tempat 

metode  compareTo dipanggil) mendahului string kedua dalam urutan alfabetis, nilai 

kembalian   akan   negatif.   Jika   tidak,   maka   nilainya   positif.   Dalam   contoh   ini,   nilai 

pengembaliannya   adalah   8.   Ini   disebabkan   karena   huruf   kedua   dalam   string   “Ada 

Lovelace” mendahului huruf kedua string “Alan Turing” sebanyak 8 huruf (huruf D dan 

L terpisah sebanyak 8 huruf dalam alfabet; cara menghitung; E  F  G  H  I  J  K  L).

Menggunakan metode compareTo terkadang malah merepotkan. Meskipun begitu, sisi 

positif dari metode ini adalah bahwa interface yang digunakannya bisa dibilang cukup 

lumayan sebagai standar untuk membandingkan berbagai tipe objek. Jadi, ketika Anda 

sudah memahami cara menggunakannya, Anda akan lebih siap untuk yang lainnya.

157
Sebagai pelengkap, saya harus mengakui bahwa adalah  legal  dalam Java, meskipun 

jarang sekali benar, menggunakan operator ' = = ' untuk tipe data String. Anda mengerti 

maksud saya? Tidak! Itu wajar, karena pembahasannya akan berada di bagian­bagian 

berikutnya. Sabar ya .....

7.11 Daftar Kata­Kata

Istilah Arti
Object Sebuah koleksi yang mengandung data yang saling berkaitan 

dan sekumpulan metode yang dapat beroperasi di dalamnya. 

Objek   yang   telah   kita   gunakan   sejauh   ini   adalah   objek 

Graphic yang disediakan oleh system dan String. 
Index  Sebuah variabel atau nilai yang digunakan untuk memilih satu 

anggota dari suatu himpunan terurut. Misalnya, satu karakter 

dalam string.
Traverse  Melakukan   suatu   operasi   yang   sama   secara   berulang­ulang 

untuk seluruh elemen yang berada dalam sebuah himpunan. 
Counter  Sebuah variabel yang digunakan untuk menghitung sesuatu. 

Variabel   ini   biasanya   diinisialisasi   dengan   nilai   0     lalu 

dinaikkan satu­satu secara bertahap (increment).
Increment menaikkan/menambahkan  nilai suatu variabel dengan nilai 

satu (1) secara berulang­ulang sampai syarat yang ditetapkan 

bernilai false. Operatornya adalah ++
Decrement  menurunkan/mengurangi  nilai suatu variabel dengan nilai 

satu (1) secara berulang­ulang sampai syarat yang ditetapkan 

bernilai false. Operatornya adalah ­­
Exceptions  Sebuah run time error. Exceptions menyebabkan terhentinya 

158
proses eksekusi sebuah program.

7.12 Latihan

Latihan 7.1

Inti   dari   latihan   ini   adalah   untuk   mencoba   beberapa   operasi   yang   berkaitan   dengan 

String dan  memasukkan beberapa bagian yang belum dibahas dalam bagian ini.

a) Buatlah sebuah program dengan nama Test.java, lalu buatlah sebuah metode main 

yang   berisi   ekspresi­ekspresi   yang   mengkombinasikan   beberapa   tipe   data 

menggunakan   operator   '   +   '.   Sebagai   contoh,   apa   yang   akan   terjadi   jika   Anda 

“menambahkan”   sebuah   String   dan   sebuah   char?   Apakah   ekspresi   ini   akan 

menghasilkan penambahan (addition) atau penggabungan (concatenation).

b) Buatlah tabel yang lebih besar ketimbang tabel di bawah ini! Lalu isilah setiap irisan 

(interseksi)   yang   terjadi   antara   tipe   data­tipe   data   ini   dengan   informasi   yang 

memberitahu legal­tidaknya penggunaan operasi ' + ' . Jika legal, maka termasuk 

kategori yang manakah operasi tersebut. Apakah penambahan atau penggabungan.

c) Bayangkan dan pikirkanlah beberapa pilihan yang telah dibuat oleh developer Java 

ketika   mereka   hendak   mengisi   tabel   ini.   Berapa   entri   di   dalamnya   yang   tampak 

masuk   akal,  jika  kemungkinan  untuk   masuk  akal   itu   sendiri  mungkin  tidak  ada? 

Berapa banyak diantaranya yang tampak seperti hasil dari pemilihan acak atau suka­

suka   (arbitrary)   dari   beberapa   kemungkinan   yang   masuk   akal?   Berapa   banyak 

diantaranya yang kelihatan sebagai hasil pilihan bodoh?

d) Waktunya bermain teka­teki: normalnya, pernyataan x++ equivalen dengan x = x + 

1.   Kecuali   jika   x   adalah   char.   Dalam   kasus   ini,   x++   adalah   sesuatu   yang   legal. 

Namun tidak dengan x = x + 1. 

159
e) Ujilah! Lalu lihatlah pesan error yang keluar. Jangan lupa, berusahalah juga untuk 

memahami apa yang sebenarnya terjadi dengan error itu. 

Latihan 7.2

Apakah output yang akan dihasilkan program ini? Ungkapkanlah dalam sebuah kalimat, 

secara abstrak, sebenarnya apa sih bing itu (tapi bukan bagaimana cara ia bekerja)?
public class Mystery {

public static String bing (String s) {
int i = s.length() ­ 1;
String total = "";

while (i >= 0 ) {
char ch = s.charAt (i);
System.out.println (i + " " + ch);

total = total + ch;
i­­;
}
return total;
}

public static void main (String[] args) {
System.out.println (bing ("Allen"));
}
}

Latihan 7.3

160
Salah   seorang   temanmu   menunjukkan   metode   berikut   ini   kepadamu.   Ia   juga 

menjelaskan bahwa jika variabel number adalah semua bilangan yang terdiri dari dua 

digit, maka program akan mengeluarkan bilangan tersebut secara terbalik (backward). 

Dia mengklaim bahwa kalau number sama dengan 17, output akan sama dengan 71. 

Benarkah itu? Jika tidak, jelaskan apa yang sebenarnya dikerjakan oleh program. Lalu 

modifikasilah program ini sehingga bisa berfungsi dengan baik dan tepat.
int number = 17;
int lastDigit = number%10;
int firstDigit = number/10;
System.out.println (lastDigit + firstDigit);

Latihan 7.3

Apakah output dari program ini?
public class Rarefy {

public static void rarefy (int x) {
if (x == 0) {
return;
} else {
rarefy (x/2);
}

System.out.print (x%2);
}

public static void main (String[] args) {
rarefy (5);

161
System.out.println ("");
}
}
Jelaskan dalam 4 s.d. 5 kata tentang apa yang sebenarnya dikerjakan oleh metode ini.

Latihan 7.5

a) Buatlah sebuah program dengan nama Palindrome.java.

b) Buatlah sebuah metode dengan nama first dan last yang menggunakan sebuah String 

sebagai   parameter.   Metode  first  hanya   akan   mengembalikan   karakter   awal   dari 

string sementara last hanya akan mengembalikan karakter terakhir dari string itu.

c) Buatlah   sebuah   metode   dengan   nama   middle   yang   menggunakan   String   sebagai 

parameter.   Metode   ini   akan   mengembalikan   sebuah   substring   yang   mengandung 

semua anggota string tersebut kecuali karakter awal dan akhirnya. 

Petunjuk:   bacalah   dokumentasi   mengenai   metode  substring  dalam   kelas   String. 

Eksekusilah beberapa uji coba yang dapat membuat Anda mengerti bagaimana cara 

substring bekerja sebelum Anda menulis middle.  

Apa yang akan terjadi jika Anda memanggil middle dalam sebuah string yang hanya 

berisi dua huruf atau karakter? Satu karakter? Tanpa karakter? Hmmm ...

d) Pengertian umum untuk palindrome adalah sebuah kata yang apabila dibaca baik dari 

depan maupun dari belakang akan menghasilkan ejaan baca yang sama. Contohnya; 

“otto”, “palindromeemordnilap”. Cara alternatif untuk mendefinisikan kasus­kasus 

seperti ini adalah dengan menentukan sebuah metode khusus dan spesifik yang dapat 

digunakan untuk menguji kasus itu sendiri. Misalnya, mungkin kita semua sepakat 

berkata, “satu huruf yang tunggal termasuk palindrome, dan sebuah kata yang terdiri 

dari dua huruf termasuk palindrome jika kedua huruf adalah sama, dan semua kata 

yang lain adalah palindrome jika huruf pertama dan terakhir adalah sama sementara 

162
kata yang berada diantaranya termasuk palindrome.”

Buatlah sebuah metode dengan teknik rekursif, isPalindrome,  yang menggunakan 

sebuah String sebagai parameter dan mampu mengembalikan sebuah nilai boolean 

yang   dapat   dijadikan   penanda   apakah   kata   yang   Anda   masukkan   termasuk 

palindrome ataukah bukan.

e) Jika Anda sudah mempunyai metode pemeriksa palindrome yang dapat berfungsi 

dengan   baik,   carilah   cara   untuk   menyederhanakannya   dengan   cara   mengurangi 

jumlah persyaratan (conditions) yang harus diperiksa.

Petunjuk: mungkin akan berguna bagi Anda untuk menetapkan string kosong sebagai 

palindrome. 

f) Di atas selembar kertas, rancanglah sebuah strategi iteratif untuk memeriksa bentuk 

palindrome.   Ada   beberapa   pendekatan   yang   mungkin   bisa   dipakai   untuk 

menyelesaikan   ini,   jadi   buatlah   rencana   yang   matang   terlebih   dahulu   sebelum 

menulis kodenya. 

g) Implementasikan   strategi   yang   sudah   Anda   putuskan   ke   dalam   sebuah   metode 

dengan nama isPalindromeIter.

Latihan 7.6

Sebuah   kata   dapat   dikategorikan   sebagai   “abecedarian”   jika  huruf­huruf  dalam   kata 

tersebut muncul dalam urutan yang alfabetis (dari A ke Z). Sebagai contoh, 19 kata dari 

bahasa inggris berikut ini merupakan “abecedarian” yang semuanya terdiri dari 6 huruf.

abdest,   acknow,   acorsy,   adempt,   adipsy,   agnosy,   befist,   behint,   beknow, 

bijoux, biopsy, cestuy, chintz, deflux, dehors, dehort, deinos, diluvy, dimpsy

a) Deskripsikan sebuah algoritma untuk memeriksa apakah kata (String) yang dijadikan 

argumen dapat digolongkan sebagai “abecedarian”. Asumsikan bahwa semua kata 

hanya boleh berisi huruf kecil (lower­case). Algoritma Anda bisa bersifat rekursif 

163
ataupun iteratif.

b) Implementasikan algoritma Anda dalam metode yang disebut dengan isAbecedarian.

Latihan 7.7

dupledrome adalah sebuah kata  yang hanya boleh mengandung huruf ganda, seperti 

“llaammaa” atau “ssaabb”. Saya menduga bahwa tidak ada satu pun dupledrome dalam 

kata­kata   bahasa   inggris   yang   sering   digunakan.   Untuk   menguji   dugaan   itu,   saya 

menginginkan sebuah program yang dapat membaca   setiap satu kata dalam kamus lalu 

memeriksanya, kemudian memberi tahu apakah kata itu termasuk dalam dupledromity 

juga.

Tulislah   sebuah   metode   isDupledrome   yang   mengambil   sebuah   String   sebagai 

parameter.   Metode   ini   akan   mengembalikan   sebuah   nilai   bertipe   boolean   yang 

mengindikasikan apakah suatu kata memiliki sifat dupledromitas.

Latihan 7.8

Ketika nama­nama telah disimpan dalam komputer, terkadang nama­nama itu ditulis 

secara  langsung,   yakni   dengan   menempatkan   nama   depan   di   depan   nama   belakang, 

seperti “Allen Downey”, atau sebaliknya, dengan cara menempatkan nama belakang di 

depan  nama  depan  namun  di  antara  keduanya  diberi  tanda  koma,  seperti  “Downey, 

Allen”. Keadaan ini dapat menyulitkan kita untuk membandingkan nama­nama tersebut 

dan menempatkannya dalam urutan yang alfabetis.

Masalah yang masih ada kaitannya dengan hal semacam ini adalah bahwa beberapa 

individu   memiliki   nama   dengan   penempatan   huruf   kapital   yang   lucu,   seperti   teman 

saya,  Beth DeSombre, atau bahkan tanpa satu huruf kapital pun,     seperti  poet e.e. 

cummings.   Ketika   komputer­komputer   digunakan   untuk     membandingkan   karakter­

karakter,  mereka   cenderung  menempatkan  semua  huruf  kapital   dalam  susunan   yang 

salah.

164
Jika   Anda   mau,   lihatlah   buku   telepon   umum,   seperti   buku   direktori   kampus,   lalu 

cobalah pahami bagaimana teknik yang dipakai oleh buku itu untuk menuliskan nama­

nama yang ada di dalamnya. Perhatikan nama­nama yang mengandung beberapa kata 

sekaligus seperti Van Houten juga   nama­nama   dengan   huruf   kapital   yang   non­

standar,   seperti   desJardins.   Coba   lihat,   apakah   Anda   sanggup   untuk   merancang 

aturan/rambu­rambu pengurutannya. Jika Anda memiliki akses ke buku telepon negara­

negara di eropa, coba juga itu, dan telitilah kalau­kalau aturan yang digunakan juga 

berbeda dengan standar Amerika.

Hasil dari semua bentuk non­standar ini adalah bahwa terkadang tidaklah tepat untuk 

mengurutkan nama­nama tersebut menggunakan aturan String yang biasa. Satu solusi 

yang umum adalah dengan cara menyimpan dua versi sekaligus untuk tiap­tiap nama: 

pertama,   untuk   dicetak;   kedua,   format   internal   yang   digunakan   untuk   melakukan 

pengurutan.

Dalam   latihan   kali   ini,   Anda   diminta   menulis   sebuah   metode   yang   akan 

membandingkan dua nama dengan cara mengkonversikan keduanya ke dalam format 

standar. Kita akan bekerja dari bawah ke atas (bottom­up), menulis beberapa metode 

penolong untuk kemudian baru menulis metode compareName.

a) Buatlah sebuah program dengan nama Name.java. Dalam dokumentasi untuk String, 

bacalah   tentang   metode   find,   toLower,   dan   compareTo.   Buatlah   beberapa   kode 

sederhana untuk menguji masing­masing metode. Pastikan Anda dapat memahami 

bagaimana cara kerja ketiganya.

b) Buatlah metode hasComa yang menggunakan sebuah nama sebagai argumen serta 

mampu   mengembalikan   nilai   boolean   yang   mengindikasikan   apakah   nama   itu 

mengandung koma ataukah tidak. Jika ya, maka Anda sudah dapat menganggapnya 

sebagai format nama dengan nama belakang mendahului nama depan.

c) Buatlah  metode convertName  yang menggunakan sebuah nama  sebagai  argumen. 

165
Metode  ini  harus memeriksa  apakah nama  itu  mengandung  koma. Jika  ya, maka 

metode   ini   hanya   perlu   mengembalikan   string   nama   itu   saja.   Jika   tidak,   maka 

anggaplah   nama   tersebut   termasuk   dalam   format   nama­depan   duluan.   Selain   itu, 

metode ini  juga harus mengembalikan  sebuah string baru yang berisi nama yang 

telah dikonversikan ke format nama­belakang duluan.

d) Tulislah sebuah metode dengan nama compareName yang menggunakan dua buah 

nama   sebagai   argumen   dan   yang   mengembalikan   nilai   ­1   jika   nama   pertama 

mendahului  nama   kedua,  dalam urutan   abjad  alfabet,  0 jika  kedua  nama  bernilai 

sama secara alfabetis, dan 1 untuk keadaan lainnya. Metode yang Anda buat haruslah 

bersifat case­insensitive. Artinya, metode ini tidak akan memedulikan apakah huruf­

huruf penyusun nama­nama yang Anda berikan nantinya merupakan huruf kapital 

(upper case) atau huruf non­kapital (lower case).

Latihan 7.9

a) Cincin Decoder Kapten Crunch bekerja dengan cara mengambil setiap huruf dalam 

sebuah string, lalu menambahkan ke masing­masing huruf tersebut nilai 13. Sebagai 

contoh, ' a ' menjadi ' n ' dan ' b ' menjadi ' o '. Huruf­huruf tersebut kemudian akan 

“berputar” (wrap around) di bagian akhir, sehingga ' z ' akan menjadi ' m ' (z + 13 = 

m) .  

Buatlah sebuah metode yang mengambil sebuah String sebagai parameter dan yang 

mengembalikan   sebuah   String   baru   yang   mengandung   versi   enkode   dari   String 

tersebut. Anda harus mengasumsikan bahwa String yang akan dilewatkan sebagai 

parameter dapat berisi huruf kecil, huruf kapital, dan spasi. Tetapi tidak untuk tanda 

baca   yang   lain.   Huruf   kecil   harus   diubah   ke   dalam   huruf   kecil   lagi,   begitu   pula 

dengan huruf kapital. Bagaimana dengan spasi? Anda tidak perlu mengenkodenya. 

b) Generalisasilah metode ini sehingga dapat menambahkan nilai berapa pun yang Anda 

166
kehendaki   ketimbang   hanya   mampu   menambahkan   13   ke   dalam   setiap   huruf. 

Sekarang   Anda  pastinya  bisa  mengenkode  sesuatu  dengan  menjumlahkan   13 lalu 

mendekodenya dengan menambahkan ­13. Ayo coba!

167
Bab 8

Interesting Objects

8.1 Apanya yang menarik?

Meskipun String adalah objek, tapi mereka bukanlah objek yang benar­benar menarik. 

Maklum, String itu:

● Tidak bisa “diubah­ubah” alias immutable.

● Mereka tidak mempunyai variabel instan.

● Tidak mengharuskan kita untuk menggunakan perintah new ketika membuatnya.

Dalam bagian ini, kita akan menggunakan dua tipe objek baru yang merupakan bagian 

dari Java, yakni Point dan Rectangle. Mulai saat ini juga, saya ingin membuat Anda 

tahu  bahwa  points dan rectangle  bukanlah  objek­objek gambar yang akan  tampil di 

layar. Keduanya merupakan variabel yang mengandung data, sama halnya dengan int 

dan double. Layaknya variabel­variabel lain, keduanya digunakan secara internal untuk 

mengerjakan perhitungan­perhitungan.

Definisi­definisi mengenai kelas Point dan kelas Rectangle berada dalam paket java.awt, 

jadi kita harus mengimport keduanya. 

8.2 Paket­paket

Kelas­kelas  bawaan  Java  dibagi  ke   dalam  beberapa  paket,   termasuk  paket   java.lang 

yang mengandung hampir semua kelas yang telah kita gunakan sejauh ini. Begitu juga 

dengan  javax.swing yang berisi kelas­kelas untuk bekerja dengan jendela (window), 

tombol (button), grafis (graphic), dsb.

Untuk menggunakan sebuah paket, Anda harus mengimportnya, inilah yang menjadi 

168
alasan   kenapa   program   yang   ada   di   bagian   D.1   dimulai   dengan   sintaks   import 

javax.swing.*. Tanda ' * ' mengindikasikan bahwa kita ingin mengimport semua kelas 

yang berada dalam paket SWING. Jika Anda mau, Anda dapat menuliskan kelas­kelas 

yang   Anda   inginkan   secara   eksplisit,   tapi   sayangnya   tidak   terlalu   menguntungkan. 

Kelas­kelas   dalam   java.lang   sudah   diimport   secara   otomatis.   Hal   inilah   yang 

menyebabkan kenapa program­program yang kita tulis sejauh ini belum memerlukan 

sebuah perintah import.

Semua perintah import tampil di bagian awal dari sebuah program, di luar definisi milik 

kelas.

8.3 Objek Titik (Point)

Dalam   pengertian   yang   paling   sederhana,   sebuah   titik   (point)   adalah   dua   angka 

(koordinat)   yang   kita   anggap/sepakati   sebagai   sebuah   objek   tunggal.   Dalam   notasi 

matematika,   titik­titik   ini   (points)   sering   ditulis   dalam   tanda   kurung   (parentheses), 

dengan   satu   koma   yang   memisahkan   kedua   koordinat.   Contohnya,   (0,   0)   yang 

mengindikasikan titik asal/awal, dan (x, y) yang mengindikasikan titik di lokasi x satuan 

ke kanan dan y satuan ke atas dengan acuan titik asal (0, 0).

Dalam Java, sebuah titik direpresentasikan dengan sebuah objek yang disebut Point. 

Untuk membuat sebuah titik yang baru, Ada harus menggunakan perintah new:
Point blank;
blank = new Point (3, 4);

Baris pertama adalah contoh deklarasi variabel yang sudah umum alias konvensional: 

blank memiliki tipe data Point. Sementara baris kedua adalah sesuatu yang terlihat lucu; 

baris ini memanggil (invoke) perintah new, lalu menentukan tipe untuk objek yang baru 

itu,   kemudian   memberinya   argumen­argumen.   Mungkin   ini   bukanlah   sesuatu   yang 

mengejutkan Anda bahwa argumen­argumen yang berada dalam tanda kurung, (3, 4), 

169
adalah koordinat dari titik yang baru kita buat.

Hasil dari perintah new yang baru kita buat adalah sebuah acuan (reference) bagi titik 

yang baru. Saya akan menjelaskan masalah acuan ini secara lebih mendalam  dalam 

bagian   yang   lain.   Untuk   sekarang,   yang   lebih   penting   adalah   bahwa   variabel   blank 

berisi acuan kepada objek yang baru saja dibuat. Ada cara standar untuk menggambar 

diagram assignment seperti ini. Lihat gambar berikut:

Seperti biasa, nama variabel blank muncul di luar kotak sementara nilai­nilainya berada 

di   dalam.  Dalam   kasus   ini,   nilai   adalah   suatu   acuan,   seperti  yang   ditunjukkan   oleh 

sebuah dot dan anak panah dalam gambar. Anak panah itu menunjuk ke objek yang 

sedang kita acu. 

Kotak besar itu memperlihatkan objek yang baru saja kita buat beserta 2 nilai yang 

berada di dalamnya. x dan y adalah nama dari variabel­variabel instan.

Jika disatukan/digabungkan, maka semua komponen, variabel, nilai, dan objek dalam 

program   tersebut   akan   disebut   dengan   state.   Diagram­diagram   seperti   ini   yang 

menunjukkan state dari suatu program disebut juga dengan diagram­diagram state (state  

diagram). Ketika program berjalan (running), state­nya juga akan berubah. Jadi, Anda 

harus menganggap diagram state sebagai sebuah snapshot (tangkapan) dari suatu titik 

tertentu ketika eksekusi sedang terjadi.

8.4  Variabel Instan

Kumpulan data yang menyusun sebuah objek sering juga disebut sebagai komponen, 

rekaman (record), atau field. Dalam Java, mereka disebut sebagai variabel instan karena 

170
setiap objek, yang merupakan sebuah instan dari tipenya sendiri, memiliki salinan instan 

variabelnya sendiri. 

Hal ini persis seperti laci kecil yang ada di dalam sebuah mobil. Setiap mobil adalah 

instan dari tipe “mobil”, dan setiap mobil memiliki laci kecilnya masing­masing. Jika 

Anda menyuruh saya untuk mengambil sesuatu dari laci kecil dalam mobil Anda, maka 

Anda harus memberi tahu saya dahulu mobil mana yang menjadi kepunyaan Anda.

Mirip   dengan   analogi   di   atas,   jika   Anda   ingin   membaca   sebuah   nilai   dari   sebuah 

variabel instan, maka Anda harus menentukan terlebih dahulu objek mana yang akan 

mengambil nilai tersebut. Dalam Java, aksi ini akan dikerjakan dengan menggunakan 

perintah “notasi dot”.

Int x = blank.x;

Ekspresi blank.x mengandug arti “pergilah ke tempat yang diacu oleh objek blank, lalu 

ambillah nilai x”. Dalam kasus ini, kita meng­assign nilai tersebut ke dalam sebuah 

variabel lokal yakni x. Perhatikan bahwa tidak ada konflik yang terjadi antara variabel 

lokal   x   dengan   variabel   instan   x.   Fungsi   notasi   dot   dalam   kasus   ini   adalah   untuk 

mengidentifikasi dengan pasti variabel mana yang sedang atau akan Anda acu. 

Anda dapat menggunakan notasi dot untuk ekspresi bahasa Java apapun, jadi bentuk 

berikut ini dianggap legal.
System.out.println (blank.x + ", " + blank.y);
int distance = blank.x * blank.x + blank.y * blank.y;

Baris pertama mencetak 3, 4; sementara baris kedua menghasilkan nilai 25.

8.5 Objek Sebagai Parameter

Anda dapat melewatkan (pass) suatu objek sebagai parameter dengan cara yang sudah 

lazim digunakan. Contoh, 
public static void printPoint (Point p) {

171
  System.out.println ("(" + p.x + ", " + p.y + ")");
}

adalah   sebuah   metode   yang   menggunakan   sebuah   point   sebagai   argumen   lalu 

mencetaknya dalam format standar. Jika Anda memanggil metode printPoint (blank), 

Anda   akan   mencetak   (3,   4).   Sebenarnya,   Java   mempunyai   metode   bawaan   untuk 

mencetak   Points.   Jika   Anda   memanggil   System.out.println(blank)   Anda   akan 

mendapatkan 
java.awt.Point[x=3,y=4]

Ini merupakan format standar Java untuk mencetak mencetak suatu objek. Metode ini 

akan mencetak nama tipe, kemudian diikuti dengan isi dari objek tersebut, termasuk 

nama­nama dan nilai­nilai dari variabel instan. 

Untuk contoh tambahan, kita dapat menulis ulang metode distance dari bagian 5.2 agar 

ia menggunakan dua Point sebagai parameter ketimbang empat double.
public static double distance (Point p1, Point p2) {
  double dx = (double)(p2.x ­ p1.x);
  double dy = (double)(p2.y ­ p1.y);
  return Math.sqrt (dx*dx + dy*dy);
}

Typecast di atas sebenarnya tidaklah terlalu bermanfaat; saya hanya menambahkannya 

sebagai pengingat bahwa variabel instan dalam sebuah Point adalah integer.

8.6 Rectangle

Rectangle memiliki sifat yang hampir mirip dengan Point, kecuali variabel   instannya 

yang berjumlah empat. Keempat variabel itu antara lain; x, y, width, dan height. Selain 

itu, semuanya sama saja.
Rectangle box = new Rectangle (0, 0, 100, 200);

menghasilkan   sebuah   objek   Rectangle   baru   sekaligus   membuat   variabel   box   akan 

172
mengacu kepadanya. Gambar berikut ini akan menunjukkan efek dari assignment ini.

Jika Anda mencetak box, Anda akan mendapatkan
java.awt.Rectangle[x=0,y=0,width=100,height=200]

Lagi­lagi, ini merupakan hasil dari metode bawaan Java yang sudah tahu bagaimana 

caranya mencetak objek Rectangle.

8.7 Objek sebagai tipe kembalian (Return Type)

Anda dapat menulis metode yang menghasilkan nilai kembalian bertipe objek. Sebagai 

contoh,   findCenter   menggunakan   Rectangle   sebagai   argumen   lalu   mengembalikan 

sebuah   Point,   yang   merupakan   objek,   yang   berisi   koordinat­koordinat   pusat   dari 

Rectangle:
public static Point findCenter (Rectangle box) {
  int x = box.x + box.width/2;
  int y = box.y + box.height/2;
  return new Point (x, y);
}

Perhatikan bahwa Anda dapat menggunakan  new  untuk membuat sebuah objek baru, 

untuk kemudian langsung menggunakan hasilnya sebagai nilai kembalian.

8.8 Objek dapat diubah­ubah (Mutable)

Anda   dapat   mengubah­ubah   isi   dari   sebuah   objek   dengan   cara   membuat   sebuah 

assignment untuk salah satu variabel instan yang dimilikinya. Sebagai contoh, untuk 

“memindahkan”   sebuah   lingkaran   tanpa   mengubah   ukurannya,   Anda   dapat 

memodifikasi nilai x dan y:
box.x = box.x + 50;
box.y = box.y + 100;

Hasilnya dapat Anda lihat dalam gambar di bawah ini:

173
Kita dapat mengambil kode ini lalu mengenkapsulasinya dalam sebuah metode, lalu 

menggeneralisasinya   agar   dapat   digunakan   untuk   memindahkan   sebuah   lingkaran 

dengan nilai berapa pun yang kita mau.

public static void moveRect (Rectangle box, int dx, int dy) {
  box.x = box.x + dx;
  box.y = box.y + dy;
}

Variabel dx dan dy akan memberi tahu sejauh mana perpindahan yang telah terjadi pada 

lingkaran dalam setiap arah. Jika Anda memanggil metode ini, berarti Anda juga telah 

mengubah objek Rectangle yang dilewatkan sebagai sebuah argumen. 
Rectangle box = new Rectangle (0, 0, 100, 200);
moveRect (box, 50, 100);
System.out.println (box);
akan mencetak
java.awt.Rectangle[x=50,y=100,width=100,height=200].

Memodifikasi objek dengan cara melewatkan mereka sebagai argumen untuk sebuah 

metode memang dapat memberikan manfaat. Namun hal ini juga dapat menimbulkan 

kesulitan   ketika   kita   hendak   melakukan  debugging.   Kok   bisa?   Karena   terkadang 

tidaklah  terlalu jelas bagi kita untuk menentukan dengan cepat pemanggilan metode 

mana yang turut mengubah atau tidak mengubah masing­masing argumen yang mereka 

bawa.   Nanti,   saya   akan   membahas   beberapa   pro   dan   kontra   yang   berkaitan   dengan 

teknik pemrograman seperti ini.

174
Untuk saat ini, kita sudah dapat menikmati “kemewahan” yang tersedia dalam metode­

metode bawaan Java. Termasuk di dalamnya translate, yang  kemampuannya  sepadan 

dengan   metode   moveRect,   meskipun   sintaks   yang   digunakan   untuk   memanggilnya 

mungkin   agak   sedikit   berbeda.   Ketimbang   melewatkan   Rectangle   sebagai   sebuah 

argumen,   kita   memanggil   translate   dalam   objek   Rectangle   kemudian   melewatkan 

variabel dx dan dy saja sebagai argumen.
box.translate (50, 100);

Pengaruh yang dihasilkan akan sama dengan moveRect.

8.9 Aliasing

Penting untuk diingat, ketika Anda meng­assign suatu variabel dengan objek, ini berarti 

Anda   sedang   meng­assign   sebuah   acuan   (reference)   untuk   sebuah   objek.   Java 

mengizinkan Anda untuk membuat lebih dari satu variabel yang mengacu kepada satu 

objek yang sama. Untuk lebih jelasnya, perhatikan kode berikut ini:
Rectangle box1 = new Rectangle (0, 0, 100, 200);
Rectangle box2 = box1;
kode di atas akan menghasilkan diagram state seperti yang tampak di bawah ini:

Baik box1 maupun box2 mengacu kepada objek yang sama. Dengan kata lain, objek ini 

memiliki dua nama, yakni box1 dan box2. Ketika seorang individu memiliki dua buah 

nama, kita menyebutnya dengan istilah aliasing. Nah, begitu juga dengan objek.

Ketika   dua   variabel   berada   dalam   status  aliasing,   semua   perubahan   yang   dapat 

memengaruhi satu variabel akan turut memengaruhi variabel lainnya. Contohnya:

175
Baris pertama akan mencetak 100, yang merupakan lebar dari Rectangle yang diacu 

oleh box2. Sementara baris kedua digunakan untuk memanggil metode grow melalui 

box1.   Pernyataan   ini   akan   melebarkan/memperluas   Rectangle   sebanyak   50   pixel   ke 

segala   arah   (silahkan   membaca   dokumentasinya   agar   lebih   jelas).   Perubahan   yang 

terjadi ditunjukkan oleh gambar di bawah ini:

Melalui gambar ini, seharusnya Anda sudah dapat memahami, bahwa perubahan apapun 

yang terjadi pada box1 juga turut memengaruhi box2. Oleh karena itulah, nilai yang 

dicetak oleh pernyataan pada baris ketiga adalah 200, sebagai lebar dari hasil perluasan 

lingkaran.   (Sebagai   pertimbangan,   Java   juga   mengizinkan   nilai   negatif   sebagai 

koordinat Rectangle)

Dari kode sederhana di atas, Anda mungkin akan langsung menyimpulkan bahwa kode 

yang menerapkan prinsip aliasing justru dapat merepotkan kita sendiri.  Apalagi kalau 

sudah masuk ke dalam urusan debugging. Untuk itulah, sebaiknya Anda menghindari 

penggunaan teknik ini, atau gunakan ia dengan sehati­hati mungkin.

8.10 Null

Ketika Anda membuat sebuah variabel objek, Anda harus ingat bahwa Anda sedang 

mengacu kepada suatu objek. Jika Anda belum membuat variabel tersebut mengacu 

kepada suatu objek, maka nilai dari variabel itu akan sama dengan null. null adalah nilai 

yang khusus (juga sebuah keyword) dalam Java yang berarti “tidak ada objek”.

Pendeklarasian bentuk 
Point blank;

176
akan sama dengan inisialisasi beriktu ini:
Point blank = null;

Diagram state dari deklarasi di atas dapat dilihat melalui gambar di bawah ini:Nilai null 

direpresentasikan dengan sebuah dot tanpa anak panah. 

Jika   Anda   mecoba   untuk   menggunakan   objek   yang   berstatus   null,   entah   dengan 

mengaksesnya melalui variabel instan atau memanggilnya melalui sebuah metode, Anda 

akan   mendapatkan   sebuah   pesan   berbunyi,   “NullPointerException”.   Sistem   akan 

menampilkan sebuah pesan error lalu menghentikan program itu.
Point blank = null;
int x = blank.x;          // NullPointerException
blank.translate (50, 50); // NullPointerException
Di  sisi  lain, adalah legal dalam  Java untuk melewatkan  sebuah objek  berstatus null 

sebagai sebuah argumen atau menerima salah satunya sebagai sebuah nilai kembalian. 

Faktanya, memang demikianlah adanya. Para pengguna Java terbiasa mengaplikasikan 

konsep   ini   untuk   merepresentasikan   sebuah   himpunan   kosong   atau   untuk 

menginformasikan sebuah keadaan error.

8.11 Garbage Collection

Dalam bagian 8.9 kita telah berbicara mengenai apa yang akan terjadi jika lebih dari 

satu  variabel mengacu kepada satu objek yang sama. Lalu sekarang, apa yang akan 

terjadi  jika tidak ada satu pun variabel yang mengacu kepada suatu objek? Sebagai 

contoh:
Point blank = new Point (3, 4);
blank = null;

177
Baris pertama menghasilkan sebuah objek Point lalu membuat variabel blank mengacu 

kepadanya. Baris kedua mengubah blank sehingga ketimbang mengacu kepada suatu 

objek, ia justru lebih memilih untuk tidak mengacu kepada objek mana pun (objek null).

Jika tidak ada variabel yang mengacu kepada sebuah objek, maka tidak akan ada yang 

dapat   membaca   (read)   atau   menulisi   (write)   objek   ini   dengan   nilai   apa   pun,   atau 

memanggil sebuah metode melalui objek ini. Walaupun begitu, objek seperti  ini tetap 

eksis dalam memori. Sebenarnya, kita bisa saja menyimpan objek ini dalam memori, 

tapi   hal   ini   hanya   akan   membuang­buang   ruang   (space).   Oleh   karena   itulah,   selagi 

program Anda berjalan, sistem Java akan mencari objek­objek yang tidak terpakai ini 

secara berkala (periodically),  untuk kemudian mengaturnya. Proses inilah yang disebut 

dengan garbage collection. Walhasil, ruang memori yang tadinya dipakai oleh objek ini 

akan dapat digunakan kembali sebagai bagian dari objek yang baru.

Anda tidak perlu melakukan apapun untuk membuat proses garbage collection bekerja. 

Lagipula, umumnya Anda memang tidak akan memerhatikannya.

8.12 Objek dan Primitif

Ada dua jenis tipe data dalam Java, tipe data primitif dan tipe data objek. Tipe primitif, 

seperti int dan boolean diawali dengan huruf kecil; sementara tipe objek diawali dengan 

huruf kapital. Perbedaan ini sangat bermanfaat karena dapat mengingatkan kita kepada 

beberapa perbedaan antara keduanya.

● Ketika   Anda   mendeklarasikan   sebuah   tipe   data   primitif,   Anda   akan 

178
mendapatkan   ruang   penyimpanan   untuk   nilai   primitif.   Ketika   Anda 

mendeklarasikan   variabel   bertipe   data   objek,   Anda   akan   mendapatkan   ruang 

memori sebagai acuan (reference) kepada sebuah objek. Agar objek yang Anda 

buat memiliki ruang, Anda harus menggunakan perintah new.

● Jika Anda tidak menginisialisasi sebuah tipe primitif, Java telah memberi nilai 

bawaan (default) untuk setiap tipe data tersebut. Contohnya, 0 untuk tipe data int 

dan true untuk tipe boolean. Nilai bawaan untuk tipe­tipe objek adalah null yang 

berarti tidak ada objek.

● Variabel­variabel primitif diisolasi dengan baik oleh Java. Maksud pernyataan 

ini adalah bahwa Anda tidak dapat melakukan apapun melalui sebuah metode 

untuk mengubah variabel lain yang berada dalam metode lain. Variabel­variabel 

objek menjadi agak sulit dan membingungkan untuk digunakan karena mereka 

tidak   diisolasi   sebaik   variabel   bertipe   primitif.   Jika   Anda   melewatkan   suatu 

referensi   kepada   sebuah   objek   sebagai   sebuah   argumen,   maka   metode   yang 

Anda panggil dapat mengubah objek tersebut. Keadaan yang sama juga berlaku 

ketika Anda memanggil sebuah metode melalui suatu objek. Tetapi tentu saja, 

hal ini sebenarnya juga dapat bermanfaat untuk Anda, asalkan Anda hati­hati 

ketika menggunakannya.

Ada satu perbedaan lagi antara tipe data primitif dengan tipe data objek. Anda tidak 

dapat menambahkan tipe data primitif baru ke dalam bahasa Java (kecuali kalau Anda 

termasuk dalam anggota komite standardisasi Java milik Sun Microsystem), tapi Anda 

dapat   membuat   tipe   objek   yang   baru!   Caranya?   Kita   akan   melihatnya   di   bagian 

berikutnya.

179
8.13 Daftar Kata­Kata

Istilah Arti
Sebuah kumpulan dari kelas­kelas (classes). Kelas­kelas 

paket (package) yang dibawa (built­in) oleh Java dikelola dalam bentuk 

paket­paket.
Abstract   Window   Toolkit,   salah   satu   paket   terbesar 
AWT
dalam Java.
Sebuah   contoh   dari   suatu   kategori/golongan.   Kucing 

saya adalah suatu instan dari (baca: yang termasuk ke 
instan (instance)
dalam   golongan)   “keluarga   kucing”.   Semua   objek 

adalah instan dari beberapa kelas. 
Salah   satu   item­item   data   yang   membentuk   sebuah 

variabel instan objek. Setiap objek (instan) memiliki salinan variabel­

variabel instan untuk kelasnya masing­masing.
Sebuah   nilai   yang   mengindikasi   sebuah   objek.   Dalam 

acuan (reference) sebuah   diagram   state,   suatu   acuan   diwakili   dengan 

gambar anak panah.
Suatu kondisi dimana dua atau lebih variabel mengacu 
aliasing
ke objek yang sama.
Suatu   proses   untuk   mencari   objek­objek   yang   tidak 

garbage collection punya acuan untuk kemudian mengelola kembali ruang 

memori yang telah dipakainya.
Sebuah deskripsi lengkap dari semua variabel dan objek 

sekaligus   nilai­nilai   yang   dikandungnya   pada   suatu 


state
waktu   tertentu   selama   eksekusi   program   sedang 

berlangsung.

180
Sebuah   pencitraan   (snapshot)   atas   kondisi/keadaan 

diagram state yang terjadi pada sebuah program, ditunjukkan dengan 

gambar.

8.14 Latihan

Latihan 8.1

a) Untuk program di bawah ini, gambarlah sebuah diagram stack yang menunjukkan 

variabel­variabel lokal dan parameter­parameter dari main dan fred, lalu tunjukkan 

suatu objek yang diacu oleh variabel­variabel tersebut.

b) Apakah output yang dihasilkan oleh program berikut ini?
public static void main (String[] args)
{
int x = 5;
Point blank = new Point (1, 2);

System.out.println (fred (x, blank));
System.out.println (x);
System.out.println (blank.x);
System.out.println (blank.y);
}

public static int fred (int x, Point p)
{
x = x + 7;
return x + p.x + p.y;
}

181
Tujuan   utama   dari   latihan   ini   adalah   untuk   memastikan   bahwa   Anda   benar­benar 

memahami mekanisme untuk melewatkan objek sebagai parameter.

Latihan 8.2

a) Untuk   program   berikut   ini,   gambarlah   sebuah   diagram   stack   yang   menunjukkan 

keadaan   dari   program   beberapa   saat   sebelum   metode   distance   dikembalikan. 

Masukkan ke dalam gambar Anda itu semua variabel, parameter,   dan objek yang 

diacu oleh variabel­variabel tersebut.

b) Output apakah yang dihasilkan oleh program berikut ini?
public   static   double   distance   (Point   p1,   Point   p2)  
{
int dx = p1.x ­ p2.x;
int dy = p1.y ­ p2.y;
return Math.sqrt (dx*dx + dy*dy);
}

public static Point findCenter (Rectangle box) {
int x = box.x + box.width/2;
int y = box.y + box.height/2;
return new Point (x, y);
}

public static void main (String[] args) {
Point blank = new Point (5, 8);
Rectangle rect = new Rectangle (0, 2, 4, 4);
Point center = findCenter (rect);
double dist = distance (center, blank);
System.out.println (dist);
}

182
Latihan 8.3

Metode grow adalah bagian dari kelas Rectangle. Berikut ini merupakan dikumentasi 

mengenai grow (diambil dari situs Sun):
public void grow(int h, int v)

Grows the rectangle both horizontally and  
vertically.

This   method   modifies   the   rectangle   so   that   it   is   h  


units   larger   on   both   the   left   and   right   side,   and   v 
units larger at both the top and bottom.

The   new   rectangle   has   (x   ­   h,   y   ­   v)   as   its   top­


left   corner,   a   width   of   width   +   2h,   and   a   height   of  
height + 2v.

Jika nilai negatif

a) Output apakah yang dihasilkan oleh program berikut ini?

b) Gambarkan sebuah diagram state yang menunjukkan keadaan dari program sesaat 

sebelum main berakhir. Masukkan ke dalam gambar Anda tersebut semua variabel 

dan objek­objek yang diacunya.

c) Pada bagian akhir dari main, apakah p1 dan p2 termasuk aliasing? Mengapa atau 

mengapa tidak?
public static void printPoint (Point p) {
System.out.println ("(" + p.x + ", " + p.y +  
")");

183
}

public static Point findCenter (Rectangle box) {
int x = box.x + box.width/2;
int y = box.y + box.height/2;
return new Point (x, y);
}

public static void main (String[] args) {
Rectangle box1 = new Rectangle (2, 4, 7, 9);
Point p1 = findCenter (box1);
printPoint (p1);

box1.grow (1, 1);
Point p2 = findCenter (box1);
printPoint (p2);
}

Latihan 8.4

Mungkin   sekarang   Anda   sudah   benar­benar   bosan   dengan   metode   faktorial,   tapi 

sayangnya kita akan membuat satu versi lagi dari metode ini.

a) Buatlah sebuah program baru dengan nama Big.java lalu mulailah dengan menulis 

sebuah versi iteratif dari factorial.

b) Cetaklah sebuah tabel integer dari 0 s.d. 30 bersama faktorial mereka. Ketika sampai 

ke   nilai   15­an,   Anda   mungkin   akan   mendapati   bahwa   jawaban   Anda   sepertinya 

sudah tidak tepat lagi. Coba periksa! Mengapa begitu?

c) BigInteger   adalah   metode   bawaan   Java   yang   dapat   merepresentasikan   bilangan­

184
bilangan   integer.   Tidak   ada   batas­atas   kecuali   ukuran   memori   dan   kecepatan 

pemrosesan itu sendiri. Cetaklah dokumentasi untuk kelas BigInteger yang terdapat 

dalam paket java.math, lalu bacalah!

d) Ada   beberapa   cara   untuk   membuat   metode   BigInteger,   tapi   yang   saya 

rekomendasikan   adalah   dengan   menggunakan   valueOf.   Kode   berikut   ini   akan 

mengkonversikan sebuah integer ke bentuk metode BigInteger: 
int x = 17;
BigInteger big = BigInteger.valueOf (x);

Tulislah kode ini! Lalu cobalah beberapa kasus sederhana, seperti membuat sebuah 

BigInteger   kemudian   mencetaknya.   Perhatikan   bahwa   metode   println   sudah 

mengetahui   cara   untuk   mencetak   BigInteger!   Jangan   lupa   untuk   menambahkan 

import java.math.BigInteger di awal program Anda.

e) Sayangnya,   karena   BigInteger   bukanlah   tipe   primitif,   kita   jadi   tidak   dapat 

menggunakan   operator   matematika   biasa   untuknya.   Sebaliknya,   kita   akan 

menggunakan  metode   objek  seperti  add.  Untuk  menambah   dua  BigInteger,  Anda 

harus memanggil add melalui salah satu objek dan melewatkan objek lainnya sebagai 

argumen. Sebagai contoh:
BigInteger small = BigInteger.valueOf (17);
BigInteger big = BigInteger.valueOf (1700000000);
BigInteger total = small.add (big);
Cobalah beberapa metode lainnya, seperti multiply dan pow.

f) Konversikanlah   metode   factorial   sehingga   ia   dapat   melakukan   penghitungan 

menggunakan   BigInteger,   lalu  mengembalikan   BigInteger   sebagai   hasilnya.   Anda 

tidak   perlu   menghiraukan   parameternya   –   karena   tipe   data   yang   akan   digunakan 

tetaplah berupa integer.

185
g) Cobalah mencetak tabel lagi dengan metode factorial yang telah anda modifikasi. 

Benarkah hasilnya untuk angka di atas 30? Sampai seberapa besar (baca: angkanya) 

Anda  dapat  mempertahankan   ketepatan  ini?  Saya  telah   menghitung  faktorial   dari 

semua angka mulai dari 0 s.d. 999. Namun karena mesin saya terlalu lambat, saya 

jadi   perlu   waktu   yang   agak   lama.   Angka   terakhir,   999!,   mempunyai   2565   digit. 

Bagaimana dengan Anda?

Latihan 8.5

Banyak   algoritma­algoritma   enkripsi   sangat   bergantung   kepada   kemampuan   untuk 

menaikkan nilai integer yang besar ke bentuk integer berpangkat. Berikut ini adalah 

sebuah metode yang mengimplementasikan sebuah algoritma cepat untuk pemangkatan 

(exponentiation) integer.   
public static int pow (int x, int n) {
if (n==0) return 1;

// find x to the n/2 recursively
int t = pow (x, n/2);

// if n is even, the result is t squared
// if n is odd, the result is t squared times x

if (n%2 == 0) {
return t*t;
} else {
return t*t*x;
}
}
Masalah yang muncul dalam metode ini adalah bahwa ia hanya bekerja dengan benar 

186
jika hasil yang didapatkan kurang dari 2 miliar. Tulis­ulanglah metode ini sehingga 

hasilnya   merupakan   bentuk   BigInteger.   Meskipun   begitu,   parameter­paramater   yang 

digunakan haruslah tetap berupa integer.

Anda   diizinkan   menggunakan   metode  add   dan   multiply   milik   BigInteger,   tapi  tidak 

dengan metode pow, karena metode ini bisa jadi justru akan merusak 'keceriaan' Anda.

187
Bab 9

Membuat Objek Anda Sendiri

9.1 Definisi­definisi kelas dan tipe­tipe objek

Setiap kali Anda menulis sebuah definisi untuk kelas, Anda sebenarnya telah membuat 

sebuah tipe objek baru dengan nama yang sama dengan nama kelas Anda. Kembali ke 

bagian   1.5,  ketika kita  mendefinisikan  sebuah  kelas  bernama  Hello,  pada  saat  yang 

sama  (tanpa  perlu  Anda   sadari)  kita  juga  membuat  sebuah tipe  objek  dengan  nama 

Hello. Kita tidak membuat variabel apapun untuk tipe Hello, tidak juga menggunakan 

perintah new untuk membuat objek­objek Hello, tapi kita sudah berhasil melakukannya! 

Contoh   di   atas   agak   tidak   masuk   akal,   karena   kita   pada   dasarnya   memang   tidak 

bermaksud untuk membuat objek Hello. Lagipula, masih tidak jelas apa manfaatnya 

untuk kita kalau memang kita benar­benar telah membuatnya. Dalam bab ini,  kita 

akan melihat beberapa contoh definisi­definisi kelas yang mampu menunjukkan kepada 

kita tipe objek baru yang bermanfaat. 

Berikut ini adalah hal­hal penting yang harus diperhatikan dalam bab ini:

● Mendefinisikan   sebuah   kelas   baru   akan   menyebabkan   'lahirnya'   sebuah   tipe 

objek baru dengan nama yang sama.

● Suatu definisi untuk kelas dapat diasumsikan sebagai sebuah cetakan (template) 

untuk objek: definisi ini akan menentukan variabel instan mana yang dimiliki 

objek sekaligus metode­metode yang bisa beroperasi di atasnya.

● Setiap   objek   merupakan   milik   beberapa   objek   sekaligus;   oleh   karena   itulah, 

setiap objek juga merupakan instan dari beberapa kelas.

● Ketika Anda   menggunakan perintah  new   untuk  membuat  sebuah objek,  Java 

188
memanggil   sebuah   metode   khusus   yang   disebut   constructor   untuk 

menginisialisasi variabel­variabel instan.

● Semua metode yang beroperasi dalam sebuah tipe akan masuk dalam definisi 

kelas untuk tipe tersebut.

Berikut ini merupakan isu­isu sintaks mengenai definisi­definisi kelas:

● Nama kelas  (atau  tipe objek) selalu  dimulai  dengan huruf kapital  yang akan 

membedakannya dengan tipe­tipe primitif dan nama­nama variabel.

● Anda biasanya meletakkan satu definisi kelas dalam setiap file, dan nama file 

tersebut   haruslah   sama   dengan   nama   kelas   yang   Anda   buat   dengan   ekstensi 

.java.   Sebagai   contoh,   kelas   Time   didefinisikan   dalam   sebuah   file   bernama 

Timed.Java.

● Dalam program manapun, sebuah kelas dirancang untuk menjadi kelas startup 

(startup class). Kelas ini harus mengandung sebuah metode dengan nama main, 

yang   akan   menjadi   tempat   dimana   eksekusi   program   dimulai.   Kelas   lain 

diizinkan untuk memiliki metode main, tapi ia tidak akan dieksekusi.

Dengan   topik­topik   di   atas,   sekarang   kita   akan   melihat   sebuah   contoh   kelas   yang 

merupakan hasil buatan sendiri (user­defined type), yakni Time.

9.2 Time

Tujuan   utama   yang   mendasari   pembuatan   sebuah   tipe   objek   baru   adalah   untuk 

mengambil beberapa data yang saling berhubungan lalu mengenkaspsulasi mereka ke 

dalam   sebuah   objek   yang   dapat   dimanipulasi   (dilewatkan   sebagai   sebuah   argumen, 

beroperasi dengan suatu metode) sebagai sebuah unit tunggal. Sebelumnya kita semua 

sudah melihat dua tipe bawaan Java seperti ini, yaitu Point dan Rectangle.

Contoh lainnya, yang akan kita impelementasikan sendiri adalah Time. Tipe objek ini 

akan  kita gunakan untuk merekam waktu dalam satu hari. Beberapa informasi yang 

189
menyusun 'sebuah' waktu antara lain; jam, menit dan detik. Karena setiap objek waktu 

akan berisi data ini, kita memerlukan variabel instan untuk menyimpan data tersebut.

Langkah pertama adalah menentukan tipe data yang cocok untuk variabel yang akan 

kita gunakan. Untuk variabel hour dan minute, kita sebaiknya menggunakan integer. 

Untuk membuat proses ini lebih menyenangkan, mari kita simpan data second dalam 

variabel bertipe double agar nantinya dapat merekam detik­detik yang 'kecil'. 

Variabel instan akan dideklarasikan di awal definisi kelas, di luar semua definisi metode 

yang ada, seperti ini bentuknya:
class Time {
int hour, minute;
double second;
}

Lampiran kode di atas termasuk definisi kelas yang legal dalam Java. Diagram state 

untuk objek Time akan tampak sebagai berikut:

Setalah   mendeklarasikan   variabel   instan,   langkah   selanjutnya   adalah 

mendefinisikan/menentukan sebuah konstruktor untuk kelas yang baru. 

Fungsi  utama dari konstruktor  adalah untuk menginisialisasi variabel instan. Sintaks 

untuk   membuat   konstruktor   sama   dengan   yang   digunakan   untuk   membuat   metode­

metode biasa, tapi dengan tiga pengecualian:

● Nama konstruktor harus sama dengan nama kelas.

● Konstruktor tidak mempunyai tipe dan atau nilai pengembalian. 

● Keyword static tidak boleh digunakan.

Berikut ini adalah contoh kelas Time:
public Time () {

190
this.hour = 0;
this.minute = 0;
this.second = 0.0;
}

Perhatikan bahwa tidak ada apa­apa di antara keyword public dan Time (yang biasanya 

terdapat tipe data pengembalian diantaranya) . Inilah salah satu cara yang digunakan 

oleh kita (juga  compiler) untuk menyatakan bahwa lampiran kode di atas merupakan 

sebuah konstruktor.

Konstruktor   di   atas   tidak   menggunakan   satu   argumen   pun,   sebagaimana   yang 

diindikasikan oleh tanda kurung yang kosong; ( ). Setiap baris yang terkandung dalam 

konstruktor akan menginisialisasi sebuah variabel instan dengan nilai default yang kita 

buat sendiri (dalam kasus ini, kita menginisialisasi Time dengan waktu tepat di saat 

tengah malam, yaitu 0, 0, dan 0.0). keyword this merupakan kata tercadang khusus yang 

merupakan   nama   dari   objek   yang   sedang   kita   buat.   Anda   dapat   menggunakan   this 

seperti   anda   menggunakan   nama­nama   objek   lainnya.   Sebagai   contoh,   Anda   dapat 

membaca dan menulis variabel instan dengan this, lalu Anda juga dapat melewatkan this 

sebagai argumen kepada metode lainnya.

Tetapi Anda tidak perlu mendeklarasikan this atau menggunakan perintah new untuk 

membuatnya.   Kenyataannya,   Anda   bahkan   tidak   diizinkan   untuk   meng­assign­nya 

dengan sesuatu apapun. this merupakan produk sistem Java secara otomatis; yang harus 

Anda lakukan hanyalah menyimpan nilai­nilai ke dalam variabel instan miliknya. Itu 

saja!

Suatu bentuk error yang sering dilakukan oleh para pemrogram ketika menulis sebuah 

konstruktor   yaitu   ketika   mereka   meletakkan   perintah   return   di   akhir   kode   untuk 

konstruktor mereka. Hindari kesalahan seperti ini!

191
9.4 Konstruktor Lagi

Konstruktor­konstruktor  dalam  Java juga dapat  berstatus  overloading seperti metode 

pada  lazimnya.  Akibatnya,  Anda   dapat  menyediakan  beberapa  konstruktor  sekaligus 

dalam sebuah tipe objek dengan parameter­parameter yang berbeda. Java mengetahui 

konstruktor mana yang dipanggil dengan cara mencocokkan argumen yang digunakan 

oleh   perintah   new   dengan   parameter­parameter   yang   digunakan   oleh   konstruktor­

konstruktor.

Adalah sesuatu yang biasa dalam Java jika terdapat sebuah definisi kelas yang selain 

mengandung konstruktor yang tidak mempunyai satu argumen pun (seperti ditunjukkan 

di   atas),   ia   juga   mengandung   sebuah   konstruktor   yang   menggunakan   beberapa 

parameter sekaligus yang identik dengan variabel­variabel instan miliknya. Contohnya:
public Time (int hour, int minute, double second) {
this.hour = hour;
this.minute = minute;
this.second = second;
}

Nama dan tipe paramater yang digunakan akan sama persis dengan nama dan tipe dari 

variabel instan. Semua konstruktor bertugas untuk menyalin informasi dari parameter­

parameter itu ke dalam variabel­variabel instan.

Jika  Anda kembali dan melihat dokumentasi untuk Point dan Rectangle, Anda akan 

melihat   bahwa   kedua   kelas   tersebut   menyediakan   konstruktor   seperti   ini.   Status 

overloading   dalam   konstruktor   dapat   memberikan   fleksibilitas   bagi   Anda   untuk 

membuat sebuah objek terlebih dahulu lalu mengisi kekurangan­kekurangannya, atau 

Anda dapat mengumpulkan semua informasi sebelum membuat suatu objek yang benar­

benar sesuai dengan keinginan Anda.

192
Sejauh   ini,   apa   yang   sedang   kita   lakukan   mungkin   tidaklah   terlalu   menarik,   dan 

memang   demikianlah   adanya.   Menulis   konstruktor   adalah   pekerjaan   yang 

membosankan,   maklum   saja,   proses   ini   memang   dapat   dianalogikan   seperti     proses 

mekanis (mereparasi mesin). Sekali saja Anda telah mampu menulis dua konstruktor 

sekaligus,   Anda   akan   sadar   bahwa   tanpa   berkedip   pun   Anda   sebenarnya   tetap   bisa 

membuatnya. Cukup dengan memperhatikan daftar variabel­variabel instannya saja.

9.5 Membuat Sebuah Objek yang Baru

Meskipun konstruktor­konstruktor ini tampak seperti sebuah metode, Anda tetap  tidak 

akan   pernah   bisa   memanggilnya   secara   langsung.   Sebaliknya,   ketika   Anda 

menggunakan perintah new, sistem akan mengalokasikan ruang memori untuk objek 

yang baru lalu memanggil konstruktor Anda untuk menginisialisasi variabel­variabel 

instannya.

Program   berikut   ini   memperlihatkan   kepada   kita   dua   cara   untuk   membuat   dan 

menginisialisasi objek Time:

class Time {
int hour, minute;
double second;

public Time () {
this.hour = 0;
this.minute = 0;
this.second = 0.0;
}

public Time (int hour, int minute, double  
second)  {

193
this.hour = hour;
this.minute = minute;
this.second = second;
}

public static void main (String[] args) {

// one way to create and initialize a Time  
object
Time t1 = new Time ();

t1.hour = 11;
t1.minute = 8;
t1.second = 3.14159;
System.out.println (t1);

// another way to do the same thing
Time t2 = new Time (11, 8, 3.14159);
System.out.println (t2);
}
}

Sebagai latihan untuk Anda, cobalah pahami lalu tentukan bagaimana aliran eksekusi 

program ini.

Dalam   metode   main,   ketika   kali   pertama   kita   memanggil   perintah   new,   kita   tidak 

memberikan satu argumen pun, akibatnya, Java akan memanggil konstruktor pertama 

dari  kelas Time di atas. Beberapa baris berikutnya meng­assign nilai­nilai ke setiap 

variabel­variabel instan. 

194
Pada   kesempatan   kedua   ketika   kita   memanggil   perintah   new,   kita   memberikan 

argumen­argumen   yang   cocok   dengan   parameter­parameter   dari   konstruktor   kedua. 

Cara penginisialisasian variabel instan seperti ini mungkin lebih jelas (dan efisien), tapi 

juga dapat lebih menyulitkan untuk dibaca. Hal ini bisa jadi disebabkan karena tidak 

jelasnya nilai­nilai apa yang akan di­assign ke variabel instan yang mana.

9.6 Mencetak Sebuah Objek

Output dari program di atas adalah: 
Time@80cc7c0
Time@80cc807

Ketika Java mencetak nilai dari sebuah tipe objek buatan pengguna (user­defined object  

type), yang akan dicetaknya adalah nama dari tipe objek tersebut beserta suatu kode 

heksadesimal (basis 16) yang unik untuk setiap objek. Kode ini memang tidak artinya; 

kenyataannya, hasil ini bisa bervariasi diantara satu mesin dengan mesin lainnya atau 

bahkan diantara waktu pemrosesan yang satu dengan waktu pemrosesan yang lainnya. 

Meskipun begitu, kita masih tetap dapat memanfaatkannya untuk debugging, misalnya 

untuk   kasus   dimana   kita   tetap   ingin     mengawasi   keberadaan   suatu   objek   secara 

individual. 

Untuk mencetak objek yang menghasilkan pesan yang lebih manusiawi (baca: dapat 

dimengerti)   bagi   pengguna,   Anda   biasanya   ingin   menulis   sebuah   metode   seperti 

printTime:

public static void printTime (Time t) {
System.out.println (t.hour + ":" + t.minute 

1. ":" + t.second);

195
}

Bandingkanlah metode ini dengan metode printTime yang ada di bagian 3.10.

Output   metode   ini,   jika   kita   melewatkan   t1   atau   t2   sebagai   argumen   adalah 

11:8:3.14159. Meskipun bentuk seperti ini kita anggap sebagai sebuah penunjuk waktu, 

tapi ia belumlah dapat dikategorikan ke dalam bentuk standar yang sudah kita kenal. 

Sebagai contoh, jika angka menit atau detik kurang dari 10, maka kita mengharapkan 

adanya awalan berupa angka 0 yang berfungsi sebagai penjaga­tempat (place­keeper). 

Selain   itu,  kita  mungkin  ingin  membuang  angka­angka yang  termasuk  dalam angka 

desimal/pecahan dari detik. Dengan kata lain, kita ingin sesuatu yang tampak seperti 

11:08:03.

Dalam lingkungan bahasa­bahasa pemrograman lainnya, biasanya sudah terdapat cara 

sederhana untuk mengendalikan format output yang berupa angka­angka. Namun dalam 

Java, tidak ada cara seperti itu.

Java   menyediakan  tools  yang   sangat   bagus   untuk   mencetak   sesuatu   yang   sudah 

memiliki   bentuk   standar   (formatted   things)   seperti   waktu   atau   tanggal,   juga   untuk 

menginterpretasikan   input­input   terformat   (formatted   input).   Sayangnya,   tools   ini 

tidaklah terlalu mudah untuk digunakan, jadi saya tidak akan membahasnya di dalam 

buku ini. Tetapi jika Anda benar­benar ingin menggunakannya, silahkan melihat­lihat 

dokumentasi mengenai kelas Date dalam paket java.util.

9.7 Operasi Pada Objek

Meskipun kita tidak dapat mencetak waktu dalam format yang optimal, kita masih dapat 

menulis   sebuah   metode   yang   bisa   memanipulasi   objek   Time.   Dalam   bagian­bagian 

berikutnya,   saya   akan   menunjukkan   beberapa   antarmuka   (interface)   yang   mungkin 

dapat   digunakan   untuk   metode­metode   yang   beroperasi   melalui   objek­objek.   Untuk 

196
beberapa operasi, Anda mempunyai beberapa pilihan antarmuka yang bisa digunakan, 

jadi Anda harus mempertimbangkan sendiri pro dan kontra untuk setiap pilihan:

● pure function: menggunakan objek­objek/primitif sebagai argumen tetapi tidak 

memodifikasi objek.  Nilai  kembalian  berupa  primitif   atau  sebuah  objek  baru 

yang dibuat di dalam metode tersebut.

● Modifier:   menggunakan   objek   sebagai   argumen   dan   memodifikasi   beberapa 

atau semua bagian di dalamnya. Seringkali mengembalikan void.

● Fill­in­method: salah satu argumennya adalah sebuah objek 'kosong' yang diisi 

oleh metode. Secara teknis, sebenarnya ini merupakan salah satu bentuk dari 

modifier. 

9.8 Fungsi­fungsi murni

Sebuah metode dianggap sebagai fungsi murni jika hasilnya hanya bergantung kepada 

argumen­argumen, dan pada saat yang bersamaan dia tidak memberikan efek samping; 

seperti memodifikasi sebuah argumen atau mencetak sesuatu. Satu­satunya hasil dari 

melakukan   pemanggilan   terhadap   sebuah   fungsi   murni   adalah   nilai   kembalian   itu 

sendiri.  

Salah   satu   contohnya   adalah   after,   yang   membandingkan   dua   buah   waktu,   lalu 

mengembalikan   nilai   bertipe   boolean   yang   mengindikasikan   apakah   operan   pertama 

berada di belakang operan kedua:
public   static   boolean   after   (Time   time1,   Time  
time2) {
if (time1.hour > time2.hour) return true;
if (time1.hour < time2.hour) return false;

if (time1.minute > time2.minute) return true;

197
if (time1.minute < time2.minute) return false;

if (time1.second > time2.second) return true;
return false;
}

Apa yang akan dihasilkan oleh metode ini jika kedua waktu adalah sama? Apakah hasil 

tersebut merupakan hasil yang tepat dan sesuai dengan apa yang kita harapkan dari 

metode   ini?   Jika   Anda   menulis   dokumentasi   untuk   metode   ini,   maukah   Anda 

menyebutkan kasus tersebut secara spesifik?

Contoh   kedua   adalah   addTime,   yang   mengkalkulasi   jumlah   dari   dua   buah   waktu. 

Sebagai contoh, jika sekarang waktu menunjukkan 9:14:30, dan pemanggang roti Anda 

membutuhkan   3   jam   lebih   35   menit,   Anda   dapat   menggunakan   addTime   untuk 

menentukan kapan roti Anda akan selesai dipanggang:
public static Time addTime (Time t1, Time t2) {
Time sum = new Time ();
sum.hour = t1.hour + t2.hour;
sum.minute = t1.minute + t2.minute;
sum.second = t1.second + t2.second;
return sum;
}

Meskipun   metode   ini   mengembalikan   nilai   yang   berupa   objek   waktu,   ia   bukanlah 

sebuah konstruktor. Anda harus kembali lagi untuk membandingkan sintaks dari metode 

seperti ini dengan sintaks sebuah konstruktor. Mengapa? Karena kita seringkali menjadi 

terlalu mudah untuk kebingungan.

Berikut ini adalah sebuah contoh mengenai bagaimana cara menggunakan metode ini. 

198
Jika   currentTime   berisikan   waktu   saat   ini,   sementara   breadTime   mengandung   total 

waktu   yang   dibutuhkan   oleh   pembuat­roti   Anda   untuk   membuat   roti   yang   Anda 

inginkan,   maka   Anda   harus   menggunakan   addTime   untuk   menentukan   kapan   roti 

tersebut akan selesai dibuat. 
Time currentTime = new Time (9, 14, 30.0);
Time breadTime = new Time (3, 35, 0.0);
Time doneTime = addTime (currentTime, breadTime);
printTime (doneTime);

Output dari program ini adalah 12:49:30.0, yang berarti sesuai dengan apa yang kita 

inginkan. Namun di sisi lain, ada kasus­kasus tertentu di mana hasil yang dikeluarkan 

ternyata tidak sesuai. Bisakah Anda menunjukkan salah satunya?

Masalahnya adalah bahwa metode ini ternyata tetap menjumlahkan dan menampilkan 

nilai   detik   dan   menit   meskipun   nilai   keduanya   telah   melampaui   angka   60.   Untuk 

mengatasinya, kita harus berupaya agar jumlah detik setelah angka 60 bisa ditambahkan 

kepada   nilai   menit   (+1   menit).  Begitu   juga   dengan   jumlah   menit,   setiap   menembus 

angka 60, nilai menit tersebut akan ditambahkan ke dalam jam (+1 jam).

Kode berikut ini merupakan perbaikan dari kode di atas:
public static Time addTime (Time t1, Time t2) {
Time sum = new Time ();
sum.hour = t1.hour + t2.hour;
sum.minute = t1.minute + t2.minute;
sum.second = t1.second + t2.second;

if (sum.second >= 60.0) {
sum.second ­= 60.0;
sum.minute += 1;

199
}

if (sum.minute >= 60) {
sum.minute ­= 60;
sum.hour += 1;
}
return sum;
}

Meskipun kode di atas sudah benar, tapi ia akan menjadi semakin kompleks. Nanti, saya 

akan   menunjukkan   sebuah   pendekatan   alternatif   yang   lebih   singkat   untuk 

menyelesaikan masalah­masalah seperti ini.

Kode di atas menampilkan dua operator yang belum kita lihat sebelumnya, yakni ' += ' 

dan ' ­ = '. Kedua operator ini memberikan cara yang jelas untuk menaikkan (increment) 

atau menurunkan (decrement) nilai variabel­variabel. Keduanya hampir sama dengan ' 

++ ' dan ' ­­ ' kecuali bahwa:

1. Keduanya dapat digunakan untuk operasi variabel bertipe double, selain untuk 

integer.

2. Derajat kenaikan atau penurunan tidak harus 1. Pernyataan

sum.second ­= 60.0; sama dengan sum.second = sum.second – 60;

9.9 Modifier

Untuk mencontohkan suatu modifier, perhatikanlah metode increment berikut! Metode 

ini   menambahkan   nilai   detik   ke   dalam   objek   Time.   Lagi­lagi,   bentuk   mentah   dari 

metode ini akan tampak sebagai berikut:
public   static   void   increment   (Time   time,   double  
secs) {

200
time.second += secs;

if (time.second >= 60.0) {
time.second ­= 60.0;
time.minute += 1;
}

if (time.minute >= 60) {
time.minute ­= 60;
time.hour += 1;
}
}

Baris pertama mengerjakan operasi dasar;  remainder  (nilai pengingat) bekerja dengan 

cara yang sama seperti pada kasus yang sudah kita lihat sebelumnya.

Sudah benarkah metode ini? Apa yang terjadi jika argumen secs lebih besar daripada 

60? Dalam kasus ini, tidak cukup mengurangi nilai 60 sebanyak satu kali saja. Kita 

harus   terus   mengurangi   60   sampai  second  bernilai   kurang   dari   60.   kita   dapat 

melakukannya dengan hanya mengganti perintah if dengan while:
public   static   void   increment   (Time   time,   double  
secs) {
time.second += secs;

while (time.second >= 60.0) {
time.second ­= 60.0;
time.minute += 1;
}

201
while (time.minute >= 60) {
time.minute ­= 60;
time.hour += 1;
}
}

Solusi ini sudah tepat, tapi tampaknya tidak terlalu efisien. Bisakah Anda memberikan 

sebuah solusi yang tidak membutuhkan bentuk­bentuk perulangan (iteration)?

9.10 Fill­in Methods

Umumnya Anda akan jarang sekali menemui metode seperti addTime ditulis dengan 

antar   muka   yang   berbeda   (dari   segi   argumen   dan   nilai   kembaliannya).   Ketimbang 

membuat   sebuah   objek   baru   setiap   kali   addTime   dipanggil,   kita   bisa   menyuruh   si 

pemanggil (the caller) untuk menyediakan objek 'kosong' sebagai tempat bagi addTime 

untuk menyimpan hasilnya. Bandingkan kode berikut ini dengan kode sebelumnya:
public   static   void   addTimeFill   (Time   t1,   Time   t2,  
Time sum) {
sum.hour = t1.hour + t2.hour;
sum.minute = t1.minute + t2.minute;
sum.second = t1.second + t2.second;

if (sum.second >= 60.0) {
sum.second ­= 60.0;
sum.minute += 1;
}

if (sum.minute >= 60) {
sum.minute ­= 60;

202
sum.hour += 1;
}
}

Satu   keuntungan   dari   pendekatan   seperti   ini   adalah   bahwa   si   pemanggil   memiliki 

kesempatan/opsi   untuk   menggunakan   objek   yang   sama   secara   berulang­ulang   untuk 

melakukan operasi penjumlahan yang beruntun. Pendekatan ini mungkin sedikit lebih 

efisien,   meskipun   dapat   membingungkan   juga   ketika  malah  menyebabkan   error.   Di 

dalam dunia pemrograman, banyak yang lebih memilih untuk menghabiskan waktunya 

demi   sebuah   program   dengan  run   time  yang   pendek   (baca:   cepat)   ketimbang 

menghabiskan waktunya untuk men­debug kode program yang panjang.

9.11 Mana yang terbaik?

Semua yang dapat dilakukan dengan menggunakan modifier dan fill­in­method   dapat 

juga dikerjakan menggunakan fungsi murni. Dalam kenyataannya, ada sebuah bahasa 

pemrograman,   yang   disebut   sebagai   bahasa   pemrograman   fungsional,   yang   hanya 

mengizinkan   penggunaan   fungsi­fungsi   murni   saja.   Beberapa   pemrogram   percaya 

bahwa program yang dibangun dengan menggunakan fungsi murni akan lebih cepat 

untuk dikembangkan dan lebih kecil risiko error­nya ketimbang program yang dibangun 

dengan menggunakan modifier. Meskipun begitu, tetap ada saat­saat dimana modifier 

lebih sesuai untuk diterapkan, dan saat­saat dimana program fungsional menjadi tidak 

efisien.

Secara   umum,   saya   merekomendasikan   Anda   untuk   menulis   fungsi   murni   saja   di 

manapun Anda berkesempatan untuk menulisnya, lalu berganti ke modifier ketika Anda 

melihat keuntungan besar di dalamnya. Pendekatan seperti inilah yang mungkin disebut 

dengan teknik pemrograman fungsional.

203
9.12 Pengembangan secara bertahap vs perencanaan

Dalam   bab   ini   saya   telah   menunjukkan   sebuah   pendekatan   untuk   mengembangkan 

sebuah   program   yang   saya   sendiri   menyebutnya   sebagai  rapid   prototyping   with 

iterative   improvement.   Dalam   tiap   kasusnya,   saya   selalu   menuliskan   satu   bentuk 

mentah   (atau   prototipe)   yang   berfungsi   untuk   mengerjakan   kalkulasi   dasar,   lalu 

mengujinya   dalam   beberapa   kasus,   untuk   kemudian   langsung   memperbaiki 

kesalahan/kelemahan yang terdapat di dalamnya.

Walaupun efektif, pendekatan ini juga dapat menyebabkan lahirnya kode yang tidak 

perlu sekaligus membingungkan – karena digunakan untuk menyelesaikan banyak kasus 

khusus ­ juga tidak dapat dipercaya (unreliable) – karena Anda sendiri masih belum 

bisa yakin apakah Anda telah menemukan semua error yang ada. 

Alternatif yang ada diantaranya adalah high­level programming (pemrograman tingkat­

tinggi). Dalam teknik ini, Anda harus benar­benar mengandalkan  deep­thinking  Anda 

terhadap   suatu   kasus.   Untuk   kasus   Time   di   atas,   deep­thinking   ini   berarti   Anda 

menganggap bahwa Time merupakan angka tiga­digit dalam basis 60! Artinya, second 

adalah “kolom satuan”, minute adalah “kolom 60­an”, lalu hour adalah “kolom 3600­

an”.

Ketika kita menulis addTime dan increment, sebenarnya kita juga sedang mengerjakan 

penjumlahan dalam basis 60. Inilah yang menjadi penyebab sehingga kita memerlukan 

“carry” dari satu kolom ke kolom berikutnya.

Dus, pendekatan alternatif yang akan kita gunakan untuk menyelesaikan semua masalah 

ini adalah dengan cara mengkonversikan Time ke bentuk double. Hal ini kita lakukan 

karena sebuah fakta bahwa komputer memang sudah “mengerti” cara mengoperasikan 

aritmetika   untuk   bentuk   double.   Berikut   ini   adalah   sebuah   metode   yang 

mengkonversikan objek Time ke bentuk double:

204
public static double convertToSeconds (Time t) {
int minutes = t.hour * 60 + t.minute;
double seconds = minutes * 60 + t.second;
return seconds;
}

Sekarang, apa yang perlu kita kerjakan adalah menemukan cara untuk mengubah bentuk 

double   ke   bentuk   Time.   Sebenarnya   kita   bisa   saja   menulis   sebuah   metode   untuk 

melakukannya, tapi akan lebih masuk akal jika kita menuliskannya sebagai konstruktor 

ketiga:   
public Time (double secs) {
this.hour = (int) (secs / 3600.0);
secs ­= this.hour * 3600.0;
this.minute = (int) (secs / 60.0);
secs ­= this.minute * 60;
this.second = secs;
}

Konstruktor ini memang tampak sedikit berbeda dengan yang lainnya, mungkin karena 

ia melibatkan sejumlah kalkulasi dan assignment terhadap variabel­variabel instan.

Anda   mungkin  harus  berpikir  lebih dalam  lagi untuk  meyakinkan  diri  Anda  sendiri 

bahwa teknik yang saya gunakan untuk mengubah satu basis ke dalam basis lainnya 

adalah benar. Jika Anda sudah yakin, maka kita dapat menggunakan metode berikut 

untuk menulis ulang metode addTime:
public static Time addTime (Time t1, Time t2) {
double seconds = convertToSeconds (t1) + 
convertToSeconds (t2);
return new Time (seconds);

205
}

Kode di atas lebih singkat daripada versi aslinya. Selain itu, saya juga lebih mudah 

untuk menunjukkan kepada Anda bahwa metode ini memang benar (anggaplah, seperti 

biasa,  bahwa metode­metode yang dipanggilnya  juga benar).  Untuk latihan, cobalah 

menulis ulang increment dengan cara yang sama.

9.13 Generalisasi

Dalam beberapa kasus, mengubah satu bentuk dari basis 60 ke basis 10 atau sebaliknya 

adalah lebih sulit daripada berpacu dengan waktu itu sendiri. Konversi suatu basis itu 

lebih abstrak; bahkan intuisi kita terhadap “berpacu dengan waktu” itu sendiri lebih 

baik.

Namun   jika   kita   mempunyai   pemahaman   mendalam   untuk   memperlakukan   waktu 

sebagai   angka   berbasis   60,   lalu   membuat   “investasi”   dengan   cara   menulis   metode 

pengubah/konverter   (convertToSecond   dan   konstruktor   ketiga),   maka   kita   akan 

mendapatkan program yang lebih pendek, lebih enak untuk dibaca dan di­debug, juga 

lebih andal.

Kita juga akan lebih mudah untuk menambahkan beberapa fitur di kesempatan lainnya. 

Misalnya, Anda membayangkan untuk mengurangi dua Time lalu mencari durasi/tempo 

antara   keduanya.   Pendekatan   yang   naif   adalah   dengan   mengimplementasikan   suatu 

pengurangan   yang   lengkap   dengan   teknik   “peminjaman”.   Menggunakan   metode 

pengubah akan lebih mudah.

Ironisnya,   terkadang   tidak   menganggap   ringan   suatu   masalah   justru   akan   membuat 

masalah   itu   menjadi   'ringan'   dengan   sendirinya.   (semakin   kecil   kasus­kasus   khusus, 

maka akan semakin kecil pula kesempatan untuk membuat error)

206
9.14 Algoritma

Ketika  Anda  menulis sebuah solusi umum  untuk suatu masalah, sebagai  lawan  dari 

solusi spesifik untuk suatu masalah khusus, sebenarnya Anda sudah menulis apa yang 

disebut   dengan  algoritma.   Saya   menyebut   kata   ini   dalam   bab   1,   tapi   tidak 

mendefinisikannya secara mendalam. Tidaklah mudah untuk mendefinisikannya, jadi 

saya akan mencoba beberapa pendekatan.

Pertama,   pikirkanlah   beberapa   hal   yang   tidak   termasuk   algoritma.   Sebagai   contoh, 

ketika   Anda   telah   belajar   untuk   mengalikan   beberapa   angka   berdigit   tunggal,  Anda 

mungkin ingat akan tabel perkalian. Sebagai dampaknya, Anda mengingat 100 solusi 

khusus, jadi pengetahuan Anda tersebut belumlah termasuk ke dalam apa yang disebut 

dengan algoritma.

Tapi jika Anda adalah seorang “pemalas”, Anda mungkin akan mencuranginya dengan 

mengambil   beberapa   trik   di   dalamnya.   Sebagai   contoh,   untuk   menemukan   hasil 

perkalian n dengan 9, Anda dapat menulis n – 1 sebagai digit pertama  dan 10 – n 

sebagai digit kedua. Trik ini merupakan solusi umum untuk mengalikan sebua angka 

berdigit tunggal dengan 9. Nah, ini baru algoritma!

Dengan   cara   yang   sama,   teknik­teknik   yang   sudah   Anda   pelajari   ketika   melakukan 

penjumlahan dengan “penyimpanan”, pengurangan dengan peminjaman, dan pembagian 

yang panjang juga termasuk algoritma. Salah satu sifat algoritma adalah bahwa ia sama 

sekali tidak membutuhkan kecerdasan di dalamnya.  Ia   merupakan   proses   mekanik 

dimana setiap proses, dari awal hingga akhir, dibuat berdasarkan sekumpulan aturan 

tertentu. 

Menurut pendapat saya, adalah memalukan bagi seorang manusia untuk menghabiskan 

begitu   banyak   waktu   di   sekolah   hanya   untuk   mengeksekusi   algoritma   yang,   secara 

harfiah, tidak melibatkan kecerdasan sama sekali.

207
Justru,   proses   ketika   merancang   algoritma   itu   sendirilah   yang   menarik,   menantang 

intelektual, sekaligus sebagai pusat dari apa yang kita sebut dengan programming.

Beberapa hal yang dilakukan oleh manusia secara alamiah, tanpa kesulitan atau pun 

kesadaran pikiran, adalah hal yang paling sulit untuk diterjemahkan dengan algoritma. 

Memahami bahasa natural adalah salah satu contoh yang bagus. Kita semua memang 

melakukannya,   tapi   sampai   sejauh   ini,   belum   ada   satu   orang   pun   yang   mampu 

menjelaskan bagaimana cara kita melakukannya, setidaknya dalam bentuk algoritma.

Nantinya, Anda akan berkesempatan untuk meracang suatu algoritma sederhana untuk 

beberapa masalah.

9.15 Daftar Kata­Kata

Istilah Arti
Sebelumya, saya telah mendefinisikan kelas sebagai sebuah 

koleksi/kumpulan dari metode­metode yang saling berkaitan. 

Class (kelas) Dalam bab ini kita mempelajari bahwa sebuah definisi untuk 

kelas juga merupakan sebuah template untuk tipe baru suatu 

objek.   
Salah satu anggota kelas. Setiap objek merupakan instan dari 
Instance (instan)
suatu kelas.
Constructor  Metode khusus yang menginisialisasi variabel­variabel instan 

(konstruktor) dari objek yang baru akan dibuat.

Sebuah koleksi dari satu atau lebih definisi kelas (satu kelas 
Project (proyek)
per satu file) yang membentuk sebuah program.
Startup class Kelas yang mengandung metode main, tempat di mana 

208
Istilah Arti
eksekusi program dimulai.
Sebuah metode yang hasilnya bergantung kepada paramater­

Function (fungsi) parameternya sendiri, dan tidak memberikan dampak apa pun 

selain nilai yang dikembalikannya.
Suatu metode yang mengubah satu atau lebih objek yang 
modifier
diterimanya sebagai parameter, biasanya mengembalikan void.
Suatu jenis metode yang mengambil sebuah objek “kosong” 

sebagai sebuah parameter lalu mengisi variabel­variabel 
Fill­in­method
instannya ketimbang membuat suatu nilai kembalian. Metode 

jenis ini biasanya bukanlah pilihan terbaik untuk digunakan.
Suatu himpunan aturan yang digunakan untuk menyelesaikan 
algoritma
suatu masalah dengan proses mekanis.

9.16 Latihan

Latihan 9.1

Dalam   permainan   Scrabble1,   setiap   petak   mengandung   sebuah   huruf,   yang   bisa 

digunakan untuk mengeja sebuah kata, lalu sebuah nilai (score), yang digunakan untuk 

menentukan nilai dari setiap kata. 

a) Buatlah sebuah definisi kelas dengan nama Tile yang merepresetasikan petak­petak 

Scrabble. Variabel­variabel insatannya haruslah sebuah karakter dengan nama letter 

dan sebuah integer dengan nama value.

b) Tulislah sebuah konstruktor yang menggunakan parameter­parameter dengan nama 

letter dan value lalu inisialisasilah variabel­variabel instannya. 

c) Tulislah sebuah metode dengan nama printTile yang menggunakan satu objek Tile 

209
sebagai parameter lalu mencetak variabel­variabel instannya dalam format yang enak 

dan mudah untuk dibaca.

d) Tulislah sebuah metode dengan nama testFile yang dapat menghasilkan satu objek 

Tile dengan huruf Z dan nilai 10, lalu gunakan printTile untuk mencetak keadaan 

(the state) objek tersebut.

Inti dari latihan ini adalah untuk melatih Anda memahami sisi­sisi mekanis pembuatan 

definisi kelas yang baru sekaligus membuat kode yang digunakan untuk mengujinya.

Latihan 9.2

Tulislah sebuah definisi kelas untuk Date, sebuah tipe objek yang berisi tiga integer, 

yakni year, month, dan day. Kelas ini harus menyediakan dua konstruktor. Konstruktor 

Pertama   tidak   boleh   menggunakan   parameter   apapun.   Sedangkan   konstruktor   kedua 

harus menggunakan year, month, dan day sebagai parameter, kemudian menggunakan 

ketiganya untuk menginisialisasi variabel­variabel instan.

Tambahkan kode ke dalam main yang membuat sebuah objek Date baru dengan nama 

birthday.   Objek   yang   baru   tersebut   harus   berisi   tanggal   lahir   Anda.   Anda   dapat 

menggunakan kedua konstruktor tersebut.

Latihan 9.3

Sebuah   bilangan   rasional   (rational   number)   adalah   suatu   bilangan   yang   dapat 

ditampilkan sebagai suatu rasio (perbadingan) dari dua integer. Contohnya; 2/3 adalah 

bilangan rasional, dan Anda pun dapat menganggap 7 sebagai bilangan rasional dengan 

implisit   1   dalam   denominatornya.   Untuk   tugas   kali   ini,   Ada   akan   menulis   sebuah 

definisi kelas untuk bilangan rasional.

a) Perhatikan   kode   berikut   ini   dan   pastikan   Anda   dapat   memahami   apa   yang 

dikerjakannya:
public class Complex
{

210
    double real, imag;
    // simple constructor
    public Complex () {
        this.real = 0.0; this.imag = 0.0;
    }
    // constructor that takes arguments
    public Complex (double real, double imag) {
        this.real = real; this.imag = imag;
    }
    public static void printComplex (Complex c) {
                System.out.println   (c.real   +   "   +   "   +   c.imag   + 
"i");
    }
    // conjugate is a modifier
    public static void conjugate (Complex c) {
        c.imag = ­c.imag;
    }

// abs is a function that returns a primitive
public static double abs (Complex c) {
    return Math.sqrt (c.real * c.real + c.imag * c.imag);

}
// add is a function that returns a new Complex object
public static Complex add (Complex a, Complex b) {
    return new Complex (a.real + b.real, a.imag + b.imag);
}
public static void main(String args[]) {
    // use the first constructor
    Complex x = new Complex ();

211
    x.real = 1.0;
    x.imag = 2.0;
    // use the second constructor
    Complex y = new Complex (3.0, 4.0);
    System.out.println (Complex.abs (y));

    Complex.conjugate (x);
    Complex.printComplex (x);
    Complex.printComplex (y);
    Complex s = Complex.add (x, y);
    Complex.printComplex (s);
  }
}

b) Buatlah   sebuah   program   dengan   nama   Rational.java   yang   mendefinisikan   sebuah 

kelas   dengan   nama   Rational.   Suatu   objek   Rational   haruslah   memiliki   2   variabel 

instan   berupa   integer   yang   digunakan   untuk   menyimpan   nilai   numerator   dan 

denumerator dari bilangan rasional. 

c) Tulislah sebuah konstruktor tanpa parameter yang menginisialisasi kedua variabel 

instan tersebut dengan nilai 0.

d) Tulislah   sebuah   metode   dengan   nama   printRational   yang   menggunakan   objek 

Rational   sebagai   sebuah   argumen   lalu   mencetaknya   ke   dalam   format   yang   dapat 

diterima oleh Anda sendiri.

e) Tulislah sebuah metode main yang mampu menghasilkan sebuah objek baru bertipe 

Rational, inisialisasilah variabel­variabel instannya dengan nilai­nilai tertentu, lalu 

cetaklah objek tersebut.

f) Sampai   sejauh   ini,   Anda   telah   membuat   program­program   yang   dapat   diuji 

(debuggable), meski dalam jumlah yang tidak terlalu banyak. Sekarang ujilah semua 

212
program itu, lalu debug­lah jika memang perlu.

g) Tulislah sebuah konstruktor kedua untuk kelas Anda. Kelas ini menggunakan dua 

argumen yang sekaligus berfungsi untuk menginisialisasi variabel­variabel instan.

h) Tulislah   sebuah   metode   dengan   nama   negate   yang   mengubah   tanda   dari   suatu 

bilangan rasional. Metode ini haruslah termasuk ke dalam tipe modifier yang akan 

mengembalikan void. Tambahkan baris­baris ke dalam metode main untuk menguji 

metode baru itu.

i) Tulislah   sebuah   metode   dengan   nama   invert   yang   membalik   angka   dengan   cara 

menukar (swapping) numerator dengan denumerator. Ingat­ingatlah pola  swapping 

yang telah kita lihat sebelumnya. Ujilah metode ini dengan menambahkan beberapa 

baris kode dalam metode main.

j) Tulislah   sebuah   metode   dengan   nama   toDouble   yang   dapat   mengubah   bilangan 

rasional   ke   bentuk   double   (bilangan  floating­point)   sekaligus   mengembalikan 

hasilnya. Metode ini termasuk ke dalam kelompok fungsi murni; jadi ia tidak akan 

mengubah   atau   memodifikasi   objek   yang   dioperasikannya.   Lalu   seperti   biasanya, 

ujilah metode yang baru Anda buat itu.

k) Tulislah   sebuah   modifier   dengan   nama   reduce   yang   dapat   mengurangi   sebuah 

bilangan rasional sampai ke bentuknya (term) yang terkecil dengan cara menemukan 

GCD  dari numerator dan denumerator untuk kemudian membagi atas dan bawah 

dengan   GCD.   Metode   ini   seharusnya   berupa   fungsi   murni   yang   tidak   mengubah 

variabel­variabel instan milik objek tempat dimana dia dipanggil.

l) Tulislah sebuah metode dengan nama add yang menggunakan dua bilangan rational 

sebagai argumen dan mengembalikan sebuah objek Rational yang baru. Objek yang 

dikembalikan, jelas, harus mengandung jumlah dari kedua argumen tersebut.

Tujuan   dari   latihan  ini   adalah  untuk  menulis  sebuah  definisi  kelas   yang  melibatkan 

berbagai jenis metode sekaligus yakni; konstruktor, modifier, dan fungsi­fungsi murni. 

213
214
Bab 10

Array

Array   adalah   suatu   kumpulan   nilai   yang   diidentifikasi   dengan   sebuah   indeks.   Anda 

dapat membuat sebuah array berisi nilai­nilai yang bertipe int, double, atau tipe lainnya. 

Tapi ingat, semua nilai tersebut harus sama tipenya.

Dilihat dari sintaksnya, tipe array tampak seperti tipe Java lainnya kecuali bahwa tipe 

ini diikuti dengan simbol ' [ ] '. sebagai contoh, int [ ] adalah tipe array untuk integer dan 

double [ ] adalah tipe array untuk double.

Anda dapat mendeklarasikan variabel­variabel bertipe ini dengan cara yang sudah lazim 

digunakan:
int[] count;
double[] values;

Sampai Anda menginisialisasi variabel­variabel ini, semua akan  diinisialisasi  dengan 

null. Untuk membuat array, gunakan perintah new.
count = new int[4];
values = new double[size];

Assignment pertama membuat variabel count akan mengacu pada sebuah array yang 

berisi empat nilai bertipe integer. Sementara Assignment kedua akan   menyebabkan 

values mengacu pada suatu array bertipe double. Jumlah elemen dalam variabel values 

bergantung   kepada   size.   Anda   dapat   menggunakan   ekspresi   integer   apapun   untuk 

membuat ukuran array.

Gambar berikut ini menunjukkan representasi array dalam diagram keadaan.

215
Nomor yang dicetak tebal di dalam kotak merupakan elemen dari array. Sedangkan 

nomor­nomor   yang   berada   di   luar   kotak   merupakan   indeks   yang   digunakan   untuk 

mengidentifikasi setiap kotak. Ketika Anda mengalokasikan sebuah array baru, elemen­

elemennya akan diinisialisasi ke nol (0).

10.1 Mengakses Elemen

Untuk menyimpan nilai­nilai di dalam array, gunakanlah operator []. Sebagai contoh, 

count [0] akan mengacu kepada elemen ke­0 dari array tersebut. Sedangkan count [1] 

akan mengacu kepada elemen ke­1 array tersebut.

Anda dapat menggunakan operator [] dimanapun di dalam sebuah ekspresi:
count[0] = 7;
count[1] = count[0] * 2;
count[2]++;
count[3] ­= 60;

Semua pernyataan di atas merupakan bentuk assignment yang legal dalam Java. Berikut 

ini adalah pengaruh yang ditimbulkan oleh lampiran kode di atas:

Mulai   sekarang Anda  harus memperhatikan  bahwa keempat  elemen dalam array ini 

diindeks mulai dari 0 sampai  dengan 3. Ini berarti bahwa tidak ada elemen dengan 

nomor indeks yang sama dengan 4. Anda semestinya sudah terbiasa dengan bentuk­

bentuk seperti ini karena sebelumnya kita sudah melihat hal yang sama terjadi pada 

penomoran indeks untuk variabel bertipe data String. Meskipun begitu, terkadang kita 

seringkali melakukan kesalahan dengan menggunakan nomor indeks yang di luar batas 

array   itu   sendiri.   Kesalahan   semacam   ini   akan   menghasilkan   sebuah   eksepsi,   yakni 

ArrayOutOfBoundsExceptions. Laiknya   yang terjadi pada kemuculan semua eksepsi, 

216
Anda juga akan mendapatkan sebuah pesan error yang akan menyebabkan terhentinya 

eksekusi program Anda.

Anda dapat menggunakan ekspresi apapun sebagai suatu indeks, selama ia bertipe  data 

int. Salah satu cara yang paling umum untuk mengindeks sebuah array adalah dengan 

menggunakan variabel perulangan (loop variable). Simaklah contoh berikut ini:
int i = 0;
while (i < 4) {
System.out.println (count[i]);
i++;
}

Bentuk   ini   merupakan   bentuk   perulangan   while   yang   lazim   digunakan   untuk 

menghitung indeks mulai dari indeks 0 hingga 4. ketika variabel perulangan, i, berisi 

nilai   4,   syarat   perulangan   tersebut   akan   menghasilkan   kesalahan.   Kesalahan   ini 

menyebabkan terhentinya  eksekusi program. Oleh karena itu, badan dari perulangan 

tersebut hanya dieksekusi ketika i sama dengan 0, 1, 2 dan 3.

Setiap kali kita melewati perulangan di atas, kita menggunakan variabel i sebagai indeks 

untuk array. Bentuk penelusuran array seperti ini merupakan bentuk yang paling sering 

digunakan. Array dan perulangan memadu bersama laksana memakan sate madura yang 

gurih dengan wedang jahe manis nan hangat. 

10.2 Menyalin Array

Ketika Anda menyalin sebuah variabel bertipe array, ingatlah bahwa Anda sebenarnya 

sedang menyalin sebuah acuan kepada array tersebut. Sebagai contoh:
double[] a = new double [3];
double[] b = a;

217
Kode ini akan membuat sebuah array yang diisi dengan tiga elemen bertipe double, lalu 

membuat dua variabel yang berbeda mengacu kepadanya. Situasi ini merupakan salah 

satu bentuk aliasing.

Perubahan   apapun   yang   Anda   lakukan   pada   satu   array   akan   memberikan   pengaruh 

kepada array lainnya. Mungkin ini bukanlah perilaku yang Anda inginkan; sebaliknya, 

Anda harus membuat sebuah salinan dari array, dengan mengalokasikan sebuah array 

baru dan menyalin setiap elemen dari astu array ke array lainnya.
double[] b = new double [3];

int i = 0;
while (i < 4) {
b[i] = a[i];
i++;
}

10.3 Bentuk Perulangan for 

Perulangan­perulangan   yang   sudah   kita   tulis   sejauh   ini   merupakan   perulangan   yang 

sudah   terlalu   sering   kita   lihat.   Semuanya   dimulai   dengan   menginisialisasi   sebuah 

variabel; menggunakan suatu test, atau sebuah persyaratan, yang bergantung kepada 

variabel itu sendiri; lalu di dalam perulangan itu mereka mengerjakan sesuatu untuk 

variabel tersebut, seperti misalnya melakukan increment untuknya.

Ada sebuah bentuk perulangan alternatif bagi bentuk sangat umum seperti di atas, yakni 

perulangan for. Bentuk ini mampu mengekspresikan perulangan secara tepat dan lugas. 

Bentuk umum sintaksnya tampak sebagai berikut:
for (INITIALIZER; CONDITION; INCREMENTOR) {
BODY

218
}

Pernyataan ini eqivalen dengan 
INITIALIZER;

while (CONDITION) {
BODY
INCREMENTOR
}

Selain lebih lugas, bentuk ini juga lebih mudah untuk dibaca. Ini disebabkan karena 

semua pernyataan yag terkait dengan perulangan itu sendiri ditempatkan di dalam satu 

baris. Sebagai contoh:
for (int i = 0; i < 4; i++) {
System.out.println (count[i]);
}

Eqivalen dengan
int i = 0;

while (i < 4) {
System.out.println (count[i]);
i++;
}

Untuk   latihan  Anda,  tulislah  sebuah   perulangan  for  yang  mampu  menyalin   elemen­

elemen yang terdapat dalam sebuah array.

219
10.4 Array dan Objek

Dalam beberapa kesempatan, array bertingkah­laku laiknya objek:

● ketika Anda mendeklarasikan sebuah variabel array, Anda akan mendapatkan 

sebuah acuan/referensi ke sebuah array.

● Anda harus menggunakan perintah new untuk membuat sebuah array.

● Ketika   Anda   melewatkan   sebuah   array   sebagai   argumen,   Anda   berarti 

melewatkan sebuah acuan, yang berarti bahwa metode yang Anda panggil dapat 

mengubah elemen yang dikandung array.

Beberapa   objek   yang   sudah   kita   lihat,   seperti  Rectangles,   dapat   disamakan   dengan 

array, dalam artian bahwa keduanya merupakan kumpulan dari nilai­nilai yang diberi 

nama.   Hal   ini   mengundang   sebuah   pertanyaan,   “Apa   beda   array   dengan   4   elemen 

bertipe integer dengan sebuah objek bertipe Rectangle?”;

Jika Anda melihat kembali definisi “array” di awal bab, Anda akan menemukan sebuah 

perbedaan, yakni bahwa elemen dari sebuah array diidentifikasi menggunakan  indeks, 

sementara elemen­elemen (variabel instan) dari suatu objek menggunakan nama, seperti 

x, width, dst. 

Perbedaan lain antara array dan objek adalah bahwa semua elemen dari sebuah array 

haruslah   bertipe   sama.   Meskipun   hal   yang   sama   juga   terjadi   pada   objek   Rectangle, 

namun   pada   kesempatan   lain   kita   juga   mengetahui   bahwa   ada   objek   lain   yang 

mempunyai variabel­variabel instan dengan tipe data yang berbeda­beda. Coba lihat 

kembali objek Time. 

10.5 Panjang Array

Sebenarnya, array sudah memiliki satu variabel instan, yakni length. Mudah diterka, 

variabel   ini   berisi   informasi   (nilai)   mengenai   panjang   suatu   array   (jumlah   elemen­

220
elemen). Adalah ide brilian untuk menggunakan nilai variabel instan ini sebagai batas 

atas untuk sebuah perulangan ketimbang menggunakan nilai yang   konstan. Dengan 

variabel ini, jika ukuran array suatu array mengalami perubahan, maka Anda tidak perlu 

lagi bersusah payah mengubah semua pernyataan yang terkait dengan perulangan; ini 

akan bekerja dan berfungsi untuk semu ukuran array.
for (int i = 0; i < a.length; i++) {
b[i] = a[i];
}

Eksekusi terakhir yang terjadi dalam badan perulangan di atas adalah ketika  i  sama 

dengan   a.length   –   1.     ekspresi   ini   merupakan   indeks   untuk   elemen   terakhir   array 

tersebut. Ketika i sama dengan a.length, syarat perulangan akan bernilai salah sehingga 

badan perulangan tidak akan dieksekusi lagi. Hal ini menguntungkan untuk kita karena 

jika   ekspresi   tersebut   sampai   dieksekusi   maka   eksepsi   tidak   akan   dapat   dihindari. 

Lampiran   kode  ini  mengasumsikan   bahwa   array  b  mempunyai  jumlah  elemen   yang 

sama dengan array a.

Sebagai latihan, tulislah sebuah metode cloneArray yang menggunakan sebuah array 

bertipe   integer   sebagai   parameter.   Metode   ini   nantinya   akan   mampu   menghasilkan 

sebuah   array   baru   yang   memiliki   ukuran   yang   sama,   menyalin   elemen­elemen   dari 

array pertama ke array yang baru, lalu mengembalikan nilai kembalian yang berupa 

acuan ke array baru tersebut.

10.6 Angka­Angka Acak (Random) 

Program­program komputer pada umumnya selalu mengerjakan hal yang sama setiap 

kali mereka dieksekusi. Sifat seperti ini membuat program­program komputer pantas 

disebut sebagai sesuatu yang deterministik. Biasanya, sesuatu yang determinis adalah 

221
hal yang baik karena kita cenderung untuk mengharapkan perhitungan yang sama untuk 

menghasilkan hasil yang sama pula. Namun untuk beberapa aplikasi, ternyata kita lebih 

menginginkan sebuah komputer yang memiliki sifat tidak bisa diterka (unpredictable). 

Permainan­permainan (games) yang dimainkan dengan sebuah komputer adalah contoh 

yang jelas, tapi masih banyak lagi contoh yang lain tentunya.

Membuat sebuah program yang benar­benar bersifat non­deterministik adalah perkara 

yang sangat tidak mudah. Namun tetap ada cara untuk membuat sebuah program agar 

tampak bersifat non­deterministik. Salah satu cara adalah dengan menggunakan angka­

angka acak lalu memanfaatkannya untuk menentukan keluaran/hasil sebuah program. 

Java menyediakan metode bawaan yang dapat membuat angka­angka  pseudorandom 

(imitasi terhadap definisi angka random sesungguhnya). Angka­angka ini sebenarnya 

tidaklah sungguh­sungguh random secara matematis, tapi untuk tujuan yang hendak kita 

capai, mereka tampaknya bisa mengerjakan apa yang kita maksudkan. 

Periksalah   dokumentasi   untuk   metode   random   dalam   kelas   Math.   Nilai   kembalian 

merupakan angka bertipe double antara 0.0 dan 1.0. untuk lebih jelasnya; angka­angka 

ini lebih besar atau sama dengan 0.0 dan kurang dari 1.0. Setiap kali Anda memanggil 

metode random, Anda akan medapatkan angka berikutnya dalam urutan yang bersifat 

pseudorandom (alias tidak terurut). Untuk melihat contohnya,  eksekusilah perulangan 

ini:
for (int i = 0; i < 10; i++) {
double x = Math.random ();
System.out.println (x);
}

Untuk menghasilkan bilangan acak bertipe double antara 0.0 dengan batas atas yang 

berupa variabel seperti high, Anda dapat mengalikan  x dengan high. 

222
Bagaimana   cara   Anda   membuat   sebuah   bilangan   acak   antara   variabel  low  dengan 

high? Bagaimana cara Anda membuat bilangan acak bertipe integer?

Latihan 10.1

Tulislah sebuah metode randomDouble yang menggunakan dua variabel bertipe double, 

yakni low dan high, yang mampu mengembalikan nilai acak bertipe double, yakni x 

dimana low ≤ x < high.

Latihan 10.2

Tulislah sebuah metode randomInt yang menggunakan dua argumen, yakni low dan 

high,  yang mampu mengembalikan  nilai acak  bertipe integer diantara  low dan high 

dimana  low ≤ x ≤ high.

10.7 Array dari Angka­angka Random (Acak) 

Jika implementasi metode randomInt buatan Anda berhasil, maka setiap nilai dalam 

interval   (range)   antara   low   dan   high   harus   memiliki   probabilitas   kemunculan   yang 

sama. Jika Anda membuat sebuah deretan angka yang panjang, maka setiap nilai harus 

muncul, setidaknya mendekati, angka yang sama setiap kali kemunculannya.

Salah satu cara untuk menguji metode Anda adalah dengan membuat angka­angka acak 

dalam   jumlah   yang   banyak,   lalu   menyimpannya   ke   dalam   array,   untuk   kemudian 

menghitung jumlah kemunculan setiap nilai yang telah ditampilkan.

Metode   berikut   ini   menggunakan   satu   argumen,   yakni   ukuran   array.   Metode   ini 

mengalokasikan   sebuah   array   baru   yang   berisi   elemen­elemen   bertipe   integer. 

Kemudian   mengisinya   dengan   bilangan­bilangan   acak,   lalu   mengembalikan   sebuah 

acuan/referensi kepada array yang baru.
public static int[] randomArray (int n) {

223
int[] a = new int[n];

for (int i = 0; i<a.length; i++) {
a[i] = randomInt (0, 100);
}
return a;
}

Tipe kembaliannya adalah int [], yang berarti bahwa metode ini akan mengembalikan 

nilai­nilai bertipe integer. Untuk menguji metode ini, Anda sebaiknya menulis metode 

lain yang dapat mencetak isi array tersebut.
public static void printArray (int[] a) {

for (int i = 0; i<a.length; i++) {
System.out.println (a[i]);
}
}

Kode berikut ini akan membuat sebuah array lalu mencetak hasilnya:
int numValues = 8;
int[] array = randomArray (numValues);
printArray (array);

Di mesin saya, hasilnya adalah:
27
6
54
62
54

224
2
44
81

Hasil ini kelihatan seperti sungguh­sungguh acak. Hasil yang Anda peroleh mungkin 

akan berbeda.

Jika   ini   merupakan   hasil   ujian,   maka   ini   adalah   hasil   ujian   yang   buruk,   sang   guru 

mungkin akan menampilkan hasilnya kepada kelas dalam bentuk histogram. Histogram 

merupakan  suatu  kumpulan  penghitung­penghitung  (counter)   yang  menyimpan   jejak 

mengenai jumlah kemunculan suatu nilai dalam setiap kesempatan.

Untuk nilai­nilai ujian, kita mungkin menyediakan 10 penghitung untuk menyimpan 

jejak   mengenai   berapa   banyak   murid   yang   mendapatkan   nilai   dalam   interval   90an, 

80an,   dst.   Subbab   berikutnya   akan   memperlihatkan   Anda   mengenai   cara   untuk 

membuat suatu histogram.

10.8 Pencacahan

Sebuah pendekatan yang bagus untuk masalah­masalah seperti ini adalah dengan cara 

memikirkan sebuah metode sederhana yang mudah untuk ditulis, sekaligus   memiliki 

kemungkinan untuk dimanfaatkan. Kemudian Anda dapat mengkombinasikannya untuk 

menghasilkan sebuah solusi. Tentu, adalah tidak mudah untuk mengetahui metode mana 

yang   bisa   dimanfaatkan   dalam   waktu   yang   singkat,   tapi   seiring   meningkatnya 

pengalaman Anda, maka akan semakin banyak pula ide­ide Anda.

Selain itu, terkadang kita juga tidak bisa selalu menyadari dengan jelas dan pasti suatu 

hal yang menurut kita mudah untuk ditulis. Namun pendekatan yang mungkin berhasil 

adalah dengan cara mencari penyelesaian atas submasalah yang sesuai dengan pola­pola 

masalah yang sebelumnya sudah pernah Anda lihat.

225
Kembali   ke   subbab   7.7,   kita   telah   melihat   sebuah   perulangan   yang   melakukan 

penelusuran sebuah string lalu menghitung jumlah kemunculan suatu huruf. Anda dapat 

menganggap   pola   yang   dianut   oleh   program   ini   sebagai   sebuah   pola   dengan   nama 

“penelusuran dan penghitungan”. Elemen­elemen dalam pola ini antara lain:

● Sebuah   kumpulan   kontainer   yang   dapat   ditelusuri,   seperti   sebuah   array   atau 

string.

● Sebuah pengujian yang dapat Anda lakukan kepada setiap elemen yang berada 

di dalam kontainer tersebut.

● Sebuah   pencacah   (counter)   yang   menyimpan   jejak   tentang   berapa   banyak 

elemen yang telah melewati ujian.

Dalam kasus ini, kontainer yang dimaksudkan adalah suatu array yang bertipe integer. 

Pengujian   yang   dilakukan   adalah   dengan   cara   memasukkan   nilai­nilai   yang   ada   ke 

dalam interval­interval nilai yang ada.

Berikut ini adalah metode inRange yang menghitung jumlah suatu elemen dalam array 

yang  masuk ke  dalam  interval  nilai  yang ada.  Parameter­parameter   yang digunakan 

adalah array dan dua integer yang akan menentukan batas atas dan bawah suatu interval.
public   static   int   inRange   (int[]   a,   int   low,   int  
high) {
int count = 0;
for (int i=0; i<a.length; i++) {
if (a[i] >= low && a[i] < high) count++;
}
return count;
}

Ketika saya mendeskripsikan metode ini, saya tidak terlalu peduli apakah suatu    nilai 

yang sama dengan low atau high akan turut masuk ke dalam interval ataukah tidak, tapi 

226
dari   kode tersebut Anda  dapat  melihat bahwa  low akan ikut  masuk sementara  high 

tidak. Dari sini kita langsung dapat mencegah terjadinya   penghitungan ganda untuk 

satu elemen.

Sekarang kita dapat menghitung banyak nilai (cacah bukan jumlah) yang berada dalam 

interval yang kita inginkan:
int[] scores = randomArray (30);
int a = inRange (scores, 90, 100);
int b = inRange (scores, 80, 90);
int c = inRange (scores, 70, 80);
int d = inRange (scores, 60, 70);
int f = inRange (scores, 0, 60);

10.9 Histogram

Kode   yang   kita   tulis   dan   lihat   sejauh   ini   tampaknya   seperti   sesuatu   yang   selalu 

berulang­ulang. Tetapi selama interval nilai yang kita miliki tidaklah terlalu besar, hal 

ini bukanlah masalah serius. Tapi coba bayangkan jika Anda memiliki 100 interval. 

Apakah Anda mau menulis kode berikut ini?
int count0 = inRange (scores, 0, 1);
int count1 = inRange (scores, 1, 2);
int count2 = inRange (scores, 2, 3);
...
int count3 = inRange (scores, 99, 100);

Saya   pikir   tidak!   Apa   yang   kita   inginkan   sesungguhnya   adalah   suatu   cara   untuk 

menyimpan 100 integer, dan lebih bagus lagi kalau kita bisa memakai sebuah indeks 

untuk mengaksesnya. Biar saya tebak, Anda pasti langsung terpikir dengan  “array!” 

227
Pola   penghitungan   yang   akan   kita   gunakan   adalah   sama,   tak   peduli   apakah   kita 

menggunakan satu pencacah (single counter) atau satu array berisi pencacah.   Dalam 

kasus ini, kita menginisialisasi array di luar perulangan; lalu, di dalam perulangan itu, 

kita panggil metode inRange untuk menyimpan hasilnya:
int[] counts = new int [100];

for (int i = 0; i<100; i++) {
counts[i] = inRange (scores, i, i+1);
}

Satu­satunya 'kecurangan' di sini adalah bahwa kita menggunakan variabel perulangan 

untuk dua kepentingan sekaligus: sebagai indeks untuk array juga sebagai parameter 

untuk inRange.

10.10 Solusi Single­Pass

Meskipun   kode   ini   bekerja,   tapi   ia   belum   bisa   dianggap   efisien.   Karena   setiap   kali 

memanggil  inRange,   kode   ini   akan   menelusuri   semua   array.  Ketika   jumlah   interval 

bertambah, maka bertambah pula waktu untuk penelusuran.

Akan   lebih   baik   bagi   kita   untuk   membuat   satu   single­pass   yang   dapat   menelusuri 

seluruh array, dan untuk setiap nilai yang ditelusuri, cukup dengan menghitung interval 

tempat nilai tersebut berada. Kemudian barulah kita dapat menaikkan nilai pencacah 

yang kita gunakan. Dalam contoh ini, aspek komputasi menjadi tidak begitu penting. 

Hal ini terjadi karena kita dapat menggunakan nilai itu sendiri sebagai indeks untuk 

array pencacah (array of counters).

Berikut ini adalah kode yang mampu menelusuri sebuah array yang berisi nilai­ nilai 

(skor) dengan hanya satu kali penelusuran. Hasilnya adalah sebuah histogram.

228
int[] counts = new int [100];

for (int i = 0; i < scores.length; i++) {
int index = scores[i];
counts[index]++;
}

Latihan 10.3

Enkapsulasilah kode ini dalam satu metode dengan nama scoreHist yang menggunakan 

array berisi nilai­nilai (skor) lalu mengembalikan sebuah histogram yang berisi nilai­

nilai dalam array tersebut.

Modifikasilah metode tersebut sehingga histogram hanya memiliki 10 pencacah,   lalu 

menghitung banyak  nilai yang muncul dalam setiap  intervalnya;  maksudnya  banyak 

nilai dalam interval 90­an, 80­an, dst. 

10.11 Daftar Kata­Kata

Istilah Arti
Kumpulan nilai­nilai yang diberi nama, dimana semua nilai 

Array  tersebut   memiliki   tipe   yang   sama   dan   setiap   nilai 

diidentifikasi dengan indeks.
Suatu bentuk struktur data yang berisi kumpulan item atau 
koleksi
elemen
Salah satu nilai di dalam array. Operator [] digunakan untuk 
elemen
memilih elemen dalam suatu array.
Variabel   integer   atau   nilai   yang   digunakan   untuk 
index
mengindikasi (menunjukkan) satu elemen dalam array.

229
Sebuah program yang mengerjakan hal­hal yang sama setiap 
deterministik
kali digunakan/dipanggil.
Suatu deretan angka­angka yang tampak seperti angka­angka 

pseudorandom yang diacak, tetapi sebenarnya tidak. Angka­angka tersebut 

hanyalah hasil dari komputasi yang determinis. 
Array   bertipe   integer   dimana   setiap   nilai   integer   akan 

histogram mencacah   banyak   nilai   yang   masuk   ke   dalam   interval­

interval yang sudah ditentukan.

10.12 Latihan

Latihan 10.4

Tulislah  metode  areFactors  yang   menggunakan  sebuah  integer,  n,  dan   sebuah  array 

bertipe   integer,   lalu   mengembalikan  true  jika   angka­angka   dalam   array   merupakan 

faktor dari n (dengan kata lain; n bisa dibagi dengan semua angka tersebut). Petunjuk : 

Lihat Latihan 5.1

Latihan 10.5

Tulislah metode yang menggunakan sebuah array integer dan sebuah integer dengan 

nama target sebagai argumen. Metode ini akan mengembalikan nilai yang berupa indeks 

tempat dimana target pertama kali muncul dalam array tersebut. Jika nilai yang dicari 

tidak ditemukan maka metode akan mengembalikan nilai ­1. 

Latihan 10.6

Tulislah metode arrayHist dengan sebuah array integer sebagai argumen, yang dapat 

menghasilkan sebuah array histogram yang baru. Histogram ini harus   berisi 11 elemen 

dengan tampilan sebagai berikut:
elemen t 0  ­­  numbe r of  elem ent s in  the  array  that  are  <=  0

230
  1  ­­  numbe r of  elem ent s in  the  array  that  are  ==  1
  2  ­­  numbe r of  elem ent s in  the  array  that  are  ==  2
      ...
  9  ­­  numbe r of  elem ent s in  the  array  that  are  ==  9
  10  ­ ­ numb er  of  elemen ts  in  the  array  that  are  >=  10

Latihan 10.7

Beberapa  programmer  tidak setuju dengan aturan umum yang menyebutkan   bahwa 

variabel   dan   metode   haruslah   diberi   nama   yang   mengandung   makna.   Sebaliknya, 

mereka   justru   beranggapan  bahwa   variabel   atau   metode  seharusnya   dinamai   setelah 

nama buah­buahan.

Untuk setiap metode di bawah ini, tulislah satu kalimat yang mendeskripsikan secara 

abstrak   tugas/fungsi   yang   dikerjakannya.   Lalu   untuk   setiap   variabel,   identifikasilah 

peran yang diembannya.
public static int banana (int[] a) {
int grape = 0;
int i = 0;
while (i < a.length) {
grape = grape + a[i];
i++;
}
return grape;
}

public static int apple (int[] a, int p) {
int i = 0;
int pear = 0;
while (i < a.length) {

231
if (a[i] == p) pear++;
i++;
}
return pear;
}

public static int grapefruit (int[] a, int p) {
for (int i = 0; i<a.length; i++) {
if (a[i] == p) return i;
}
return ­1;
}

Tujuan   latihan   ini   adalah   untuk   melatih   kemampuan   Anda   dalam  membaca  kode 

sekaligus mengenali pola­pola penyelesaian yang telah kita lihat sebelumnya.

Latihan 10.8

a) Apa output yang dihasilkan dari program berikut ini?

b) Gambarlah diagram stack yang menunjukkan keadaan dari program sesaat sebelum 

mus dikembalikan.

c) Deskripsikan dalam beberapa kata mengenai apa yang dilakukan oleh mus.

public static int[] make (int n) {
int[] a = new int[n];

for (int i=0; i<n; i++) {
a[i] = i+1;
}
return a;
}

232
public static void dub (int[] jub) {
for (int i=0; i<jub.length; i++) {
jub[i] *= 2;
}
}

public static int mus (int[] zoo) {
int fus = 0;
for (int i=0; i<zoo.length; i++) {
fus = fus + zoo[i];
}
return fus;
}

public static void main (String[] args) {
int[] bob = make (5);
dub (bob);

System.out.println (mus (bob));
}

Latihan 10.9

Umumnya,   pola­pola   yang   digunakan   untuk   penelusuran   array   yang   telah   kita   lihat 

sebelumnya dapat ditulis secara rekursif. Sebenarnya hal ini tidak lazim dilakukan, tapi 

ini bisa menjadi latihan yang bagus buat kita.

a) Tulislah metode maxInrange yang menggunakan sebuah array integer dan sebuah 

interval indeks (lowIndex dan highIndex). Metode ini akan mencari nilai maksimum 

233
dalam array, elemen­elemen yang dicari berada di antara lowIndex dan highIndex, 

termasuk di kedua ujungnya.

Metode ini haruslah bersifat rekursif. Jika panjang interval adalah 1, yaitu ketika 

lowIndex   ==   highIndex,   maka   kita   akan   segera   mengetahui   bahwa   satu­satunya 

elemen   yang   berada   dalam   interval   tersebut   adalah   nilai   maksimumnya.   Dengan 

demikian, inilah base case yang akan kita gunakan.

Jika   terdapat   lebih   dari   satu   elemen   dalam   suatu   interval,   kita   dapat   memecah 

arraynya   menjadi   dua   bagian;   tentukan   nilai   maksimum   dalam   setiap   bagian 

arraynya,   lalu   temukan   nilai   maksimum   diantara   nilai   maksimum   yang   sudah 

ditentukan sebelumya. 

b) Metode­metode   seperti   maxInRange   seringkali   mengundang   'kejanggalan'   ketika 

digunakan.   Untuk   menemukan   elemen   terbesar   dalam   sebuah   array,   kita   harus 

menyediakan sebuah interval yang menyertakan semua elemen dalam array.
double max = maxInRange (array, 0, a.length­1);

Tulislah   metode   max   yang   menggunakan   sebuah   array   sebagai   parameter   dan 

maxInRange untuk menemukan dan mengembalikan nilai terbesar. Metode­metode 

seperti   max   terkadang   disebut   juga   metode   pembungkus   (wrapper   methods). 

Disebut   demikian   karena   metode­metode   tersebut   meyediakan   sebuah   lapisan 

abstraksi (layer of abstraction) di sekeliling suatu metode yang janggal. Selain itu, 

metode   ini   juga   menyediakan   sebuah   antarmuka   untuk     lingkungan   di   luarnya 

sehingga   bisa   lebih   mudah   untuk   digunakan.   Metode   yang   mengerjakan 

komputasinya sendiri dikeal dengan istilah  helper method. Kita akan melihat pola 

ini lagi di subbab 14.9.

c)  Tulislah sebuah versi rekursif dari metode find menggunakan pola wrapper­helper. 

Metode   find   harus   menggunakan   sebuah   array   integer   sekaligus   sebuah   integer 

tujuan/target.   Metode   ini   harus   mengembalikan   indeks   dari   lokasi   awal   dimana 

234
integer target muncul di dalam array. Jika tidak, metode akan menghasilkan ­1.

Latihan 10.10

Salah satu cara yang tidak efisien untuk mengurutkan elemen­elemen dalam suau array 

adalah   dengan   cara   menemukan   elemen   terbesar   lalu   menukarnya   dengan   elemen 

pertama,   kemudian   menemukan   elemen   terbesar   kedua   lalau   menukarnya   dengan 

elemen kedua, dst.

a) Tulislah   metode   indexOfMaxInRange   yang   menggunakan   sebuah   array   integer 

sebagai  argumen,  yang  mampu  menemukan   elemen  terbesar  dalam   interval  yang 

telah ditentukan, lalu mengembalikan hasil yang berupa nilai indeksnya. Anda dapat 

memodifikasi   versi   rekursif   dari   maxInRange   atau   Anda   dapat   menulis   versi 

perulangannnya dari awal.

b) Tulislah   metode   swapElemet   yang   menggunakan   sebuah   array   integer   dan   dua 

indeks, yang mampu menukar elemen­elemen yang berada pada indeks yang telah 

ditentukan. 

c) Tulislah metode sortArray yang menggunakan sebuah array integer beserta metode 

indexOfMaxInRange dan swapElement untuk mengurutkan array dari yang terbesar 

hingga yang terkecil.

Latihan 10.11

Tulislah metode letterHist yang menggunakan sebuah String sebagai parameter   yang 

mampu menghasilkan histogram dari huruf­huruf yang berada di dalam String. Elemen 

ke­0 dari histogram harus berisi jumlah huruf a yang berada dalam string, baik huruf 

kecil maupun kapital, sementara elemen ke­26 harus berisi jumlah huruf z yang berada 

dalam string. Solusi Anda ini harus menerapkan pola   satu kali penelusuran. Jangan 

lebih!

Latihan 10.12

235
Sebuah  kata  disebut  “doubloon”  jika  setiap  huruf  yang  muncul  dalam  kata  tersebut 

muncul tepat dua kali. Sebagai contoh, kata­kata berikut ini merupakan doubloon yang 

saya temukan dalam kamus milikku.
Abba,   Anna,   appall,   appearer,   appeases,  
arraigning,   beriberi,   bilabial,   boob,  
Caucasus,   coco,   Dada,  deed,  Emmett,  Hannah,  
horseshoer,   Otto,   intestines,   Isis,   mama,  
Mimi,   murmur,   noon,   papa,   peep,   reappear,  
redder, sees,Toto, Shanghaiings

Tulislah metode isDoubloon yang mengembalikan nilai true jika kata yang dimasukkan 

merupakan doubloon dan false jika sebaliknya.

Latihan 10.13

Dalam permainan scrabble, setiap pemain memiliki kotak­kotak yang berisi huruf di 

dalamnya. Tujuan permainan ini adalah untuk membuat huruf­huruf yang pada awalnya 

tidak beraturan menjadi teratur sehingga dapat digunakan untuk   mengeja kata­kata. 

Sistem penilaian yang digunakan sangat membingungkan, tetapi sebagai panduan dasar, 

kata yang lebih panjang lebih banyak nilainya ketimbang kata yang lebih pendek.

Bayangkan saat ini ada seseorang yang memberi Anda sebuah kumpulan kotak yang 

berupa String, seperti “qijibo” lalu Anda juga diberi String lain untuk menguji coba, 

seperti “jib”. Tulislah metode testWord yang menggunakan dua String ini. Metode ini 

mengembalikan nilai true jika kumpulan kotak yang diberikan dapat digunakan untuk 

mengeja kata. Anda diperkenankan untuk  memiliki lebih dari satu kotak dengan huruf 

yang sama, tapi Anda hanya boleh menggunakan masing­masing kotak sebanyak satu 

kali saja. Jangan lebih!

Latihan 10.14

236
Dalam   permainan   Scrabble  yang   sebenarnya,   ada   beberapa  kotak   kosong   yang  bisa 

digunakan sebagai wild cards; yakni sebuah kotak kosong yang dapat digunakan untuk 

merepresentasikan huruf apa pun.

Pikirkanlah   sebuah   algoritma   untuk   testWord   yang   berkenaan   dengan   konsep   wild 

cards.   Tapi   ingat!   Jangan   sampai   terlalu   jauh   berurusan   dengan   detil   implementasi, 

misalnya memikirkan  cara  untuk merepresentasikan  wild  cards.  Bukan  itu!  Cobalah 

untuk   mendeskripsikan   algoritmanya   saja,   menggunakan   bahasa   yang   Anda   kuasai, 

dengan pseudocode, atau Java. 

237
Bab 11

Array berisi Objek

11.1 Komposisi

Sejauh   ini   kita   telah   melihat   beberapa   contoh   komposisi   (kemampuan   untuk 

mengombinasikan   fitur­fitur   bahasa   dalam   beberapa   variasi   susunan).   Salah   satunya 

adalah dengan menggunakan pemanggilan metode sebagai bagian dari  ekspresi. Contoh 

lainnya adalah struktur pernyataan tersarang; Anda dapat meletakkan pernyataan  if  di 

dalam perulangan while, atau di dalam pernyataan if lainnya, dst.

Setelah melihat pola ini, dan setelah belajar mengenai array dan objek, Anda semestinya 

tidak perlu terkejut ketika mengetahui bahwa ternyata Anda boleh memiliki array berisi 

objek. Kenyataannya, Anda juga dapat memiliki sebuah objek yang berisi array­array 

(sebagai variabel instan); Anda boleh memiliki array yang mengandung array; Anda 

juga boleh memiliki objek yang mengandung objek, dsb.

Di   dua   bab   berikutnya,   kita   akan   melihat   beberapa   contoh   komposisi.   Diantaranya 

adalah objek Card. 

11.2 Objek Card

Jika Anda tidak akrab dengan permainan kartu yang biasa dimainkan oleh banyak orang 

di seluruh dunia, maka sekarang adalah waktu yang tepat untuk memulainya. Karena 

kalau tidak, bab ini akan menjadi sia­sia. Ada 52 kartu dalam sebuah tumpukan kartu 

(deck).   Masing­masing   kartu   tersebut   akan   masuk   ke     dalam   satu   di   antara   empat 

kelompok (suit) yang ada. Empat kelompok tersebut antara lain; Sekop (Spade), Hati 

(Heart),   Permata   (Diamond),   dan   Wajik   (Club).   Selain   masuk   ke   dalam   empat 

238
kelompok,   setiap   kartu   juga   akan   memiliki   nomor   urutan/peringkat   (rank)   yang 

membedakannya dengan kartu­kartu lain yang masih ada dalam kelompok yang sama. 

Nomor urutan/peringkat ini antara lain; As (ace), 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, 

King. Dalam permainan kartu, kartu As bisa bernilai lebih tinggi ketimbang kartu King 

atau malah lebih rendah ketimbang kartu 2. Hal ini tergantung dengan jenis permainan 

kartu yang dimainkan.  

Jika kita hendak mendefinisikan sebuah objek untuk merepresentasikan       permainan 

kartu, maka kita bisa dengan mudah menyebutkan variabel instan yang diperlukan: rank 

dan suit. Tepat sekali! Tapi sayangnya, menentukan tipe data apa yang akan digunakan 

untuk   menyimpan   kedua   variabel   ini   justru   yang   agak   sulit.   Kemungkinan   pertama 

adalah String yang bisa menyimpan sesuatu seperti “Spade” untuk  suit  dan “Queen” 

untuk  rank. Satu masalah yang muncul dengan implementasi seperti ini adalah kita 

akan menemukan kesulitan ketika harus membandingkan kartu untuk memeriksa kartu 

mana yang memiliki suit atau rank yang lebih tinggi.

Alternatif   penyelesaian   masalah   adalah   dengan   menggunakan   tipe   integer   untuk 

menyandi (encode) rank dan suit. Dengan melakukan “penyandian”, bukan berarti saya 

ingin mengerjakan apa yang mungkin langsung terpikir di kepala banyak orang, yakni 

enkripsi, atau menyandi kedua variabel ini dengan kode rahasia. Apa yang dimaksud 

dengan   penyandian   oleh   seorang   ilmuwan   komputer   adalah   sesuatu   yang   seperti 

“buatlah   sebuah   bentuk   pemetaan   antara   deretan   angka­angka   dengan   sesuatu   yang 

ingin saya tampilkan”. Sebagai contoh,
Spades    →  3
Hearts    →  2
Diamonds  →  1
Clubs     →  0

239
Manfaat   yang   jelas   bisa   kita   lihat   dari   pemetaan   ini   adalah   bahwa   variabel  suit 

dipetakan ke tipe integer dalam keadaan terurut. Hal ini akan memberikan kemudahan 

untuk  kita ketika hendak membandingkan suit dengan cara membandingkan integer. 

Pemetaan   untuk   variabel   rank   tampak   sangat   jelas;   setiap   nomor   urut   kartu   akan 

dipetakan   sesuai   dengan   integer   yang   sama,   begitu   juga   dengan   kartu­kartu   yang 

menggunakan simbol­simbol:
Jack   →  11
Queen  →  12
King   →  13

Alasan saya menggunakan notasi matematika untuk pemetaan ini adalah karena mereka 

semua   bukanlah   bagian   dari   program   Java   yang   akan   kita   buat.   Mereka   hanyalah 

merupakan bagian dari rancangan program (program design) yang tidak akan kita ikut 

seratakan secara eksplisit di dalam kode. Definisi kelas untuk tipe Card akan tampak 

sebagai berikut:
class Card
{
    int suit, rank;
    public Card () {
        this.suit = 0;  this.rank = 0;
    }
    public Card (int suit, int rank) {
        this.suit = suit; this.rank = rank;
    }
}

Seperti   biasa,   saya   menyediakan   dua   konstruktor   di   sini,   satu   yang   menggunakan 

240
sebuah parameter untuk setiap variabel instan, dan satu lagi yang tidak menggunakan 

satu parameter pun.

Untuk   membuat   sebuah   objek   yang   dapat   merepresentasikan   rank   (urutan)   3   milik 

wajik, kita bisa menggunakan perintah new sebagai berikut:

Card threeOfClubs = new Card (0, 3);
Argumen pertama, 0, merepresentasikan kelompok wajik.

11.3 Metode printCard

Ketika   Anda   membuat   sebuah   kelas   baru,   langkah   pertama   yang   biasanya     Anda 

kerjakan   adalah   mendeklarasikan   variabel   instan   dan   menulis   konstruktor­

konstruktornya. Kemudian diikuti dengan menulis metode standar yang harus dimiliki 

oleh semua objek, termasuk satu metode yang akan mencetak objek  tersebut, lalu satu 

atau dua metode untuk membandingkan objek­objek. Saya akan memulainya dengan 

metode printCard. 

Untuk mencetak objek Card yang dapat dibaca dengan mudah oleh manusia, kita akan 

memetakan   kode­kode   integer   ke   bentuk   yang   berupa   kata­kata.   Cara   alami   untuk 

melakukannya  adalah  dengan   menggunakan   sebuah   array   berisi  String.   Anda   bisa 

membuat   sebuah   array   berisi  String  dengan   cara   yang   sama   seperti   ketika   Anda 

membuat sebuah array yang berisi tipe data primitif:
String[] suits = new String [4];
Kemudian kita isi elemen­elemen array ini dengan nilai­nilai sebagai berikut:
suits[0] = "Clubs";
suits[1] = "Diamonds";
suits[2] = "Hearts";
suits[3] = "Spades";
Membuat   sebuah   array   dan   langsung   menginisialisasinya   merupakan   operasi   yang 

241
sangat   sering   dilakukan.   Saking   seringnya,   sampai­sampai   Java   malah   sudah 

menyediakan sintaks khusus untuk melakukannya:  
String[]   suits   =   {"Clubs",   "Diamonds" ,   "Hearts",  
"Spades"};

Pengaruh yang dihasilkan oleh pernyataan di atas akan sama dengan yang ditimbulkan 

oleh deklarasi, alokasi dan assignment secara terpisah. Diagram keadaan dari array ini 

akan tampak seperti gambar berikut:

Elemen­elemen   array   merupakan   sesuatu   yang   mengacu   (references)   ke  String, 

ketimbang menjadi  String  itu sendiri. Hal ini adalah fakta umum yang berlaku untuk 

semua array yang berisi objek­objek, sebagaimana yang akan saya bahas lebih detail di 

bagian berikutnya. Sekarang, yang kita butuhkan adalah array  berisi String lain yang 

digunakan untuk mengkode balik (decode) peringkat­peringkat dalam kartu:
String[]   ranks   =   {   "narf",   "Ace",   "2",   "3",   "4",   "5",  
"6",
"7",  "8", "9",  "10",  "Jack",  "Queen",  "King"  };

Elemen   “narf”   digunakan   sebagai   penjaga­tempat   (place­keeper)   untuk   elemen   ke­0 

dari array yang tidak akan pernah dipakai dalam permainan kartu. Indeks array yang 

bisa dipakai hanyalah 1 s.d. 13. Elemen yang tidak digunakan ini memang tidak penting 

tentunya. Sebenarnya kita bisa saja memulainya dari urutan ke­0, seperti biasa, tapi 

akan lebih baik bagi kita untuk mengkode 2 dengan 2, 3 dengan 3, 4 dengan 4, dst.

Dengan   array­array   ini,   kita   bisa   memilih   String   yang   tepat   dengan   menggunakan 

variabel suit dan rank sebagai indeks. Dalam metode printCard,
publi c st atic  voi d pr intC ard ( Car d c)  {

242
Strin g[]   su its   =   {   "C lubs ",   "Di amon ds",   "Hear ts",  
"Spad es" } ;

Strin g[]   rank s   =   {   "n arf" ,   "A ce",   "2" ,   "3 ",   "4",   "5",  
"6", " 7",  "8" , "9 ", " 10",  "Ja ck",  "Qu een" , "K ing"  };

Syste m.ou t.pr intl n   (ran ks[c .ran k]   +   "   of   "   +  


suits [c.s uit] );
}

Ekspresi suits[c.suit] artinya adalah “gunakan variabel instan suit dari objek c sebagai 

sebuah indeks ke dalam array dengan nama  suits, lalu pilih string yang ada di situ.” 

hasil dari kode berikut 
Card card = new Card (1, 11);
printCard (card);

adalah Jack of Diamonds.

11.4 Metode sameCard

Kata “sama” termasuk salah satu kata dari beberapa kata dalam bahasa alami (natural  

language)   yang   tampaknya   baru   akan   jelas   maksudnya   ketika   Anda   memberinya 

dengan maksud­maksud tertentu. 

Sebagai contoh, jika saya berkata “Chris dan saya mempunyai mobil yang sama,” maka 

di   sini   saya   bermaksud   menginformasikan   bahwa   mobil   miliknya   dan   milik       saya 

mempunyai model dan tahun pembuatan yang sama. Jika saya berkata bahwa   bahwa 

“Chris dan saya mempunyai ibu yang sama,” di sini saya bermaksud mengatakan bahwa 

ibunya dan ibu saya adalah satu ibu yang sama. Jadi, ide mengenai “kesamaan” bisa 

dimaknai berbeda­beda tergantung dengan konteks kalimatnya. 

Ketika   Anda   berbicara   mengenai   objek,   Anda   juga   akan   menemui   ambiguitas   yang 

sama.   Sebagai   contoh,   jika   dua   kartu   adalah   kartu   yang   sama,   apakah   itu   berarti 

243
keduanya   memiliki   data   yang   sama   (rank  dan  suit),   ataukah   keduanya   hanya 

merupakan dua objek Card yang sama?

Untuk   melihat   apakah   dua   objek   berbeda   mengacu   ke   objek   yang   sama,   kita   bisa 

menggunakan operator “ == ”. Sebagai contoh:
Card  card1  = new  Card (1,  11);
Card  card2  = card1;

  if  (card1  == card2)  {

  System.ou t.prin tln   ("card1   and   card2   are   the   same  


object.");

Bentuk   kesamaan   seperti   ini   disebut  shallow   equality  (tidak   dalam)   karena   hanya 

membandingkan objek yang di acu, bukan isi dari objek tersebut.

Untuk membandingkan isi objek tersebut  –  deep quality –  kita bisa menulis sebuah 

metode dengan nama sameCard.   

public static boolean sameCard (Card c1, Card c2) {
        return   (c1.suit   ==   c2.suit   &&   c1.rank   ==  
c2.rank);
}

Sekarang jika kita membuat dua objek yang berbeda yang berisi data yang sama, kita 

bisa   menggunakan   metode  sameCard  untuk   melihat   apakah   keduanya 

merepresentasikan kartu yang sama:
Card card1 = new Card (1, 11);

244
Card card2 = new Card (1, 11);

if (sameCard (card1, card2)) {
System.out.println   ("card1   and   card2   are   the  
same  card.");
}

Dalam kasus ini,  card1  dan  card2  adalah dua objek berbeda yang berisi data yang 

sama. 

Jadi, persyaratan (condition) di dalam kode di atas bernilai  True. Bagaimana bentuk 

diagram keadaan ketika card1 == card2 bernilai True?

Di bagian 7.10 saya mengatakan bahwa Anda sebaiknya jangan pernah menggunakan 

operator == dalam String karena operator ini sebenarnya tidak  mengerjakan apa yang 

Anda harapkan. Ketimbang membandingkan isi String (deep equality), kita lebih baik 

memeriksa apakah kedua String merupakan objek yang sama (shallow equality) ataukah 

tidak.  

11.5 Metode compareCard

Untuk tipe data­tipe data primitif, terdapat operator­operator kondisional yang dapat 

membandingkan nilai­nilai sekaligus menentukan nilai mana yang lebih besar daripada 

nilai   lainnya.   Operator­operator   ini   (<,  >,   dll)   tidak   bisa   digunakan   untuk   tipe­tipe 

245
objek.   Khusus   untuk   String,   ada   sebuah  metode  built­in  yang   dinamai  compareTo. 

Untuk Card, kita harus menulisnya sendiri. Metode ini akan kita sebut sebagai metode 

compareCard.   Berikutnya,   kita   akan   menggunakan   metode   ini   untuk   mengurutkan 

tumpukan kartu. 

Beberapa himpunan/kelompok (set)  data berada dalam keadaan yang memang sudah 

terurut. Ini artinya, Anda bisa membandingkan dua elemen apapun dari kelompok data 

tersebut   untuk   kemudian   langsung   mengatakan   elemen   mana   yang   lebih   besar   atau 

sebaliknya.   Angka­angka   yang   termasuk   ke   dalam   kelompok   tipe   data   integer   dan 

floating­point bisa Anda jadikan contoh dalam hal ini. Namun ada juga kelompok data 

yang tidak terurut secara alami (baca: tidak untuk diurutkan). Maksudnya, tidak ada 

cara   untuk   menyebutkan   bahwa   satu   elemen   lebih   besar   daripada   elemen   lainnya. 

Sebagai contoh, buah­buahan merupakan kelompok data yang tidak bisa atau memang 

tidak   untuk   diurutkan.   Hal   inilah   yang   menyebabkan   kita   tidak   akan   pernah   bisa 

membandingkan   buah   jeruk   dengan   buah   apel   menggunakan   sudut   pandang 

perbandingan   antara   dua   angka   seperti   pada   contoh   sebelumnya.   Dalam   Java,   tipe 

boolean juga tidak termasuk ke dalam kelompok tipe data terurut. Oleh karena itulah, 

kita tidak bisa menyebut True lebih besar daripada False.

Kelompok   kartu   yang   biasa   dimainkan   bisa   dianggap   sebagai   kelompok   data   yang 

terurut secara parsial. Maksudnya, terkadang kita memang bisa membandingkan dua 

kartu   tetapi   terkadang   malah   sebaliknya.   Contohnya,   saya   mengetahui   bahwa   kartu 

wajik dengan nomor 3 lebih tinggi daripada kartu wajik dengan nomor 2, dan kartu 

permata bernomor 3 lebih tinggi daripada kartu wajik bernomor sama. Tapi kartu mana 

yang   lebih   baik,   kartu   wajik   dengan   nomor   3   ataukah   kartu   permata   yang   hanya 

bernomor 2? Kartu pertama memiliki peringkat yang lebih tinggi, tapi kartu lainnya 

memiliki kelompok yang lebih tinggi.

246
Agar  kartu­kartu  ini bisa dibandingkan, kita harus memutuskan variabel mana yang 

lebih penting, variabel rank (peringkat) ataukah suit (kelompok). Jujur saja, dua pilihan 

di atas akan sangat tergantung dengan selera masing­masing individu. Namun untuk 

kasus   ini,   saya   berpendapat   bahwa   variabel  suit  lebih   penting,   karena   ketika   Anda 

membeli  satu set kartu,  kartu­kartu  itu tersusun dalam  susunan  di  mana kartu­kartu 

wajik ditempatkan di atas permata dan kelompok lainnya. Bukan disusun berdasarkan 

nomor kartu.

Dengan   keputusan   di   atas,   kita   bisa   menulis   metode  compareCard.   Di   sini   kita 

membutuhkan dua buah Card sebagai parameter, angka 1 sebagai nilai kembalian jika 

kartu yang ditulis pertama menang dan ­1 jika sebaliknya, serta 0 jika keduanya sama 

(dari segi isi/kandungan objek  Card  tersebut). Terkadang akan membingungkan juga 

jika kita selalu menggunakan ketiga nilai di atas sebagai nilai kembalian, tetapi fakta 

berkata   lain,   ketiga   nilai   tersebut   sebenarnya   telah   menjadi   standar   untuk   metode­

metode yang berhubungan dengan perbandingan.

Awalnya, kita akan membandingkan kartu­kartu tersebut berdasarkan kelompok:
if (c1.suit > c2.suit) return 1;
if (c1.suit < c2.suit) return ­1;

Jika kedua pernyataan di atas tidak ada yang bernilai True, maka kelompok­kelompok 

kartu tersebut tentunya bernilai sama. Jika ini yang terjadi, kita harus membandingkan 

peringkatnya:
if (c1.rank > c2.rank) return 1;
if (c1.rank < c2.rank) return ­1;

Jika kedua pernyataan di atas juga tidak bernilai True, maka peringkatnya tentu  sama, 

jadi kita akan mengembalikan nilai 0. Dalam model pemeringkatan seperti ini, kartu As 

247
akan dianggap lebih rendah daripada kartu dengan nomor 2.

Untuk   latihan,   perbaikilah   metode   di   atas   agar   kartu   As   bisa   bernilai   lebih   tinggi 

ketimbang kartu King, lalu enkapsulasilah kode Anda ini ke dalam sebuah metode.

11.6 Array berisi Card

Alasan saya memilih Card sebagai objek untuk bab ini adalah karena terdapat sebuah 

manfaat jelas yang bisa didapat dari array berisi kartu, yakni sebuah tumpukan. Berikut 

ini adalah lampiran kode untuk membuat sebuah tumpukan yang berisi 52 kartu.
Card[] deck = new Card [52];
Berikut ini adalah diagram keadaan untuk objek ini:

Hal penting yang harus dilihat di sini adalah bahwa array yang kita buat hanya berisi 

referensi ke objek; tapi tidak menampung objek­objek Card itu sendiri. Nilai­nilai dari 

elemen   array   diinisialisasi   dengan  null.   Anda   bisa   mengakses   elemen­elemen   array 

dengan cara yang sudah lazim dipakai:
if (deck[3] == null) {
System.out.println ("No cards yet!");
}

Tapi jika Anda mencoba mengakses variabel­variabel instan dari Card yang memang 

tidak   ada   atau   belum   dideklarasikan,   maka   Anda   akan   mendapatkan 

NullPointerException.

deck[2].rank; // NullPointerException
Tidak   perlu   diperdebatkan  lagi,  sintaks   di   atas   merupakan   sintaks   yang  tepat   untuk 

mengakses   kartu   dengan   nomor   2   yang   berada   dalam   tumpukan   (sebenarnya   yang 

248
ketiga – kita memulainya dari urutan ke­0 bukan?). Ini adalah contoh lain dari bentuk 

composition,   kombinasi   antara   sintaks   untuk   mengakses   satu   elemen   dalam   sebuah 

array dan sebuah variabel instan dari suatu objek. 

Cara termudah untuk mengisi suatu tumpukan dengan objek­objek Card adalah dengan 

menggunakan perulangan tersarang (nested loop):
int index = 0;
for (int suit = 0; suit <= 3; suit++) {
for (int rank = 1; rank <= 13; rank++) {
deck[index] = new Card (suit, rank);
index++;
   }
}

Perulangan bagian luar akan menghasilkan kelompok­kelompok kartu, mulai dari nol 

sampai dengan tiga (0 s.d. 3). Untuk setiap kelompok kartu, perulangan bagian dalam 

akan menghasilkan peringkatnya, yakni mulai dari 1 s.d. 13. Karena perulangan (loop) 

bagian luar dieksekusi 4 kali dan perulangan bagian dalam 13 kali, total eksekusi yang 

terjadi di dalam badan perulangan adalah 52 kali (sama dengan 13 x 4).

Saya menggunakan variabel index untuk melacak keberadaan kartu berikutnya di dalam 

tumpukan. Diagram keadaan berikut ini menunjukkan keadaan tumpukan setelah dua 

kartu dimasukkan:

249
Latihan 11.1

Enkapsulasilah   kode   pembuat   tumpukan   ini   ke   dalam   sebuah   metode   dengan   nama 

buildDeck  yang tidak menggunakan parameter dan menghasilkan sebuah array berisi 

kumpulan Card.

11.7 Metode printDeck

Ketika Anda bekerja dengan array, adalah sesuatu yang wajar untuk menulis sebuah 

metode   yang   akan   mencetak   isi   array   tersebut.   Sebelumnya   kita   telah   melihat   pola 

penelusuran   array   beberapa   kali.   Jadi,   Anda   seharusnya   sudah   cukup   akrab   dengan 

metode berikut ini:
public static void printDeck (Card[] deck) {
   for (int i=0; i<deck.length; i++) {
printCard (deck[i]);
   }
}

Karena parameter  deck  bertipe  Card[], elemen dalam  deck  akan bertipe  Card. Oleh 

karena itu, deck[i] merupakan argumen legal untuk metode printCard.  

250
11.8 Searching

Metode berikutnya yang ingin saya tulis adalah findCard. Metode ini akan melakukan 

pencarian di dalam array berisi Card untuk melihat apakah array tersebut memiliki kartu 

yang sedang dicari. Mungkin metode ini tidak jelas akan dimanfaatkan untuk apa, tapi 

hal ini justru memberikan kesempatan bagi saya untuk mendemonstrasikan dua cara 

untuk melakukan pencarian, yaitu linear search dan bisection search.

Teknik  linear search  lebih sering digunakan; teknik ini menggabungkan penelusuran 

tumpukan   dan   pembandingan   setiap   kartu   dengan   kartu   yang   kita   cari.   Ketika   kita 

menemukannya, kita akan mengembalikan indeks lokasi kartu tersebut. Tapi jika kita 

tidak menemukannya di dalam tumpukan, kita mengembalikan nilai ­1.
public   static   int   findCard   (Card[]   deck,   Card   card)  
{
    for (int i = 0; i< deck.length; i++) {
      if (sameCard (deck[i], card)) return i;
    }
    return ­1;
}

Argumen­argumen  findCard  kita namai dengan nama  card  dan  deck. Mungkin akan 

terlihat ganjil jika kita menggunakan sebuah variabel dengan nama yang sama dengan 

tipenya  (variabel  card  bertipe  Card).  Hal seperti ini adalah sesuatu yang legal dan 

lazim dipakai, meskipun terkadang hal ini justru akan membuat kode yang kita tulis 

menjadi   lebih   sulit   untuk   dibaca.   Namun   dalam   kasus   ini,   saya   kira   hal   ini   bisa 

berfungsi dengan baik.

Metode   ini   akan   langsung   mengembalikan   nilai   kembalian   ketika   kartu   yang   dicari 

sudah ditemukan. Ini berarti, kita tidak perlu menelusuri semua indeks dalam tumpukan 

jika   kartu   yang   dicari   sudah   ditemukan.   Jika   perulangan   yang   dilakukan   sudah 

251
dihentikan   tanpa   menemukan   kartu   yang   dicari,   kita   akan   segera   tahu   bahwa   kartu 

tersebut   tidak   berada   di   dalam   tumpukan.   Oleh   karena   itu,   metode   ini   akan 

mengembalikan nilai ­1.  

Jika kartu­kartu yang berada dalam tumpukan tidak berada dalam posisi yang terurut, 

maka tidak ada cara yang lebih cepat untuk melakukan pencarian ketimbang cara ini. 

Kita harus memeriksa setiap kartu karena tanpa ini, kita tidak akan bisa memastikan 

bahwa kartu yang kita cari memang benar­benar tidak ada di dalam tumpukan itu. 

Namun ketika Anda mencari sebuah kata di dalam kamus, Anda tidak mencari kata 

tersebut   secara   linear   atau   kata   demi   kata.   Hal   ini   terjadi   karena   kata­kata   tersebut 

berada   dalam   posisi   yang   sudah   terurut   secara   alfabetis.   Akibatnya,   Anda   mungkin 

menggunakan sebuah algoritma yang sama dengan bisection search:

1. Mulailah mencari dari bagian tengah.

2. Pilihlah   sebuah   kata   dalam   halaman   lalu   bandingkanlah   setiap   kata   tersebut 

dengan kata yang Anda cari.

3. Jika Anda menemukan kata yang Anda cari, berhenti.

4. Jika kata yang sedang Anda cari, secara alfabetis lebih besar daripada kata yang 

berada dalam halaman, pindahlah ke halaman berikutnya lalu kerjakan kembali 

langkah 2.

5.  Jika kata yang sedang Anda cari, secara alfabetis lebih kecil daripada kata yang 

berada dalam halaman, pindahlah ke halaman sebelumnya lalu kerjakan kembali 

langkah 2.

Jika Anda sudah menemukan dua kata yang  adjacent  (saling mengiringi, contohnya; 

kata  fakta  dengan  faktor) di suatu halaman dalam kamus tetapi Anda tidak mendapati 

kata yang Anda cari (misalnya;  fakto) yang seharusnya terletak diantara dua kata itu, 

Anda bisa menyimpulkan bahwa kata yang Anda cari tersebut tidak tercantum dalam 

kamus itu. Satu­satunya alternatif yang mungkin terjadi adalah kata yang sedang Anda 

252
cari   tidak   berada   dalam   berkas   kamus   tersebut,   tapi   ini   justru   kontradiktif   dengan 

asumsi yang ada; bahwa kata­kata sudah tersusun dalam keadaan terurut alfabetis.

Dalam kasus tumpukan kartu ini, jika kita tahu bahwa kartu­kartu tersebut berada dalam 

posisi yang terurut, kita bisa menulis metode findCard yang lebih cepat. Cara terbaik 

untuk menulis  bisection search  adalah dengan menggunakan teknik rekursif. Hal ini 

terjadi   karena  bisection  sebenarnya merupakan sesuatu yang secara alamiah  bersifat 

rekursif.

Trik   yang   digunakan   adalah   dengan   cara   menulis   sebuah   metode  findBisect  yang 

menggunakan   dua   indeks   sebagai   parameter,   yakni  low  dan  high,   yang   akan 

mengindikasikan segmen/zona dari array yang akan dikenai pencarian (termasuk dua 

parameter itu sendiri, low dan high).

1. Untuk mencari di dalam array, pilihlah sebuah indeks di antara  low  dan  high 

(berilah nama mid) lalu bandingkan dengan kartu yang sedang Anda cari.

2. Jika Anda telah menemukannya, hentikan pencarian.

3. Jika kartu yang berada dalam  mid  lebih tinggi daripada kartu yang Anda cari, 

carilah kartu tersebut di daerah dalam interval antara low hingga mid­1.

4. Jika kartu yang berada dalam mid lebih rendah daripada kartu yang Anda cari, 

carilah kartu tersebut di daerah dalam interval antara mid­1 hingga high.

Langkah 3 dan 4 kelihatan seperti sesuatu yang bersifat rekursif. Berikut ini adalah 

implementasinya dalam kode Java:
public   static   int   findBisect   (Card[]   deck,   Card  
card, int low, int high) {
   int mid = (high + low) / 2;
   int comp = compareCard (deck[mid], card);

253
   if (comp == 0) {
      return mid;
    } else if (comp > 0) {
      return findBisect (deck, card, low, mid­1);
    } else {
                  return   findBisect   (deck,   card,   mid+1,  
high);
    }
}

Ketimbang   memanggil   metode  compareCard  tiga   kali,   saya   lebih   memilih   untuk 

memanggilnya sekali lalu menyimpan hasilnya.

Meskipun kode ini merupakan inti (kernel) dari bisection search, tetapi kode ini masih 

menyisakan sesuatu yang janggal. Dalam kode di atas, terlihat bahwa jika kartu yang 

kita cari tidak berada di dalam tumpukan, metode ini akan berekursi selamanya. Kita 

membutuhkan   sebuah   cara   untuk   mendeteksi   kondisi   ini   dan   mengatasinya   dengan 

cepat (misalnya dengan cara mengembalikan nilai ­1).  

Cara   termudah   untuk   menyatakan   bahwa   kartu   Anda   tidak   berada   dalam   tumpukan 

adalah   jika   memang   benar­benar  tidak  ada   kartu   lagi   dalam   tumpukan.   Kondisi   ini 

terjadi ketika  high  lebih rendah daripada  low.  Sebenarnya, masih ada kartu di dalam 

tumpukan, itu pasti, namun yang saya maksudkan di sini adalah bahwa tidak ada kartu 

di dalam segmen tumpukan yang telah diindikasikan dengan low dan high.

Dengan tambahan baris seperti di bawah ini, metode ini akan bekerja dengan baik:
public   static   int   findBisect   (Card[]   deck,   Card  
card, int low, int high) {
System.out.println (low + ", " + high);

if (high < low) return ­1;

254
int mid = (high + low) / 2;
int comp = deck[mid].compareCard (card);
if (comp == 0) {
   return mid;
} else if (comp > 0) {
   return findBisect (deck, card, low, mid­1);
} else {
      return   findBisect   (deck,   card,   mid+1,  
high);
}
}

Saya menambahkan sebuah pernyataan print di awal metode agar saya bisa memantau 

urutan pemanggilan rekursif yang terjadi sekaligus meyakinkan diri saya sendiri bahwa 

metode ini akan sampai ke base case. 

Saya mencoba kode berikut ini:
Card card1 = new Card (1, 11);
System.out.println   (findBisect   (deck,   card1,   0,  
51));

Lalu saya mendapatkan hasil sebagai berikut:
0, 51
0, 24
13, 24
19, 24
22, 24
23

255
Kemudian saya buat sebuah kartu yang tidak berada di dalam tumpukan, yakni kartu 

permata bernomor 15. Saya mencoba untuk mencarinya, lalu saya mendapatkan hasil 

seperti ini:
0, 51
0, 24
13, 24
13, 17
13, 14
13, 12
­1
Uji coba ini belum membuktikan benar­tidaknya program ini. Bahkan tidak diketahui 

berapa jumlah uji coba yang harus dilakukan untuk memastikan     kebenaran program 

ini. Di lain pihak, dengan melihat beberapa contoh kasus sekaligus mempelajari kode 

tersebut, mungkin Anda bisa meyakinkan diri Anda sendiri.

Jumlah pemangilan rekursif yang terjadi bisa dibilang relatif kecil, antara 6 atau 7. Ini 

berarti   bahwa   kita   hanya   perlu   memanggil  compareCard  sebanyak   6   atau   7   kali. 

Bandingkan   dengan   52   kali   kemungkinan   pemanggilan   jika   kita   menggunakan 

pencarian linear. Secara umum,  bisection search  lebih cepat daripada  linear search. 

Bahkan untuk array dengan ukuran yang besar.

Dua kesalahan yang sering terjadi dalam program­program rekursif adalah kealpaan 

dalam memasukkan  base case  sehingga program tidak akan pernah menemui pemicu 

untuk   berhenti   melakukan   pemanggilan.   Kesalahan   seperti   ini   akan   menyebabkan 

terjadinya   pemanggilan   rekursi   yang   tidak   berhingga   (infinite   recursion).   Dalam 

keadaan   seperti   ini,   Java   (secara   otomatis)   akan   mengeluarkan 

StackOverflowException.

256
11.9 Tumpukan dan subtumpukan

Melihat kembali interface yang digunakan oleh metode findBisect
public   static   int   findBisect   (Card[]   deck,   Card   card,  
int low,  int  high)

mungkin masih masuk akal untuk menganggap tiga parameter di atas, yakni; deck, low, 

dan high, sebagai parameter tunggal yang menentukan sebuah subdeck. Cara berpikir 

seperti ini sebenarnya sudah lazim digunakan, dan terkadang saya menyebutnya sebagai 

parameter  abstrak   (abstract   parameter).   Maksud   saya   dengan   kata   'abstrak'   adalah 

sesuatu yang secara literal tidak termasuk ke dalam kode program, tetapi digunakan 

untuk mendeskripsikan fungsi dari program dalam level yang lebih tinggi.

Sebagai contoh, ketika Anda memanggil sebuah metode, lalu melewatkan sebuah array 

dengan batasan berupa variabel low dan high ke dalamnya, maka tidak akan  ada yang 

dapat   mencegah   metode   terpanggil   untuk   mengakses   bagian­bagian   dari   array   yang 

berada   di   luar   batas.   Jadi,   Anda   sebenarnya   tidak   mengirim   sebuah   subbagian   dari 

tumpukan;   sebaliknya,   Anda   benar­benar   mengirimkan   semua   tumpukan.   Namun 

selama si penerima bermain sesuai dengan aturan, saya kira masih masuk akal untuk 

menganggap tumpukan di atas sebagai sebuah subtumpukan, tentunya secara abstrak. 

Masih ada satu contoh lagi tentang abstraksi seperti ini yang mungkin bisa Anda temui 

dalam  subbab   9.7,  yakni  ketika   saya  menyebut­nyebut   mengenai  struktur   data   yang 

“kosong”.   Alasan   saya   menggunakan   tanda   petik   untuk   kata   kosong   adalah   untuk 

menyiratkan kepada Anda bahwa kata kosong di situ sebenarnya tidaklah terlalu tepat. 

Semua variabel sebenarnya memiliki nilai sepanjang program tersebut berfungsi. Ketika 

Anda   menciptakan   variabel­variabel   tersebut,   semua   sudah   diberi   dengan   nilai­nilai 

bawaan (default). Jadi, sejatinya tidak ada satu objek yang layak disebut sebagai objek 

yang kosong.

257
Tapi jika sebuah program bisa menjamin bahwa nilai terbaru dari sebuah variabel tidak 

pernah   dibaca sebelum ditulis, maka  nilai  terbaru tersebut termasuk  irrelevan.  Oleh 

karena itu, secara abstrak, dalam kondisi seperti ini, kita bisa saja menganggap variabel 

tersebut sebagai variabel yang “kosong”.

Cara berpikir seperti ini, di mana sebuah program dipersepsikan melebihi (beyond) apa 

yang bisa ditulis merupakan salah satu bagian penting dalam kerangka berpikir para 

ilmuwan   komputer   (computer   scientist).   Terkadang,   kata   “abstrak”   terlalu   sering 

digunakan.   Saking   seringnya,   sampai­sampai   ia   sering   kehilangan   maknanya   dalam 

berbagai   konteks   kalimat.   Walaupun   begitu,   abstraksi   merupakan   ide   utama   dalam 

dunia ilmu komputer (sebagaimana juga terjadi di bidang­bidang lainnya).

Definisi   abstraksi   yang   lebih   umum   adalah   sebagai   berikut;   “suatu   proses   yang 

bertujuan untuk memodelkan sebuah sistem kompleks dengan menggunakan deskripsi 

sederhana agar dapat menekan detail­detail yang tidak penting pada saat   menangkap 

perilaku­perilaku yang relevan.”

11.10 Daftar Kata­Kata

Istilah Arti
encode Merepresentasikan satu himpunan/set nilai dengan satu set nilai 

lainnya menggunakan pemetaan antara keduanya.
Shallow equality Kesamaan acuan. Dua pengacu (references) menunjuk ke objek 

yang sama.
Deep quality Kesamaan   nilai.   Dua   pengacu   (references)   yang   menunjuk   ke 

objek yang memiliki nilai yang sama.
Abstract  Satu  set parameter  yang  beraksi  bersama­sama  sebagai  sebuah 

parameter parameter.

abstraction Proses menginterpretasi/memaknai sebuah program (atau sesuatu 

258
yang   lain)   dengan   pemaknaan   yang   lebih   tinggi   daripada   apa 

yang direpresentasikan secara literal di dalam kode. 

11.11 Latihan

Latihan 11.2

Bayangkanlah  sebuah  permainan  kartu  yang  tujuannya  adalah untuk  mengumpulkan 

kartu­kartu dengan jumlah total sama dengan 21. Skor total untuk setiap pemain adalah 

skor  total dari semua kartu  yang ada dalam genggaman tangan pemain. Skor untuk 

masing­masing kartu  adalah sebagai  berikut: kartu  As  bernilai  1, semua  kartu yang 

bergambar (Jack, Queen, King) bernilai 10, sementara kartu­kartu yang lain diberi nilai 

sesuai dengan peringkatnya. Contoh: pemain yang memegang kartu As, 10, Jack, dan 3 

memiliki skor total sebesar 1 + 10 + 10 + 3 = 24.

Tulislah metode handScore yang menggunakan sebuah array berisi kartu­kartu sebagai 

argumen.   Nilai   yang   akan   dikembalikan   adalah   skor   total   dari   kartu­kartu   tersebut. 

Peringkat­peringkat kartu yang digunakan harus berdasarkan pada pemetaan yang ada 

dalam subbab 11.2, dengan kartu As sebagai kartu yang bernilai 1.

Latihan 11.3

Metode printCard yang ada dalam subbab 11.3 menggunakan sebuah objek Card dan 

mengembalikan sebuah string yang merepresentasikan kartu yang diminta.

Buatlah sebuah metode kelas untuk kelas Card dengan nama parseCard. Metode ini 

menggunakan sebuah String sebagai argumen dan mampu mengembalikan kartu yang 

terkait dengan String tersebut. Anda bisa mengasumsikan bahwa String tersebut berisi 

nama dari sebuah kartu dalam format yang valid seperti yang sudah dihasilkan oleh 

metode printCard.

259
Dengan kata lain, string itu akan berisi satu spasi di antara variabel rank dan kata “of”, 

dan di antara kata “of” dengan variabel suit. Jika string itu tidak berisi nama kartu yang 

legal, maka metode akan mengembalikan objek berisi null.

Tujuan   dari   latihan   ini   adalah   untuk   mengulang   konsep   tentang  parsing  dan 

mengimplementasikan   sebuah   metode   yang   dapat   mem­parse  suatu   string   yang 

ditentukan.

Latihan 11.4

Tulislah sebuah metode, suitHist, yang menggunakan sebuah array berisi kartu­kartu 

sebagai   parameter   dan   mengembalikan   sebuah   histogram   dari   kelompok­kelompok 

kartu yang berada di genggaman tangan seorang pemain. Solusi yang Anda gunakan 

hanya boleh menelusuri array sebanyak satu kali saja, tidak lebih!

Latihan 11.5

Tulislah   sebuah   metode  isFlush  yang   menggunakan   sebuah   array   berisi   kartu­kartu 

sebagai sebuah parameter dan mampu mengembalikan nilai True jika kartu­kartu yang 

sedang   dipegang   berstatus  flush,   dan  False  jika   sebaliknya.  Flush  adalah   sebuah 

keadaan  ketika  seorang  pemain   mempunyai  lima  atau  lebih  kartu   yang  berasal  dari 

kelompok yang sama.

260
Bab 12

Objek berisi Array

12.1 Kelas Deck

Dalam   bab   sebelumnya,   kita   sudah   bekerja   dengan   sebuah   array   yang   berisi   objek, 

tetapi   saya   juga   menyebutkan   bahwa   kita   juga   berkesempatan  memiliki   objek   yang 

berisi sebuah array sebagai sebuah variabel instan. Dalam bab ini kita akan membuat 

sebuah  objek baru, yakni  Deck, yang berisi sebuah array yang berisi  Card  sebagai 

variabel instannya.

Definisi kelasnya tampak sebagai berikut:
class Deck {
    Card[] cards;

    public Deck (int n) {
cards = new Card[n];
    }
}

Nama variabel instannya adalah cards.  Nama ini digunakan agar kita bisa membedakan 

antara objek  Deck  dengan array berisi  Card  yang dikandungnya. Berikut ini adalah 

diagram keadaan yang menunjukkan keadaan objek  Deck  ketika tidak ada satu pun 

kartu dimasukkan ke dalamnya.

261
Seperti biasa, konstruktor akan menginisialisasi variabel instan, tapi dalam kasus ini, 

konstruktor menggunakan perintah new untuk membuat sebuah array yang berisi kartu­

kartu.   Meskipun   begitu,   konstruktor   ini   tidak   membuat   kartu   yang   bisa   masuk   ke 

dalamnya.   Untuk   melakukannya,   kita   akan   menulis   konstruktor   lain     yang   akan 

membuat sebuah tumpukan berisi 52 kartu lalu mengisinya dengan objek­objek Card:

public Deck () {
   cards = new Card[52];
   int index = 0;
   for (int suit = 0; suit <= 3; suit++) {
for (int rank = 1; rank <= 13; rank++) {
  cards[index] = new Card (suit, rank);
     index++;
   }
  }
}

Perhatikan kemiripan metode di atas dengan metode buildDeck. Bedanya, di sini kita 

harus   sedikit   mengubah   sintaksnya   agar   bisa   digunakan   sebagai   konstruktor.   Untuk 

memanggilnya, kita akan menggunakan perintah new:

Deck deck = new Deck ();

Sekarang,   karena   kita   sudah   mempunyai   kelas  Deck,   kita   bisa   meletakkan   semua 

metode   yang   terkait   dengan  Deck  di   dalam   definisi   kelas  Deck.   Bila   kita   melihat 

kembali   semua   metode   yang   sudah   kita   tulis   sejauh   ini,   salah   satu   calon   metode 

262
(kandidat)  yang  bisa  dimasukkan  ke   dalam  definisi  kelas  adalah  metode  printDeck 

(subbab 11.7). 

Inilah  metode tersebut  setelah  ditulis ulang.  Hal  ini  dilakukan  agar  metode  ini  bisa 

berfungsi ketika dipakai oleh objek Deck:

public static void printDeck (Deck deck) {
    for (int i=0; i<deck.cards.length; i++) {
 Card.printCard (deck.cards[i]);
   }
}

Sesuatu yang paling jelas harus diganti adalah tipe parameternya, dari Card[] menjadi 

Deck.   Perubahan   kedua   adalah   bahwa   sekarang   kita   tidak   bisa   lagi   menggunakan 

perintah  deck.length  untuk mendapatkan panjang array. Hal ini terjadi karena  deck 

sekarang merupakan objek dari  Deck,  bukan sebuah array lagi.  deck  memang berisi 

array,   tapi   dia   sendiri   bukanlah   sebuah   array.   oleh   karena   itu,   kita   harus   menulis 

perintah deck.cards.length untuk mengekstrak array dari objek Deck untuk kemudian 

mengambil ukuran array tersebut.

Untuk   alasan   yang   sama,   kita   harus   menggunakan   perintah  deck.cards[i]  untuk 

mengakses sebuah elemen milik array,   bukan   dengan   perintah  deck[i].   Perubahan 

terakhir adalah bahwa pemanggilan printCard harus dilakukan secara eksplisit. Hal ini 

sebagai   bukti   bahwa   metode   ini   memang   benar­benar   didefinisikan   di   dalam   kelas 

Card.     

Untuk metode­metode yang lainnya, masih tidak jelas apakah mereka harus dimasukkan 

ke dalam kelas Card ataukah Deck. Sebagai contoh, findCard menggunakan argumen 

yang   terdiri   dari   sebuah  Card  dan  Deck.   Oleh   karena   itu,     Anda   sebenarnya   bisa 

263
meletakkan metode ini ke dalam salah satu kelas yang disebutkan. 

12.2 Shuffling

Untuk   permainan­permainan   kartu   yang   sering   dimainkan,   Anda   harus   mampu 

melakukan   pengacakan   (kocok)   satu   tumpukan   kartu.   Kegiatan   ini   disebut   dengan 

shuffling. Dalam subbab 10.6 kita telah melihat cara membuat bilangan acak, tapi Anda 

mungkin masih bingung untuk mengimplementasikannya ke dalam permainan kartu.

Satu   kemungkinan   yang   bisa   diambil   adalah   dengan   menggunakan   cara   kita   (baca: 

manusia)   ketika   mengacak   kartu.   Umumnya,   pengacakan   dilakukan   dengan   cara 

membagi tumpukan kartu ke dalam dua bagian. Setelah itu, kita akan menyusun ulang 

tumpukan itu dengan mengambil satu kartu secara acak dari dua tumpukan tersebut. 

Karena manusia tidak bisa mengacak dengan sempurna, setelah 7 kali pengulangan, 

biasanya   urutan   kartu   dalam   tumpukan   menjadi   tampak   seperti   benar­benar   tidak 

beraturan.   Pun   begitu   dengan   sebuah   program   komputer,   setelah   8   kali   melakukan 

pengacakan,   urutan   kartu   dalam   tumpukan   justru   kembali   ke   dalam   posisi   semula. 

Untuk   mendiskusikan   hal   seperti   ini,   silahkan   mengunjungi 

http://www.wiskit.com/marilyn/craig.html atau Anda bisa mencarinya di mesin pencari 

menggunakan kata kunci “perfect shuffle”. 

Algoritma pengacakan yang lebih baik adalah dengan cara menelusuri tumpukan kartu 

satu kali untuk kemudian memilih dua kartu lalu menukarnya dalam tiap perulangan. 

Berikut ini adalah ringkasan cara kerja algoritma ini. Untuk mendeskripsikan   program 

ini,   saya   akan   menggunakan   kombinasi   antara   pernyataan­pernyataan   dalam   Java 

dengan kata­kata dalam bahasa alamiah (baca: bahasa yang kita gunakan sehari­hari). 

Inilah yang disebut dengan pseudocode:

for (int i=0; i<deck.length; i++) {
  // pilihlah sebuah bilangan acak di antara i dan 

264
  //  deck.cards.len gth

  //  tukarkan  kartu  urutan  ke­ i dengan  kartu  yang  sudah  


  //  terpilih  secara  acak.
}

Hal positif ketika menggunakan pseudocode seperti di atas adalah bahwa terkadang kita 

dapat melihat metode yang akan kita butuhkan dengan lebih jelas. Dalam kasus ini, kita 

membutuhkan metode seperti randomInt, yang dapat memilih bilangan bertipe integer 

secara acak di dalam interval antara variabel low dan high. Selain itu, metode ini juga 

mampu mengambil dua indeks lalu menukar kartu yang berada pada posisi indeks yang 

terpilih.

Anda   mungkin  dapat   menulis metode  randomInt  dengan  melihat   subbab  10.6,  tapi 

Anda juga harus hati­hati terhadap indeks yang dihasilkan, karena mungkin  saja indeks 

tersebut keluar dari batasan interval.

Anda juga bisa membuat metode  swapCard  sendiri tentunya. Satu­satunya trik   yang 

akan Anda gunakan adalah apakah Anda hanya akan menukar referensi yang menunjuk 

ke posisi kartu atau Anda justru akan menukar juga isi dari kartu­kartu tersebut. Pilihan 

Anda akan sangat menentukan kecepatan program yang Anda buat secara keseluruhan.

Saya akan meninggalkan implementasi masalah ini sebagai latihan.

12.3 Pengurutan (Sorting)

Karena   sebelumnya   kita   telah   mengacak­acak   tumpukan   kartu,   sekarang   kita 

membutuhkan   suatu   cara   untuk   menempatkan   semuanya   kembali   ke   posisi   terurut. 

Ironisnya, ada sebuah algoritma untuk melakukan pengurutan yang sangat mirip dengan 

pengacakan. Algoritma ini sering disebut  selection sort.  Disebut demikian    karena ia 

265
bekerja   dengan   cara   menelusuri   array   secara   berulang­ulang   lalu   memilih   kartu 

terendah dalam setiap perulangan. 

Pada perulangan pertama, kita menemukan kartu terendah (the lowest) lalu menukarnya 

dengan kartu yang berada di posisi ke­0. Pada perulangan berikutnya, yaitu yang ke­i, 

kita akan mendapatkan kartu terendah di sebelah kanan i lalu menukarnya dengan kartu 

di indeks yang ke­i.

Berikut ini merupakan pseudocode dari selection sort:
for (int i=0; i<deck.length; i++) {
  
        //   temukan   kartu   terendah   yag   berada   dalam   i  
atau  
    // yang berada di daerah sebelah kanannya

        //   tukarlah   kartu   urutan   ke­i   dengan   kartu  


terendah
}

Lagi­lagi,  pseudocode  akan   menolong   kita   dengan   memakai   rancangan  helper 

methods. Dalam kasus ini, kita bisa menggunakan swapCards kembali, jadi kita hanya 

membutuhkan   satu   buah   metode   lagi,   yakni  findLowestCard.   Metode   ini 

membutuhkan sebuah array berisi  kartu­kartu  dan sebuah indeks  tempat di mana  ia 

pertama kali melakukan pencarian.

Sekali lagi, saya akan meninggalkan implementasinya khusus untuk pembaca.

12.4 Subtumpukan (Subdecks)

Apa yang harus kita lakukan untuk merepresentasikan kartu­kartu yang berada dalam 

266
genggaman tangan seorang pemain (Hand) atau beberapa bentuk subset lain dari satu 

tumpukan kartu yang penuh? Kemungkinan pertama adalah dengan cara menulis sebuah 

kelas baru dengan nama  Hand, yang mungkin akan mewarisi sifat­sifat kelas  Deck. 

Kemungkinan lainnya, yang akan saya tunjukkan di sini,   adalah merepresentasikan 

Hand menggunakan sebuah objek Deck yang jumlahnya kurang dari 52 kartu.

Kita mungkin membutuhkan sebuah metode, yaitu subdeck, yang menggunakan sebuah 

Deck dan sekumpulan indeks. Metode ini akan mengembalikan sebuah Deck baru yang 

berisi subset dari kartu­kartu yang telah ditentukan:
public   static   Deck   subdeck   (Deck   deck,   int   low,   int  
high) {
   Deck sub = new Deck (high­low+1);
      for (int i = 0; i<sub.cards.length; i++) {
      sub.cards[i] = deck.cards[low+i];
   }
   return sub;
}

Ukuran  subdeck  adalah  high­low+1.   Hal   ini   terjadi   karena   kita   juga   akan 

mengikutsertakan  kartu  terendah dan kartu  tertinggi.  Proses komputasi semacam ini 

bisa   menimbulkan  kebingungan,   dan  juga   bisa  membawa  kita  ke  dalam  error  yang 

termasuk  off­by­one   error.   Membuat   gambar   atau   visualisasi   merupakan   cara   yang 

ampuh untuk menghindarinya.

Karena  kita menyediakan sebuah argumen dengan peringkat  new, maka konstruktor 

yang dipanggil akan menjadi yang pertama, yang hanya mengalokasikan array tapi tidak 

mengalokasikan kartu apa pun. Di dalam perulangan  for, subtumpukan­subtumpukan 

akan dibuat beserta salinan referensi yang ada dalam tumpukannya.

267
Berikut   ini   merupakan   diagram   keadaan   sebuah   subtumpukan   yang   dibuat 

menggunakan parameter  low = 3 dan high = 7. Hasilnya adalah sebuah  hand berisi 5 

kartu   yang   saling   berbagi   referensi   dengan   tumpukan   utamanya;   Anda   dapat 

menganggap hand tersebut sebagai nama alias dari tumpukan.

Saya tidak menyarankan Anda untuk menggunakan konsep aliasing karena perubahan 

yang terjadi pada satu subtumpukan akan langsung memengaruhi subtumpukan lain. 

Kecuali kalau objek­objek yang akan dikenai  aliasing  tersebut merupakan objek yang 

tidak bisa diubah (immutable). Dalam kasus ini, kita tidak bisa mengubah peringkat atau 

kelompok sebuah kartu. Sebaliknya, kita justru akan membuat setiap kartu satu kali saja 

lalu memperlakukannya sebagai objek yang immutable. Dengan alasan ini, penggunaan 

aliasing untuk Card merupakan keputusan yang masih relevan. 

12.5 Pengacakan dan Pembagian Kartu (Shuffling and Dealing)

Dalam subbab 12.2 saya menulis pseudocode untuk algoritma pengacakan. Anggaplah 

saat   ini   kita   mempunyai   sebuah   metode   dengan   nama  shuffleDeck.   Metode   ini 

menggunakan   sebuah   tumpukan   sebagai   argumen   lalu   mengacaknya.   Kita   akan 

mengacak tumpukan dengan cara seperti berikut:
Deck deck = new Deck ();

268
shuffleDeck (deck);

Kemudian,   untuk   membagi/mendistribusikan   kartu   ke   beberapa  hand  lain,   kita   bisa 

menggunakan subdeck:

Deck hand1 = subdeck (deck, 0, 4);
Deck hand2 = subdeck (deck, 5, 9);
Deck pack = subdeck (deck, 10, 51);

Kode ini akan menempatkan 5 kartu di hand pertama, 5 kartu berikutnya di hand yang 

lain, dst. 

Pada saat Anda berpikir mengenai proses bagi­bagi kartu (dealing), apakah Anda juga 

berpikir mengenai pembagian kartu yang harus dilakukan secara satu per satu untuk 

setiap pemain, dengan teknik round­robin, laiknya permainan kartu dalam dunia nyata? 

Saya sempat kepikiran juga tentang ini, tapi kemudian saya menganggapnya sebagai 

sesuatu yang tidak terlalu penting ketika harus diimplementasikan ke dalam program 

komputer. Teknik  round­robin  digunakan untuk menghindari pengacakan yang tidak 

sempurna   sekaligus   kecurangan   yang   mungkin   dilakukan   oleh   sang   pembagi   kartu 

(dealer). Tetapi Anda tidak usah khawatir, isu di atas bukanlah masalah penting dalam 

dunia komputer.

Contoh ini dapat menjadi sebuah peringatan yang berguna terhadap salah satu metafora 

berbahaya   dalam   dunia   rekayasa   (engineering):   terkadang   kita   memaksa   komputer 

untuk mengerjakan hal­hal tidak perlu yang memang berada di luar kemampuannya, 

atau mengharapkan kemampuan­kemampuan dari komputer yang  sebenarnya memang 

tidak dimilikinya. Ini semua terjadi karena kita telah melebih­lebihkan sebuah metafora 

jauh di atas ambang batasnya sendiri. Berhati­hatilah terhadap penggunaan analogi yang 

salah.

269
12.6 Mergesort

Dalam subbab  12.3, kita telah melihat sebuah algoritma  pengurutan sederhana yang 

akhirnya   malah   menimbulkan   ketidakefisienan   bagi   program   itu   sendiri.   Untuk 

mengurutkan data sebanyak  n  item, algoritma ini harus menelusuri array sebanyak  n  

kali. Dan untuk setiap penelusuran, dibutuhkan waktu sejumlah n. Oleh karena itu, total 

waktu yang dibutuhkan dalam satu pemrosesan lengkap adalah n 2.

Dalam   bab   ini   saya   akan   memberikan   sebuah   algoritma   yang   lebih   efisien,   yakni 

mergesort. Untuk mengurutkan n item, mergesort membutuhkan waktu sebanyak n log  

n.   Mungkin   tidak   terlalu   bagus,   tapi   jika   nilai  n  bertambah   semakin   besar,   maka 

perbedaan antara  n2  dan  n log n  menjadi sangat signifikan. Cobalah dengan beberapa 

nilai n lalu lihat hasilnya.

Ide   dasar   dari  mergesort  adalah   sebagai   berikut:   jika   Anda   mempunyai   dua 

subtumpukan yang keduanya sudah dalam posisi terurut, maka Anda akan lebih mudah 

(juga cepat) untuk menggabungkannya ke dalam satu tumpukan tunggal yang terurut. 

Cobalah beberapa hal di bawah ini:

1. Buatlah dua subtumpukan yang masing­masing terdiri dari 10 kartu kemudian 

urutkanlah keduanya sehingga ketika keduanya saling berhadap­hadapan, kartu 

terendah akan berada di posisi teratas. Letakkan kedua subtumpukan tersebut 

tepat di depan muka Anda.

2. Bandingkan kartu teratas dari masing­masing subtumpukan lalu pilihlah yang 

terendah   di   antara   keduanya.   Tukarkan   posisi   keduanya   lalu   tempatkan 

keduanya ke dalam tumpukan baru yang akan menjadi tumpukan tunggal.

3. Ulangi   langkah   kedua   sampai   kartu­kartu   di   kedua   subtumpukan   itu   habis. 

Kartu­kartu yang sudah dikenai proses pada langkah kedua adalah kartu­kartu 

yang telah digabung ke dalam satu tumpukan tunggal.

270
Hasilnya adalah sebuah tumpukan tunggal yang terurut tentunya. Berikut ini merupakan 

pseudocode algoritma di atas:
public  static  Deck  merge  (Deck  d1,  Deck d2)  {

  /*   buat   sebuah   tumpukan   yang   cukup   besar   untuk  


menampung  
 semua  kartu  dari  dua subtumpuk an  */

  Deck   result   =   new   Deck   (d1.cards.len gth   + 


d2.cards.leng th);

 /* gunakan  indeks  i untuk  mengetahui  posisi  kita  dalam  


  tumpukan   yang   pertama,   dan   indeks   j   untuk   tumpukan  
kedua  */

 int  i = 0;
 int  j = 0;

 // indeks  k digunakan  untuk  menelusuri  tumpukan  result

 for  (int k  = 0;  k < result.car ds.len gth;  k++)  {


 
    //   jika   d1   kosong,   d2   menang;   jika   d2   kosong,   d1  
menang;
    //   jika   dua   kondisi   ini   tidak   terpenuhi,   bandingka n  
kartu­   
      kartu  yang berada  dalam  dua subtumpuka n
  //  masukkan  pemenangnya  ke  dalam  tumpukan  yang  baru

 }
 return  result;

271
}

Cara terbaik untuk menguji metode  merge  adalah dengan membuat sebuah tumpukan 

lalu   mengacaknya,   gunakan   subtumpukan   untuk   membuat   dua  hand  dengan   jumlah 

kartu   yang   sedikit,   lalu   gunakan   algoritma   yang   ada   di   bab   sebelumnya   untuk 

mengurutkan setiap subtumpukan milik  hand. Setelah selesai, Anda bisa melewatkan 

kedua subtumpukan milik  hand  ke metode  merge  untuk melihat apakah metode ini 

berhasil atau justru sebaliknya.

Jika   Anda   melihat   metode  merge  ini   berhasil   dengan   baik,   cobalah   implementasi 

sederhana dari metode mergeSort berikut ini:

public static Deck mergeSort (Deck deck) {
  
// temukan titik tengah tumpukan tersebut
// bagilah tumpukan itu menjadi dua subtumpukan
// urutkan kedua subtumpukan menggunakan  sortDeck
// gabungkan dua subtumpukan itu lalu kembalikan 
// hasilnya
}

Nah, kalau Anda juga berhasil mengimplementasikan kode di atas dengan benar, hal­hal 

yang menarik akan segera terjadi! Sesuatu yang ajaib dalam  mergesort  adalah fakta 

bahwa teknik ini melakukan proses yang bersifat rekursif. Di saat Anda mengurutkan 

subtumpukan­subtumpukan itu, Anda tidak perlu lagi repot­repot memanggil metode 

lama  yang   lebih   lambat.   Anda   cukup   menggunakan  metode  mergeSort  milik   Anda 

sendiri yang lebih keren di dalamnya.

Bukan hanya soal penggunaan pemikiran/ide yang bagus, langkah di atas sebenarnya 

kita lakukan agar kita dapat mencapai kinerja yang sebelumnya telah saya janjikan. 

272
Agar   dapat   berfungsi   dengan   baik,   Anda   harus   menambahkan  base   case  ke   dalam 

program Anda agar program itu tidak merekursif selamanya. Base case yang sederhana 

adalah subtumpukan yang berisi 0 atau 1 kartu. Jika mergeSort menerima subtumpukan 

seperti ini, ia bisa mengembalikan subtumpukan itu tanpa mengubahnya sama sekali 

karena subtumpukan seperti itu tentu berada dalam posisi yang sudah terurut.

Berikut ini adalah versi rekursif dari mergesort:
public static Deck mergeSort (Deck deck) {

  // if the deck is 0 or 1 cards, return it
  // find the midpoint of the deck
  // divide the deck into two subdecks
  // sort the subdecks using mergesort
  // merge the two halves and return the result
}
Seperti biasa, ada dua paradigma pengembangan untuk program yang bersifat rekursif; 

Anda bisa melihatnya dari sisi keseluruhan proses yang akan dieksekusi atau Anda juga 

bisa melihatnya sebagai sesuatu yang bisa dipilah­pilah menjadi bagian­bagian kecil. 

Saya   telah   mencontohkan   contoh­contoh   di   atas   agar   Anda   bisa   mempraktikkan 

paradigma kedua.

Ketika Anda menggunakan  sortDeck  untuk mengurutkan subtumpukan­subtumpukan, 

Anda tentu tidak merasa harus mengikuti dan memperhatikan keseluruhan proses yang 

dieksekusi   bukan?   Anda   hanya   perlu   menganggap   bahwa     metode  sortDeck  akan 

bekerja   dengan   baik   karena   Anda   telah   memeriksanya   (debug)   sebelum   digunakan. 

Well, sesuatu yang harus Anda lakukan jika ingin melihat mergeSort bersifat rekursif 

adalah dengan mengganti satu algoritma pengurutan dengan algoritma lainnya. Saya 

kira Anda tidak mempunyai alasan yang cukup bagus untuk melihat program ini dengan 

273
cara yang lain. 

Sebenarnya,   ketika   Anda   menulis   program­program   bersifat   rekursif,   Anda   harus 

memberikan perhatian lebih pada saat membuat base case. Base case tersebut haruslah 

benar dan bisa berfungsi dengan tepat. Selain faktor ini, membuat versi rekursif dari 

suatu program tentunya tidak akan menjadi masalah lagi untuk Anda. Semoga berhasil!

12.7 Daftar Kata­Kata

Istilah Arti
pseudocode Suatu  teknik untuk merancang program  komputer dengan 

cara   membuat   deskripsi   singkat   (rough   drafts)   program 

tersebut   menggunakan   kombinasi   antara   bahasa  natural 

(bahasa yang kita gunakan sehari­hari) dengan bahasa Java
Helper method Metode   kecil   yang   umumnya   tidak   melakukan   sesuatu 

secara signifikan untuk dirinya sendiri tetapi justru malah 

menolong metode lain agar metode tersebut dapat berfungsi 

lebih baik

12.8 Latihan

Latihan 12.1

Tulislah   sebuah   versi   metode  findBisect  yang   menggunakan   sebuah   subtumpukan 

sebagai   argumennya   ketimbang   menggunakan   sebuah   tumpukan   dan   interval   indeks 

(lihat subbab 11.8). Versi mana yang kira­kira lebih rawan dengan error? Versi mana 

yang menurut Anda lebih efisien?

Latihan 12.2

Dalam   versi   kelas  Card  sebelumnya,   sebuah   tumpukan   diimplementasikan   sebagai 

274
sebuah array yang berisi Card. Contoh; ketika kita melewatkan sebuah “deck” sebagai 

parameter, tipe parameter yang sebenarnya adalah Card[].

Dalam bab ini, kita telah mengembangkan sebuah representasi alternatif untuk sebuah 

tumpukan, yaitu sebuah objek dengan nama Deck yang mengandung sebuah array berisi 

kartu­kartu   sebagai   variabel   instannya.   Dalam   latihan   ini,   Anda   akan 

mengimplementasikan sebuah representasi baru untuk sebuah tumpukan.

a) Buatlah  file  tambahan dengan nama  Deck.java  ke dalam program Anda.  File  ini 

akan berisi semua definisi mengenai kelas Deck.

b) Buatlah  sebuah  konstruktor  untuk  kelas  ini  seperti  yang  telah ditunjukkan  dalam 

subbab 12.1.

c) Di antara metode­metode yang ada di dalam kelas Card, pilihlah metode yang sesuai 

dan   dapat   dijadikan   sebagai   anggota   kelas  Deck  yang   baru.   Pindahkan   metode­

metode   yang   Anda   pilih   tersebut   ke   dalam   kelas   baru   itu   lalu   buatlah   beberapa 

perubahan signifikan agar program Anda bisa di­compile  dan dieksekusi kembali 

dengan benar.  

d) Lihat kembali program tersebut kemudian identifikasilah setiap tempat ketika sebuah 

array   yang   berisi  Card  digunakan   untuk   merepresentasikan   sebuah   tumpukan. 

Modifikasilah   keseluruhan   program   sehingga   program   akan   menggunakan   objek 

Deck  daripada yang lainnya. Anda bisa melihat metode  printDeck  dalam subbab 

12.1 sebagai contoh.

Perubahan ini sebaiknya dilakukan dengan sistem  per metode. Jadi, di sini Anda 

diminta untuk langsung memeriksa perubahan yang terjadi setiap kali Anda telah 

selesai memodifikasi sebuah metode. Di sisi lain, jika Anda memang benar­benar 

yakin   dengan   apa   yang   Anda   lakukan,   Anda   juga   bisa   menggunakan   perintah 

search­and­replace.

275
Latihan 12.3

Tujuan   latihan   ini   adalah   untuk   mengimplementasikan   algoritma   pengacakan   dan 

pengurutan yang telah dipelajari dalam bab ini.

a) Tulislah metode swapCards yang menggunakan sebuah tumpukan (array yang berisi 

kartu­kartu) dan dua indeks. Metode ini berfungsi untuk menukar kartu­kartu yang 

berada dalam dua lokasi tersebut.

PETUNJUK: Metode ini harus menukar referensi yang mengacu ke dua kartu itu, 

bukan   isinya.   Cara   ini   tidak  hanya   memiliki   kinerja   lebih   cepat,   tapi   juga   dapat 

memudahkan   kita   ketika   harus   berhadapan   dengan   kasus   di   mana   kartu­kartu 

tersebut sedang disamarkan (aliasing). 

b) Tulislah metode  shuffleDeck  yang menggunakan algoritma di subbab 12.2. Anda 

mungkin ingin memanfaatkan randomInt yang ada di latihan 10.2.

c) Tulislah   metode  findLowestCard  yang   menggunakan  compareCard  untuk 

menemukan   kartu   terendah   di   dalam   interval   kartu­kartu   yang   diberikan   (antara 

lowIndex hingga highIndex).

d) Tulislah metode sortDeck yang menyusun satu tumpukan kartu dari kartu  terendah 

hingga yang tertinggi.

Latihan 12.4

Untuk membuat hidup para pengacak dan pembagi kartu (card­counter) semakin sulit, 

sekarang   banyak   kasino   yang   menggunakan   mesin   pengacak   yang   mengacak   kartu 

secara   secara   naik­satu   per   satu   (incremental   shuffling).   Ini   berarti,   setiap   selesai 

membagi kartu untuk satu pemain, kartu yang telah dibagi tersebut akan dikembalikan 

lagi   ke   dalam   tumpukan.   Kartu   ini   dikembalikan   lagi   ke   dalam     tumpukan   tanpa 

melakukan pengacakan ulang. Jadi, mesin hanya memasukkan kartu itu ke posisi lain 

secara acak.

276
Tulislah   metode  incrementalShuffle  yang   menggunakan   sebuah  Deck  dan   sebuah 

Card  sebagai   argumen.   Metode   ini   berfungsi   untuk   memasukkan   atau   menyisipkan 

kartu ke dalam tumpukan di posisi yang acak. Berikut ini merupakan contoh sebuah 

incremental algorithm. 

Latihan 12.5

Tujuan   latihan   ini   adalah   untuk   menulis   sebuah   program   yang   dapat   membuat 

permainan poker untuk beberapa  hand  secara acak lalu mengelompokkannya. Dengan 

cara  ini,  kita  dapat  memperkirakan   probabilitas  dari  masing­masing  hand.      Jangan 

khawatir jika Anda belum pernah memainkannya; saya akan memberi tahu semua yang 

perlu Anda ketahui.

a) Untuk   pemanasan,   tulislah   sebuah   program   yang   menggunakan  shuffleDeck  dan 

subdeck  untuk membuat dan mencetak masing­masing lima kartu yang berada di 

empat hand pemain poker yang sudah diacak. Bagaimana, sudah mengerti? Berikut 

ini adalah beberapa status  hand  dalam permainan poker, dalam posisi yang terurut 

naik:

pair: dua kartu dengan peringkat (rank) yang sama

two pair: dua pasang kartu dengan peringkat yang sama

three of a kind: tiga kartu dengan peringkat yang sama

straight: lima kartu dengan peringkat yang berurutan

flush: lima kartu dengan kelompok (suit) yang sama 

full house: tiga kartu dengan satu peringkat yang sama, dua kartu lainnya tidak sama

four of a kind: empat kartu dengan peringkat yang sama

straight flush: lima kartu yang peringkatnya berurutan dan tergabung dalam satu 

kelompok yang sama

277
b) Tulislah metode  isFlush  yang menggunakan sebuah  Deck  sebagai parameter  dan 

mengembalikan nilai bertipe boolean sebagai indikator apakah hand yang diperiksa 

berstatus flush ataukah bukan.

c) Tulislah   sebuah   metode  isThreeKind  yang   menggunakan   sebuah  hand  dan 

mengembalikan  sebuah  nilai  bertipe boolean   yang  mengindikasikan  apakah  hand  

tersebut termasuk Three Of A Kind ataukah bukan.

d) Tulislah sebuah perulangan yang menghasilkan beberapa ribu  hand dan memeriksa 

apakah hand­hand tersebut termasuk Flush ataukah Three Of A Kind. 

e) Tulislah   beberapa   metode   yang   bisa   menguji   status­status  hand  poker   lainnya. 

Beberapa diantaranya mungkin lebih mudah ketimbang lainnya. Mungkin akan lebih 

baik jika Anda menulis beberapa helper­method yang bisa digunakan secara umum 

untuk beberapa metode penguji sekaligus. 

f) Dalam beberapa permainan poker, masing­masing pemain akan mendapatkan tujuh 

kartu. Dari ketujuh kartu tersebut, mereka diizinkan untuk membuat kombinasi dari 

lima   kartu  saja.   Modifikasilah   program  Anda  agar  bisa  menghasilkan  hand  yang 

terdiri   dari   tujuh   kartu   sekaligus   menghitung   ulang   probabilitas   yang   mungkin 

terjadi.

Latihan 12.6

Sebagai   sebuah   tantangan   khusus   untuk   Anda,   pikirkanlah   sebuah   algoritma   yang 

mampu memeriksa  wild card  yang terdapat dalam  hand­hand  yang sedang bermain. 

Sebagai contoh, jika “deuces are wild”, ini berarti bahwa jika Anda mempunyai sebuah 

kartu dengan peringkat 2, Anda bisa menggunakan kartu ini untuk merepresentasikan 

kartu apa pun yang berada dalam tumpukan.

Latihan 12.7

Tujuan latihan ini adalah agar Anda bisa mengimplementasikan mergesort.

278
a) Dengan pseudocode yang ada di subbab 12.6, tulislah metode dengan nama merge. 

Ujilah metode ini sebelum Anda memasukkannya ke dalam metode mergeSort.

b) Tulislah versi sederhana dari  mergeSort, yakni yang mampu membagi tumpukan 

menjadi   dua.   Gunakan  sortDeck  untuk   mengurutkan   kedua   bagian   tersebut,   lalu 

gunakan metode merge untuk membuat sebuah tumpukan baru yang sudah terurut.

c) Tulislah   versi  mergeSort  yang   benar­benar   bersifat   rekursif.   Ingatlah   bahwa 

sortDeck  merupakan sebuah  modifier  sementara  mergeSort  adalah sebuah fungsi. 

Ini berarti bahwa keduanya dipanggil dengan cara yang berbeda:
sortDeck  (deck);  //  modifies  existing  deck
deck  = mergeSort  (deck);  // replaces  old  deck with  new

279
Bab 13

Pemrograman Berorientasi Objek

13.1 Bahasa Pemrograman dan Teknik­tekniknya

Ada begitu banyak bahasa pemrograman di dunia ini, begitu juga dengan teknik­teknik 

pemrograman   (sering   disebut   sebagai   paradigma).   Tiga   teknik   yang   sudah   muncul 

dalam buku ini antara lain; prosedural, fungsional, dan object­oriented. Meskipun Java 

sering disebut­sebut sebagai bahasa pemrograman berorientasi objek, tapi kita masih 

diperkenankan   untuk   menulis   program   dengan   teknik   mana   pun.   Teknik   yang   saya 

peragakan di sini termasuk teknik prosedural. Program­program Java yang sudah ada 

beserta   paket­paket   bawaan   Java   ditulis   menggunakan   gabungan   dari   ketiga   teknik 

tersebut. Bedanya, program­program dan paket­paket tersebut lebih cenderung ditulis 

menggunakan paradigma pemrograman berorientasi objek.

Bukan perkara mudah untuk mendefinisikan arti dari pemrograman berorientasi objek, 

namun   beberapa   poin   berikut   ini   bisa   Anda   jadikan   pegangan   untuk   melihat 

karakteristiknya:

● Definisi objek (yang berupa kelas­kelas) biasanya berkaitan dengan objek­objek 

yang berada di dunia  nyata.  Contoh; di  subbab  12.1, pembuatan kelas  Deck 

merupakan   langkah   menuju   penggunaan   konsep   pemrograman   berorientasi 

objek. 

● Metode­metode yang dibuat umumnya berupa metode objek (yang Anda panggil 

melalui objek) ketimbang metode kelas (yang bisa langsung Anda    panggil). 

Sejauh   ini,   semua   metode   yang   kita   tulis   merupakan   metode­metode   kelas. 

Dalam bab ini, kita akan mencoba menulis beberapa metode objek.

280
● Fitur bahasa yang sangat terkait dengan sifat pemrograman berorientasi objek 

adalah inheritance. Saya akan membahasnya dalam bab ini.

Akhir­akhir ini, pemrograman berorientasi objek menjadi sangat populer, dan bahkan 

ada   orang   yang   menganggapnya   sebagai   teknik   pemrograman   yang   lebih   hebat 

(superior) ketimbang teknik­teknik lainnya. Saya berharap bahwa dengan menyuguhkan 

kepada Anda cara menggunakan beberapa teknik yang lain berarti saya telah memberi 

Anda alat untuk memahami sekaligus mengevaluasi keabsahan klaim di atas.

12.3 Metode Objek dan Metode Kelas

Ada dua tipe metode dalam Java; metode kelas (class method) dan metode objek (object  

method). Sejauh ini, semua metode yang kita tulis termasuk ke dalam tipe metode kelas. 

Metode ini bisa dikenali dari keberadaan kata kunci static yang berada di baris pertama 

pada   tiap   metode.   Sementara   itu,   semua   metode   yang   tidak   mempunyai  static  bisa 

dianggap sebagai metode objek.

Meskipun kita belum menulis satu pun metode objek, sebenarnya kita telah memanggil 

beberapa   diantaranya.   Kapan   pun   Anda   memanggil   sebuah   metode   melalui   sebuah 

objek, maka itulah yang disebut dengan metode objek. Misalnya metode  charAt  dan 

semua metode yang kita panggil melalui objek String. 

Semua yang bisa ditulis sebagai metode kelas juga bisa ditulis sebagai metode objek. 

Begitu  pula  sebaliknya. Terkadang,  akan  tampak  lebih alamiah  untuk  menggunakan 

salah   satunya   saja.   Sebentar   lagi   kita   akan   melihat   bahwa   metode­metode   objek 

seringkali terlihat lebih singkat dan padat ketimbang metode­metode kelas.

13.3 Objek Terkini

Ketika   Anda   memanggil   sebuah   metode   melalui   sebuah   objek,   objek   tersebut   akan 

281
menjadi objek terkini (the current object). Di dalam metode ini, Anda bisa mengacu ke 

variabel instan milik objek terkini menggunakan namanya, tanpa harus menulis nama 

objek tersebut secara spesifik.

Selain itu, Anda juga bisa mengacu ke objek terkini menggunakan kata kunci this. Kita 

sebelumnya telah melihat  this  digunakan di dalam konstruktor. Faktanya, Anda bisa 

saja menganggap konstruktor­konstruktor sebagai metode objek yang bersifat khusus.

13.4 Bilangan Kompleks

Untuk contoh kasus, sepanjang bab ini kita akan mencoba membuat definisi kelas untuk 

bilangan kompleks. Bilangan kompleks banyak digunakan di lingkungan matematika 

dan   dunia   perekayasaan   (engineering).   Di   samping   itu,   banyak   juga     perhitungan­

perhitungan yang menggunakan aritmetika kompleks. 

Sebuah   bilangan   kompleks   merupakan   hasil   penjumlahan   antara   bilangan   real   dan 

bilangan imajiner. Bilangan ini biasanya ditulis dalam bentuk x + yi, di mana x adalah 

bilangan realnya, sementara y merupakan bilangan imajinernya. Notasi i sendiri adalah 

representasi dari akar ­1. Oleh karena itu, i * i = ­ 1. 

Kode berikut ini merupakan definisi kelas untuk tipe objek baru, Complex:

class Complex
{
    // instance variables
    double real, imag;

    // constructor
    public Complex () {
 this.real = 0.0; this.imag = 0.0;
    }

282
    // constructor
    public Complex (double real, double imag) {
 this.real = real;
       this.imag = imag;
    }
}

Harusnya tidak ada yang mengejutkan Anda dari lampiran kode ini. Variabel­variabel 

instannya bertipe double yang mewakili bilangan real dan imajiner. Kedua konstruktor 

di  atas   termasuk jenis konstruktor  yang sudah  lazim  dipakai: satu  konstruktor  tidak 

membutuhkan satu parameter pun dan meng­assign  nilai­nilai  default  untuk variabel­

variabel   instan,   sementara   konstruktor   lainnya   menggunakan   dua   parameter   yang 

identik dengan variabel instannya. Seperti yang sudah kita lihat sebelumnya, kata kunci 

this digunakan untuk mengacu ke objek yang sedang diinisialisasi.

Di dalam main, atau di mana pun kita ingin membuat objek Complex, kita mempunyai 

pilihan; untuk membuat objeknya dahulu lalu mengatur variabel­variabel instannya atau 

melakukan keduanya sekaligus pada saat yang bersamaan:
Complex x = new Complex ();
x.real = 1.0;
x.imag = 2.0;
Complex y = new Complex (3.0, 4.0);

13.5 Fungsi­fungsi dalam Bilangan Kompleks

Mari   kita   lihat   beberapa   operasi   yang   mungkin   akan   kita   kerjakan   untuk   mengolah 

bilangan­bilangan kompleks. Nilai absolut dari sebuah bilangan kompleks didapat dari 

283
hasil   x 2 y 2 . Metode abs adalah fungsi murni yang menghitung nilai mutlak. Bila 

ditulis dalam bentuk metode kelas, seperti inilah kodenya:
// class method
public static double abs (Complex c) {
    return   Math.sqrt   (c.real   *   c.real   +   c.imag   *  
c.imag);
}

Versi  abs  ini   menghitung   nilai   absolut   milik  c,   objek  Complex  yang   diterimanya 

sebagai   parameter.   Versi   lain   dari  abs  adalah   sebuah   metode   objek;   metode   ini 

menghitung  nilai absolut  milik  objek  terkini  (objek  yang  memanggil metode).  Oleh 

karena itu, metode ini tidak akan membutuhkan parameter apa pun.
// object method
public double abs () {
return Math.sqrt (real*real + imag*imag);
}

Saya   menghilangkan   kata   kunci  static  untuk   mengindikasikan   bahwa   metode   ini 

merupakan metode objek. Selain itu, saya akan menghilangkan parameter yang tidak 

diperlukan.  Di  dalam metode,  saya  bisa mengacu  ke  variabel  instan  real  dan  imag 

dengan namanya tanpa harus menyertakan suatu objek secara spesifik. Java mengetahui 

secara  implisit   bahwa   saya   sedang  mengacu   ke   variabel­variabel   instan   milik  objek 

terkini. Jika saya ingin membuatnya bersifat eksplisit, saya akan menambahkan kata 

kunci this:
// ob ject  met hod
publi c do uble  abs  () {
    ret urn   Math .sqr t   (t his. real   *   this. real   +   this. imag   * 

284
this. imag );
}

Tapi itu hanya akan menambah panjang kode ini, ketimbang membuatnya tampak lebih 

ringkas. Untuk memanggil metode ini, kita bisa memanggilnya melalui sebuah objek, 

sebagai contoh:
Compl ex y  = n ew C ompl ex ( 3.0,  4.0 );
doubl e re sult  = y .abs ();

13.6 Fungsi­fungsi lainnya dalam Bilangan Kompleks

Operasi lain yang mungkin akan kita perlukan adalah fungsi penjumlahan. Anda bisa 

menjumlahkan   bilangan­bilangan   kompleks   dengan   menjumlahkan   masing­masing 

bilangan dengan pasangannya  masing­masing; real dengan real dan imajiner dengan 

imajiner. Dalam bentuk metode kelas, bentuknya akan seperti berikut:
publi c st atic  Com plex  add  (Co mple x a,  Com plex  b) {
      r etu rn n ew C ompl ex ( a.re al +  b.r eal,  a.i mag +  b. imag );
}

Untuk memanggil metode ini, kita akan melewatkan kedua operan sebagai argumen:
Complex sum = add (x, y);
Dalam   bentuk   metode   objek,   metode   ini   hanya   perlu   satu   argumen   yang   akan 

ditambahkan ke objek yang sedang digunakan (current object). 
publi c Co mple x ad d (C ompl ex b ) {
     r etur n ne w Co mple x (r eal +  b. real , im ag +  b.i mag) ;
}

Lagi­lagi,   di   sini   kita   bisa   mengacu   ke   variabel   instan   milik   objek   terkini   secara 

implisit, tapi untuk mengacu ke variabel instan milik objek  b  kita harus menamai b 

285
secara eksplisit menggunakan notasi titik (dot). Untuk memanggil metode ini, Anda bisa 

memanggilnya   melalui   salah   satu   operan   lalu   melewatkan   operan   lainnya   sebagai 

argumen.
Complex sum = x.add (y);

Dari contoh­contoh ini, Anda bisa melihat bahwa objek terkini (this) bisa mengambil 

alih dari salah satu parameter. Karena alasan inilah objek terkini sering juga disebut 

sebagai parameter implicit.

13.7 Modifier

Seperti contoh­contoh sebelumnya, kita akan melihat metode  conjugate. Metode ini 

merupakan metode pengubah yang mentransformasikan sebuah bilangan  Complex  ke 

bentuk konjugasi kompleksnya. Konjugasi kompleks dari x + yi adalah  x ­ yi. 

Sebagai metode kelas, bentuknya akan menjadi seperti ini:
public static void conjugate (Complex c) {
    c.imag = ­c.imag;
}

Dalam bentuk metode objek, kodenya akan menjadi seperti ini:
public void conjugate () {
    imag = ­imag;
}

Mulai sekarang, Anda harusnya sudah paham bahwa mengubah suatu metode dari satu 

bentuk   ke   bentuk  lainnya  merupakan   proses   mekanis.  Dengan  sedikit  latihan,  Anda 

akan mampu melakukannya tanpa harus berpikir panjang terlebih dahulu. Hal ini akan 

bagus   sekali   karena   Anda   memang   sudah   seharusnya   tidak   perlu   terhambat   untuk 

286
menulis salah satu diantaranya.  Anda  harus akrab  dengan keduanya agar  Anda  bisa 

langsung memilih mana yang lebih cocok dengan operasi yang sedang Anda tulis.

Sebagai contoh, saya berpikir bahwa add harusnya ditulis sebagai metode kelas karena 

metode ini merupakan operasi simetris dari dua operan. Anda juga bisa menampilkan 

kedua operan sebagai parameter. Bagi saya, agak ganjil rasanya jika kita memanggil 

satu   metode   melalui   sebuah   operan   lalu   melewatkan   operan   lainnya   sebagai 

argumennya.

Di sisi lain, beberapa operasi sederhana yang digunakan untuk satu objek bisa ditulis 

dengan   baik   menggunakan   metode­metode   objek   (pun   jika   metode­metode   itu 

membutuhkan beberapa argumen tambahan).

13.8 Metode toString

Setiap   tipe   objek   mempunyai   sebuah   metode,   yakni  toString  yang   mampu 

menghasilkan   representasi   string   dari   objek   tersebut.   Ketika  Anda   mencetak   sebuah 

objek menggunakan  print  atau  println, Java akan memanggil metode  toString  milik 

objek tersebut. Versi default metode ini akan mengembalikan sebuah string yang berisi 

tipe objek beserta sebuah identifier unik (lihat subbab 9.6). Ketika Anda mendefinisikan 

sebuah tipe objek yang baru, Anda bisa meng­override perilaku (behaviour) default dari 

suatu metode dengan membuat sebuah metode baru yang perilakunya sesuai dengan 

keinginan Anda.

Berikut ini tampilan toString di dalam kelas Complex:

public String toString () {

     return real + " + " + imag + "i";

287
Tentu   saja,   tipe   kembalian   milik  toString  adalah  String.   Metode   ini   tidak 

membutuhkan parameter apa pun. Anda bisa memanggil  toString  dengan cara yang 

sudah biasa kita pakai:
Complex x = new Complex (1.0, 2.0);
String s = x.toString ();

atau Anda juga bisa memanggilnya langsung melalui println:

System.out.println (x);

Dalam kasus ini, outputnya adalah 1.0 + 2.0i.

Versi toString ini masih belum cukup baik jika bilangan imajinernya bernilai negatif. 

Sebagai latihan, buatlah sebuah versi yang lebih baik:

13.9 Metode equals

Ketika   Anda   menggunakan   operator   ==   untuk   membandingkan   dua   objek,   yang 

sebenarnya   Anda   maksudkan   adalah,   “apakah   dua   objek   ini   merupakan   objek   yag 

sama?”   Itu   dia,   apakah   kedua   objek   mengacu   ke   lokasi   yang   sama   dalam   memori. 

Untuk kebanyakan tipe, definisi di atas bukanlah definisi yang tepat untuk menjelaskan 

prinsip  kesamaan (equality). Sebagai contoh, dua bilangan kompleks dianggap sama 

jika bilangan real keduanya sama dan begitu pula dengan bilangan imajiner mereka. 

Mereka tidak harus berupa objek yang sama.

Ketika Anda mendefinisikan sebuah tipe objek yang baru, Anda bisa membuat definisi 

persamaan   sendiri   dengan   menulis  sebuah   metode   objek,   yaitu  equals.   Untuk   kelas 

Complex, bentuknya akan tampak sebagai berikut:   

public boolean equals (Complex b) {
     return (real == b.real && imag == b.imag);
}

288
Dari hasil konvensi, metode ini akan selalu menjadi metode objek yang mengembalikan 

nilai bertipe boolean.

Dokumentasi untuk equals di dalam kelas Object memberikan beberapa panduan yang 

harus Anda terapkan ketika Anda ingin membuat definisi persamaan Anda sendiri:

Metode equals mengimplementasikan sebuah relasi ekuivalensi:

● Refleksif: untuk setiap nilai yang diacu x, x.equals(x) harus bernilai true.

● Simetris:  untuk setiap nilai yang diacu x dan y,  x.equals(y) harus bernilai true 

jika dan hanya jika  y.equals(x) juga bernilai true.

● Transitif:  untuk setiap nilai yang diacu x, y dan y, jika x.equals(y) bernilai true 

dan y.equals(z) juga bernilai true maka x.equals(z) juga harus bernilai true.

● Konsisten:  untuk setiap nilai yang diacu x dan y, pemanggilan berulang­ulang 

x.equals(y)  harus   bernilai  true  secara   konsisten,   atau   bernilai  false  secara 

konsisten.

● Untuk setiap nilai yang diacu x, x.equals(null) harus bernilai false.

Definisi equals  yang saya berikan sudah memenuhi semua persyaratan di atas kecuali 

satu. Yang mana? Sebagai latihan, coba perbaiki!

13.10 Memanggil Satu Metode Objek dari Metode Objek Lain

Seperti yang Anda harapkan, Java mengizinkan Anda untuk memanggil satu metode 

objek   dari   metode   objek   lainnya.   Sebagai   contoh,   untuk   menormalisasi   bilangan 

kompleks, Anda akan membagi kedua bagian berdasarkan nilai mutlaknya. Sebenarnya 

masih tidak cukup jelas kenapa ini bisa bermanfaat, inilah kenyataannya.

Mari   kita   tulis   metode  normalize  sebagai   sebuah   metode   objek,   lalu   membuatnya 

sebagai modifier.

289
public void normalize () {
double d = this.abs();
real = real/d;
imag = imag/d;
}

Baris   pertama   akan   menemukan   nilai   mutlak   milik   objek   terkini   dengan   cara 

memanggil  abs  melalui objek terkini. Dalam kasus ini, saya menyebut objek terkini 

secara   eksplisit,   meski   pun   sebenarnya   saya   juga   bisa   melewatkannya.   Jika   Anda 

memanggil satu metode objek melalui metode objek lainnya, Java akan mengasumsikan 

bahwa Anda sedang memanggil metode tersebut melalui objek terkini.

Latihan 13.1

Tulis­ulang lah  normalize agar menjadi fungsi murni. Lalu tulis­ulang lah metode ini 

agar bisa menjadi metode kelas.

13.11 Keganjilan dan Error

Jika Anda mempunyai metode objek dan metode kelas dalam satu definisi kelas yang 

sama, Anda justru akan lebih sering menjadi bingung. Cara yang lazim dipakai untuk 

mengelola suatu definisi kelas adalah dengan meletakkan semua konstruktor di awal­

awal kode, diikuti dengan semua metode objek lalu baru menuliskan semua metode 

kelasnya.

Anda dapat memiliki sebuah metode objek dan metode kelas dengan nama yang sama 

selama keduanya tidak sama dalam jumlah dan tipe parameter yang digunakan. Seperti 

lazimnya sebuah  overloading, Java akan menentukan versi mana yang dipanggil oleh 

pengguna dengan melihat argumen yang akan dilewatkan.

Sekarang, karena kita sudah tahu apa maksud dan manfaat dari kata kunci static, Anda 

290
mungkin berpendapat bahwa  main  termasuk metode kelas., yang juga berarti bahwa 

tidak ada “objek terkini” ketika metode ini sedang dipanggil.

Karena   objek   terkini   tidak   boleh   ada   dalam   sebuah   metode   kelas,   Anda   akan 

menghasilkan  error  jika   bersikeras   menggunakan   kata   kunci  this.   Jika   Anda 

mencobanya, Anda akan mendapatkan pesan error yang berbunyi: “Undefine variable: 

this”. Selain itu, Anda juga tidak akan bisa mengacu ke variabel instan tanpa notasi dot 

dan nama objeknya. Jika masih berani mencobanya, Anda akan mendapatkan pesan: 

“Can't make a static reference to non static variable ....”. Pesan ini sebenarnya bukanlah 

pesan  error  yang baik karena masih menggunakan bahasa yang di luar standar. Tapi 

jika   Anda   sudah   paham   apa   maksudnya,   otomatis   Anda   juga   akan   mengerti   apa 

maksudnya.

13.12 Inheritance

Kemampuan   suatu   bahasa   yang   paling   sering   dikaitkan   dengan   pemrograman 

berorientasi   objek   adalah  inheritance.   Inheritance   adalah   suatu   kemampuan   untuk 

mendefinisikan  sebuah  kelas baru  yang merupakan hasil  modifikasi dari  kelas yang 

sebelumnya telah didefinisikan (termasuk kelas­kelas built­in).

Manfaat utama dari fitur ini adalah agar Anda dapat menambahkan metode­metode atau 

variabel­variabel   instan   baru   ke   dalam   kelas   yang   sudah   ada   tanpa   harus 

memodifikasinya. Hal ini sangat berguna jika Anda hendak melakukan sesuatu terhadap 

kelas­kelas built­in yang memang tidak bisa diubah­ubah meski pun Anda sangat ingin 

melakukannya.

Disebut  inheritance  karena   kelas   yang   baru   akan   mewarisi  (inherit)   semua   variabel 

instan dan metode yang ada dalam kelas yang sudah ada terlebih dahulu itu. Dengan 

menggunakan   analogi   di   atas,   kelas­kelas   yang   sudah   ada/eksis   terlebih   dahulu   itu 

291
sering disebut dengan kelas­kelas induk (parent class).

13.13 Lingkaran yang bisa digambar 

Berikut   ini   merupakan   satu   contoh   inheritance,   di   sini   kita   akan   mengambil   kelas 

Rectangle  yang   sudah   kita   buat   sebelumnya   lalu   kita   beri   tambahan   agar   “bisa 

digambar”. Kita akan membuat sebuah kelas baru yang bernama  DrawableRectangle 

yang akan mewarisi semua variabel instan dan metode milik kelas Rectangle. Ditambah 

sebuah metode draw yang akan mengambil sebuah objek Graphics sebagai parameter 

lalu menggambar lingkaran yang kita inginkan. 
import java.awt.*;

class DrawableRectangle extends Rectangle {
    public void draw (Graphics g) {
  g.drawRect (x, y, width, height);
    }
}

Ya, itulah keseluruhan definisi kelas yang kita maksud. Baris pertama mengimpor paket 

java.awt yang menjadi tempat di mana Rectangle dan Graphics didefinisikan.

Baris   berikutnya   mengindikasikan   bahwa  DrawableRectangle  diwariskan   dari 

Rectangle.   Kata   kunci  extends  digunakan   untuk   mengidentifikasi   kelas   yang   kita 

warisi, yang dalam hal ini kita sebut sebagai kelas induk (parent class).

Sisanya adalah definisi dari metode draw, yang mengacu ke variabel instan x, y, width 

dan  height. Mungkin akan terkesan ganjil jika kita mengacu ke variabel instan yang 

tidak   tampak   dalam   definisi   kelas,   tapi   ingatlah   bahwa   mereka   sebenarnya   sudah 

diwariskan oleh kelas induk. 

292
Untuk   membuat   dan   menggambar   sebuah  DrawableRectangle,   Anda   bisa 

menggunakan kode berikut ini: 

public   static   void   draw   (Graphics   g,   int   x,   int   y,  


int width, int height) {
DrawableRectangle   dr   =   new   DrawableRectangle  
();
dr.x = 10; dr.y = 10;
dr.width = 200; dr.height = 200;
dr.draw (g);
}

Parameter­parameter   dalam  draw  adalah   sebuah   objek  Graphics  dan   kotak   untuk 

menampilkan gambar lingkaran (bukan koordinat­koordinat lingkaran tersebut).

Lagi­lagi, mungkin akan terkesan ganjil bila menggunakan perintah new untuk sebuah 

kelas  yang  tidak mempunyai  konstruktor.  DrawableRectangle  mewarisi konstruktor 

bawaan (default) milik kelas induknya, jadi tidak ada masalah di sana.

Kita   bisa   men­set  variabel   instan   milik  dr  lalu   memanggil   metode­metode   melalui 

dirinya   sendiri   dengan   cara   yang   sudah   biasa   kita   lakukan   sebelumnya.   Ketika   kita 

memanggil  grow  atau   metode­metode   lain   milik  Rectangle  melalui  dr,   Java   akan 

menggunakan metode yang sudah didefinisikan dalam kelas induk. 

13.14 Hierarki Kelas

Dalam Java, semua kelas cenderung memperluas beberapa kelas yang sudah ada. Kelas 

yang   paling   dasar   adalah  Object.   Kelas   ini   tidak   mengandung   variabel   instan   tapi 

menyediakan metode equals dan toString untuk kelas lainnya.

Banyak   sekali   kelas   yang   memperluas  Object,   termasuk   hampir   semua   kelas   yang 

293
sudah   kita  tulis  dan   kelas­kelas  bawaan   seperti  Rectangle.  Semua  kelas   yang  tidak 

menuliskan nama kelas induknya secara eksplisit akan mewarisi kelas  Object  secara 

default.

Bagaimana pun juga, beberapa rantai pewarisan ada yang lebih panjang dari apa yang 

kita perkirakan. Sebagai contoh, di Appendix D.6, di situ kita melihat bahwa kelas Slate 

merupakan perluasan dari kelas Frame, yang merupakan perluasan dari kelas Window, 

lalu   berturut­turut  Container,  Component,   sampai   ke   kelas  Object.   Tidak   peduli 

seberapa panjang rantai pewarisan ini, Object merupakan induk dari semua induk kelas 

yang ada.  

Semua kelas dalam Java bisa dikelola ke dalam sebuah “silsilah keluarga” (family  tree) 

yang disebut hierarki kelas (class hierarchy).  Object  biasanya muncul di bagian atas, 

dengan   semua   “anak”   yang   berada   di   bawahnya.   Jika   Anda   melihat   dokumentasi 

mengenai Frame, sebagai contoh, Anda akan melihat hierarki yang menyusun silsilah 

kelas Frame.

13.15 Rancangan Berorientasi Objek

Inheritance  merupakan fitur yang sangat bagus (powerfull). Beberapa program yang 

seringkali   kompleks   tanpanya,   bisa   ditulis   secara   lugas   dan   sederhana   dengannya. 

Selain itu, inheritance bisa memfasilitasi pemakaian ulang suatu kode (code reuse). Ini 

karena Anda memiliki kesempatan untuk mengkustomisasi perilaku kelas­kelas built­in  

tanpa harus mengubahnya. 

Di sisi lain, inheritance juga dapat menyebabkan suatu program lebih sulit dibaca. Hal 

ini   terjadi   jika   kodenya   ditulis   tanpa   adanya   kejelasan;   kapan   sebuah   metode   bisa 

dipanggil, di mana mencari definisinya. Sebagai contoh, salah satu metode yang bisa 

Anda panggil melalui Slate adalah getBounds. Bisakah Anda menemukan dokumentasi 

294
mengenai   metode   ini?   Saking   sulitnya   mencari   dokumentasi   untuk   metode   ini, 

terkadang kita malah beranggapan bahwa jangan­jangan dokumentasinya terdapat di 

induk dari induk dari induk dari induk Slate.

Dan jangan lupa, banyak hal­hal yang bisa dikerjakan dengan konsep inheritance juga 

bisa dikerjakan sama baiknya (bahkan lebih) jika dikerjakan tanpanya.

13.16 Daftar Kata­Kata

Istilah Arti
Metode   yang   dipanggil   melalui   sebuah   objek,   yang 

beroperasi dengan objek itu, yang diacu menggunakan kata 
object method
kunci  this  dalam   Java   atau   “objek   terkini”  dalam   bahasa 

Indonesia.
Metode   dengan   kata   kunci  static.   Metode   kelas   tidak 

class method dipanggil   melalui   objek­objek   dan   mereka   juga   tidak 

memiliki kaitan dengan objek terkini.
Objek tempat di mana sebuah metode objek dipanggil. Di 
current object
dalam metode, objek ini diacu dengan kata kunci this.
this Kata kunci yang mengacu ke objek terkini
Semua   yang   tidak   dituliskan   atau   diungkapkan   secara 

langsung.   Di   dalam   sebuah   metode   objek,   Anda   bisa 


implicit
mengacu   ke   variabel   instan   secara   implisit   (tanpa 

menyebutkan nama objek yang Anda maksud).
Semua yang dituliskan atau dinyatakan secara lengkap. Di 

explicit dalam   metode   kelas,   semua   referensi   yang   mengacu   ke 

variabel instan harus dinyatakan secara eksplisit.

295
13.17 Latihan

Latihan 13.2

Ubahlah metode kelas berikut ini ke dalam bentuk metode objek.
public static double abs (Complex c) {
    return   Math.sqrt   (c.real   *   c.real   +   c.imag   *  
c.imag);
}

Latihan 13.3

Ubahlah metode objek berikut ini ke dalam bentuk metode kelas.
public boolean equals (Complex b) {
    return (real == b.real && imag == b.imag);
}

Latihan 13.4

Latihan ini merupakan lanjutan dari latihan 9.3. Tujuannya adalah untuk melatih Anda 

menulis sintaks metode objek dan membuat Anda akrab dengan beberapa pesan error 

yang relevan dengan masalah ini.

a) Ubahlah   metode­metode   kelas   yang   ada   dalam   kelas   Rational   ke   bentuk   metode 

objek. Lalu buatlah perubahan seperlunya dalam metode main.

b) Buatlah beberapa kesalahan! Cobalah memanggil metode kelas dengan cara yang 

sama   seperti   ketika   Anda   memanggil   metode   objek.   Lalu   lakukan   hal   yang 

sebaliknya. Cobalah mencari tahu hal­hal mana yang legal dan mana yang tidak. 

Selain itu,  pelajari juga pesan­pesan error yang Anda  dapat  ketika Anda  sengaja 

mengacaukan keadaan.

c) Pikirkan mengenai pro dan kontra yang menyelimuti penggunaan dua tipe metode 

296
ini; kelas dan objek. Tipe mana yang lebih jelas (secara umum)? Cara mana yang 

lebih alami untuk mengekspresikan komputasi (atau, agar lebih adil dan jelas, tipe 

komputasi seperti apa yang bisa diekspresikan paling baik menggunakan masing­

masing bentuk)?

297
Bab 14

Linked List

14.1 Acuan­acuan dalam Objek

Di  dalam bab sebelumnya kita sudah melihat bahwa variabel­variabel instan sebuah 

objek dapat berupa array dan atau juga objek.

Satu kemungkinan yang paling menarik adalah bahwa sebuah objek bisa berisi sebuah 

acuan yang mengacu ke objek lain yang sama tipenya. Ada sebuah struktur data yang 

akan mengambil manfaat besar dari fitur ini; list.

List terbuat dari dari kumpulan node yang dalam setiap node­nya berisi suatu acuan ke 

node berikutnya dalam list. Selain itu, setiap node biasanya berisi satu unit data yang 

disebut cargo. Dalam contoh pertama kita, kargo ini berupa integer tunggal. Namun di 

kesempatan berikutnya kita akan menulis sebuah list  generic  yang dapat menyimpan 

objek dari tipe apapun.

14.2 Kelas Node

Seperti  biasa,   ketika   kita   menulis  sebuah   kelas   baru,   kita  akan   memulainya   dengan 

variabel   instan.   Lalu   dengan   satu   atau   dua   konstruktor   baru   kemudian   diteruskan 

dengan pembuatan metode toString agar kita bisa menguji mekanisme dasar dalam hal 

pembuatan dan penyajian tipe baru tersebut.
public class Node {
int cargo;
Node next;

298
public Node () {
cargo = 0;
next = null;
}

public Node (int cargo, Node next) {
   this.cargo = cargo;
   this.next = next;
  }

public String toString () {
   return cargo + "";
}
}

Deklarasi untuk variabel­variabel instan sudah mengikuti spesifikasi yang ada secara 

alami,   sementara   sisanya   tinggal   menyesuaikan   dengan   variabel   instan.   Ekspresi 

cargo   +   ""   sebenarnya  agak­agak  aneh,   tapi  justru  inilah  cara  terbaik     untuk 

mengkonversi sebuah integer menjadi String.

Untuk menguji implementasi ini, kita akan meletakkan kode seperti ini dalam main:

Node node = new Node (1, null);
System.out.println (node);

Hasilnya adalah
1
agar tambah menarik, kita membutuhkan sebuah list yang terdiri dari dua atau lebih 

node!
Node node1 = new Node (1, null);

299
Node node2 = new Node (2, null);
Node node3 = new Node (3, null);

Kode ini menghasilkan tiga node tapi kita masih belum memiliki list karena node­node 

tersebut  belum   kita  hubungkan   (linked).   Diagram   keadaannya   akan   tampak   sebagai 

berikut:

Untuk   menghubungkan   node­node   itu,   kita   harus   merancang   kode   sedemikian   rupa 

sehingga node pertama akan mengacu ke node kedua, sementara node kedua mengacu 

ke node ketiga.
node1.next = node2;
node2.next = node3;
node3.next = null;

Acuan   milik   node   ketiga   adalah   null.   hal   ini   mengindikasikan   bahwa   node   ini 

merupakan akhir dari list. Sekarang diagram keadaannya akan tampak sebagai berikut:

Sekarang kita semua sudah tahu cara membuat node­node sekaligus bagaimana cara 

menghubungkannya agar menjadi list.  Apa yang mungkin kurang jelas sampai saat ini 

300
adalah kenapa.

14.3 List sebagai Collection

Sesuatu yang menyebabkan list bermanfaat adalah karena list merupakan suatu teknik 

untuk   merangkai   objek­objek   yang   berbeda   menjadi   satu   entitas   tunggal,   biasanya 

diistilahkan dengan collection. Dalam contoh ini, node pertama dari list akan bertindak 

sebagai acuan untuk keseluruhan list.

Jika   kita   ingin   melewatkan   list   sebagai   parameter   maka   yang   harus   kita   lewatkan 

hanyalah  acuan   yang  mengacu   ke   node  pertama.   Sebagai   contoh,   metode  printList 

menggunakan satu node sebagai argumennya. Dimulai dari bagian kepala (head) list, 

metode ini mencetak setiap node sampai selesai (ditandai dengan acuan yang berupa 

null).
public static void printList (Node list) {
    Node node = list;
    
    while (node != null) {
  System.out.print (node);
  node = node.next;
    }

    System.out.println ();
}

Untuk   memanggil   metode   ini,   kita   hanya   perlu   melewatkan   sebuah   acuan   ke   node 

pertama:
printList (node1);

Di dalam  printList, kita mempunyai sebuah acuan yang mengarah ke node pertama 

301
dalam   list,   tapi   tidak  ada   variabel   yang   mengacu   ke   node­node   lainnya.   Kita   harus 

menggunakan nilai next dari setiap node untuk mendapatkan node berikutnya.

Diagram berikut ini menunjukkan nilai list dan nilai yang diambil oleh node:

Pergerakan   untuk   menelusuri   sebuah   list   seperti   ini   sering   disebut   dengan   istilah 

traversal.   Sama   seperti   pola   penelusuran   yang   telah   kita   lakukan   terhadap   elemen­

elemen  suatu array. Adalah hal yang biasa/lazim  untuk menggunakan variabel  loop  

seperti node untuk mengacu ke setiap node dalam list secara beruntun.

Hasil metode ini adalah
123
Jika   menggunakan   konvensi   yang   sudah   ada,   list   sebaiknnya   dicetak   dalam   tanda 

kurung (parentheses) dengan koma di antara masing­masing elemen, misalnya (1, 2, 3). 

Untuk   latihan   Anda,   ubahlah  printList  sedemikian   sehingga   ia   bisa   menghasilkan 

output seperti format di atas.

Untuk   tambahan,   tulis­ulanglah  printList  menggunakan   perulangan  for  ketimbang 

memakai while. 

14.4 List dan Rekursi

Rekursi dan list berjalan seiring­seirama laksana fava beans dan chianti yang nikmat. 

Sebagai contoh, berikut ini merupakan algoritma untuk mencetak sebuah list dari bagian 

302
belakang:

1. Pisahlah list ke dalam dua bagian: node pertama (sebagai kepala (head)) dan 

sisanya (sebagai ekor (tail)).

2. Cetak ekornya dari belakang.

3. Cetak kepalanya.

Tentu saja, langkah kedua, pemanggilan rekursinya, mengasumsikan bahwa kita sudah 

mempunyai suatu cara untuk mencetak list dari belakang. Tapi jika kita menganggap 

bahwa pemanggilan rekursi ini bekerja dengan baik – leap of faith – barulah kita boleh 

yakin kepada diri kita sendiri kalau algoritma ini telah bekerja dengan baik dan benar.

Yang   kita   butuhkan   adalah  base   case,   lalu   sebuah   cara   untuk   membuktikan   bahwa 

untuk setiap list yang kita gunakan, kita akan bisa kembali lagi ke  base case. Pilihan 

paling wajar untuk base case adalah sebuah list dengan satu elemen tunggal, tapi akan 

lebih   baik kalau  kita mau  menggunakan list kosong,  yang direpresentasikan  dengan 

null.
public static void printBackward (Node list) {
if (list == null) return;

Node head = list;
Node tail = list.next;

printBackward (tail);
System.out.print (head);
}

Baris pertama merupakan base case yang tidak mengembalikan nilai apapun. Dua baris 

berikutnya   memecah   list   menjadi   dua;  head  dan  tail.   Sementara   dua   baris   terakhir 

digunakan untuk mencetak list itu sendiri.

303
Kita   memanggil   metode   ini   dengan   cara   yang   sama   seperti   ketika   kita   memanggil 

printList:

printBackward (node1);

Hasilnya adalah sebuah backward list. 

Bisakah kita membuktikan bahwa metode ini pasti akan selalu bisa dihentikan? Dengan 

kata   lain, apakah ia  akan selalu  sampai  menuju  base  case? Sayangnya,  jawabannya 

adalah tidak. Ada beberapa list yang justru akan membuat lumpuh metode ini.

14.5 Infinite List

Tidak akan ada yang dapat mencegah sebuah node untuk mengacu kembali ke node 

sebelumnya dalam list, tidak terkecuali node itu sendiri. Sebagai contoh, gambar berikut 

ini menunjukkan sebuah list dengan dua node, satu di antaranya mengacu ke dirinya 

sendiri.

Jika kita memanggil  printBackward, metode ini akan terus melakukan rekursi tanpa 

henti. Perilaku semacam ini akan membuat kita sulit bekerja dengannya.

Tapi   meskipun   begitu,   mereka   sebenarnya   seringkali   berguna.   Contohnya,   kita   bisa 

merepresentasikan   suatu   bilangan   dalam   bentuk   list   yang   berisi   digit­digit,   lalu 

menggunakan infinite list untuk merepresentasikan bagian atau angka­angka (fraction) 

yang berulang (muncul lebih dari 1 kali). 

Terlepas   dari   semua   itu,   sangat   disayangkan   karena   kita   tidak   dapat   membuktikan 

304
bahwa printList dan printBackward bisa dihentikan. Hal terbaik yag bisa kita lakukan 

adalah mengeluarkan pernyataan bersifat hipotesis (hypotetical statement), “jika suatu 

list tidak berisi perulangan, maka metode ini akan berhenti”. Klaim seperti ini disebut 

precondition. Klaim ini menekankan pada satu hambatan yang terdapat dalam salah 

satu   parameter   lalu   mendeskripsikan   perilaku   metode   tersebut   jika   hambatan   yang 

dimaksud muncul. Kita akan melihat contoh lain sesaat lagi.

14.6 Teorema Ambiguitas Fundamental

Ada bagian dalam  printBackward  yang mungkin akan membuat Anda mengangkat 

kedua alis:
Node head = list;
Node tail = list.next;

Setelah argumen pertama,  head  dan  list  mempunyai tipe dan nilai yang sama. Lalu 

kenapa saya membuat satu variabel baru? 

Alasannya adalah karena kedua variabel tersebut memiliki fungsi yang berbeda. Kita 

menganggap head sebagai sebuah acuan yang mengacu ke node tunggal, sementara tail, 

kita menganggapnya sebagai acuan yang mengacu ke node pertama dalam list. “Aturan­

aturan” ini memang bukan bagian dalam program; tapi keduanya ada dalam benak sang 

programmer.

Assignment  kedua membuat sebuah acuan baru ke node kedua dalam list, tapi dalam 

kasus   ini   kita   menganggapnya   sebagai   sebuah   list.   Jadi,   meskipun  head  dan  tail 

memiliki tipe yang sama, keduanya tetap memainkan peran yang berbeda.

Ambiguitas seperti ini sangat bermanfaat, tapi dapat menyebabkan program­program 

dengan list justru sulit dibaca. Saya sering menggunakan nama­nama variabel seperti 

305
node  dan  list  untuk   mendokumentasikan   bagaimana   saya   menggunakan   sebuah 

variabel,   dan   terkadang   saya   juga   membuat   variabel   tambahan   agar   tidak   terjadi 

ambiguitas lagi.

Saya bisa menulis  printBackward  tanpa  head  dan tail, tapi saya pikir hal ini justru 

akan membuatnya semakin sulit untuk dibaca:
public static void printBackward (Node list) {
if (list == null) return;

printBackward (list.next);
System.out.print (list);
}

Ketika kita melihat pemanggilan dua fungsi, kita harus ingat bahwa  printBackward 

memperlakukan   argumennya   sebagai   sebuah   list   sementara  print  memperlakukan 

argumennya sebagai sebuah objek tunggal.

Ingatlah mengenai teorema ambiguitas fundamental:

Sebuah variabel yang mengacu ke sebuah node mungkin akan memperlakukan node  

tersebut sebagai sebuah objek tunggal atau sebagai node pertama dalam list.

14.7 Metode Objek Untuk Node­Node

Anda   mungkin   akan   heran   kenapa  printList  dan  printBackward  masuk   ke   dalam 

golongan metode kelas. Saya sudah membuat klaim sebelumnya bahwa semua yang 

bisa ditulis sebagai metode kelas juga bisa ditulis sebagai metode objek; masalahnya 

adalah format mana yang Anda anggap lebih jelas.

Dalam kasus ini terdapat sebuah alasan bagus kenapa kita sampai menggunakan metode 

objek. Adalah suatu yang legal mengirimkan null sebagai argumen ke metode kelas, 

306
tapi adalah hal sebaliknya untuk memanggil sebuah metode objek melalui objek null.
Node node = null;
printList (node); // legal
node.printList (); // NullPointerException

Pembatasan ini justru membuat kita akan tampak aneh ketika hendak menulis kode 

pemanipulasi list yang bersih dalam paradigma berorientasi objek. Tapi  nanti, kita akan 

melihat cara untuk menyelesaikan masalah ini.

14.8 Memodifikasi List

Satu cara yang jelas­jelas bisa dipakai untuk memodifikasi sebuah list adalah dengan 

mengubah kargo salah satu node yang ada. Namun, operasi yang lebih menarik adalah 

dengan cara menambahkan, menghilangkan, atau mengubah urutan node­node tersebut.

Sebagai   contoh,   kita   akan   menulis   sebuah   metode   yang   dapat   menghilangkan   node 

kedua dalam list lalu memberikan hasil yang berupa acuan ke node yang dihilangkan. 
public static Node removeSecond (Node list) {
Node first = list;
Node second = list.next;

// make the first node refer to the third
first.next = second.next;

//   separate   the   second   node   from   the   rest   of  


the  // list
second.next = null;
return second;
}

307
Lagi­lagi, di sini saya menggunakan variabel temporer agar kode di atas lebih mudah 

dibaca. Berikut ini adalah cara menggunakan metode ini.
printList (node1);
Node removed = removeSecond (node1);
printList (removed);
printList (node1);

Hasilnya adalah 
(1, 2, 3) the original list
(2) the removed node
(1, 3) the modified list

Berikut   ini  adalah  diagram   keadaan  yang  menunjukkan  efek  yang   ditimbulkan  oleh 

operasi ini.

Apa yang akan terjadi jika memanggil metode ini lalu melewatkan sebuah list yang 

hanya berisi satu elemen (satu singleton)? Apa yang terjadi jika melewatkan list kosong 

sebagai sebuah argumen? Adakah precondition untuk metode ini?

14.9 Wrappers dan Helpers

Untuk beberapa operasi list, akan sangat berguna jika kita pisahkan metode ini menjadi 

308
dua.   Sebagai   contoh,   untuk   mencetak   satu   list   dari   belakang   dalam   bentuk   yang 

konvensional, yakni (3, 2, 1), kita bisa menggunakan printBackward untuk mencetak 

3,  2, tapi kita membutuhkan satu metode terpisah untuk mencetak tanda kurung dan 

node pertamanya. Kita akan menyebutnya printBackwardNicely.

public   static   void   printBackwardNicely   (Node   list)  


{
System.out.print ("(");

if (list != null) {
   Node head = list;
   Node tail = list.next;
   printBackward (tail);
   System.out.print (head);
}
System.out.println (")");
}

Kembali,   adalah   ide   yang   bagus   untuk   memeriksa   metode­metode   seperti   ini   untuk 

melihat apakah mereka benar­benar berfungsi dengan kondisi­kondisi khusus seperti list 

kosong atau sebuah singleton.

Di  bagian manapun dalam program, ketika kita menggunakan metode ini, kita akan 

memanggil printBackwardNicely lalu ia akan memanggil printBackward untuk kita. 

Dalam   kondisi   seperti   ini,  printBackwardNicely  bertindak   sebagai  wrapper. 

Sementara printBackward, yang berada dalam printBackwardNicely, disebut sebagai 

helper.

309
14.10 Kelas intList

Ada   beberapa   masalah   serius   dan   penting   terkait   dengan   cara   kita   dalam 

mengimplementasikan list. Dalam hukum sebab akibat yang selalu berubah­ubah, saya 

akan memperlihatkan sebuah cara alternatif untuk mengimplementasikan listnya dahulu 

baru   kemudian   menjelaskan   kepada   Anda   semua   masalah   apa   yang   dapat 

diselesaikannya.

Pertama­tama, kita akan membuat sebuah kelas baru, IntList. Variabel instan kelas ini 

adalah sebuah integer yang berisi panjang list dan sebuah acuan ke node pertama dalam 

list. Objek­objek IntList bertindak sebagai manipulator list milik objek­objek Node. 

public class IntList {
int length;
Node head;

public IntList () {
   length = 0;
        head = null;
}
}

Satu  hal bagus mengenai kelas IntList adalah karena ia dapat memberi kita tempat, 

secara   alami,   untuk   meletakkan   fungsi   pembungkus   (wrapper)   seperti 

printBackwardNicely di mana bisa membuat sebuah metode objek dalam kelas IntList.

public void printBackward () {
System.out.print ("(");

if (head != null) {

310
   Node tail = head.next;
   Node.printBackward (tail);
   System.out.print (head);
}
System.out.println (")");
}

Untuk   membuatnya   menjadi   semakin   membingungkan,   saya   menamai   ulang 

printBackwardNicely.   Nah,   karena   sekarang   ada   dua   metode   dengan   nama 

printBackward: satu ada dalam kelas Node (helper) sementara satunya lagi berada di 

dalam   kelas  IntList  (wrapper).   Agar   wrapper   bisa   memanggil   helper,   ia   harus 

mengidentifikasi kelasnya secara eksplisit (Node.printBackward). 

Jadi, satu keuntungan dari kelas IntList adalah karena ia dapat menyediakan tempat 

yang   bagus   untuk   meletakkan   fungsi­fungsi   pembungkus   (wrapper).   Keuntungan 

lainnya adalah karena ia dapat memudahkan kita untuk menambah atau menghilangkan 

elemen pertama dalam list. Sebagai contoh,  addFirst  merupakan metode objek milik 

IntList; metode ini menggunakan sebuah int sebagai argumennya lalu meletakkannya 

ke posisi pertama dalam list.
public void addFirst (int i) {
Node node = new Node (i, head);
head = node;
length++;
}

Seperti   biasa,   untuk   memeriksa   kode   seperti   ini,   adalah   hal   yang   bagus   untuk 

memikirkan beberapa kasus khusus. Seperti, apa yang terjadi jika list pada awalnya 

311
sudah diinisialisasi dalam keadaan kosong? 

14.11 Invariants

Beberapa   list   memang   sudah   berada   dalam  keadaan   yang   “well­formed”,  sementara 

yang  lain  tidak. Sebagai   contoh,  jika sebuah  list  berisi  sebuah  perulangan,  ini  akan 

menyebabkan   rusaknya   beberapa   metode   yang   sudah   kita   buat.   Jadi,   mungkin   kita 

menginginkan agar list kita tidak berisi perulangan sama sekali. Syarat lainnya adalah 

bahwa nilai  length  dalam objek  IntList  harus sama dengan jumlah node yang berada 

dalam list.

Persyaratan   seperti   ini   disebut  invariants  karena,   idealnya,   mereka   harusnya   selalu 

bernilai  true  untuk semua objek sepanjang waktu. Menentukan  invarian  untuk objek­

objek   merupakan   praktik  pemrograman  yang  bermanfaat  karena  dapat   memudahkan 

kita ketika hendak meningkatkan tingkat kebenaran suatu kode, memeriksa integritas 

struktur data yang digunakan, dan mendeteksi error.

Satu   hal   yang   sering   membingungkan   mengenai  invarian  adalah   bahwa   mereka 

terkadang justru dilanggar dalam kode program. Contohnya, di tengah addFirst, setelah 

kita   menambahkan   nodenya,   tapi   sebelum   kita   menaikkan   nilai  length,   invariannya 

justru dilanggar. Pelanggaran seperti ini masih bisa diterima; kenyataannya, terkadang 

mustahil bagi kita untuk memodifikasi sebuah objek tapa melanggar sebuah invarian 

meskipun itu untuk sesaat saja. Normalnya, persyaratan yang harus disertakan adalah 

bahwa   semua   metode   yang   melanggar   suatu   invarian   harus   bisa 

mengembalikan/memperbaikinya (restore) lagi.

Jika ada sesuatu yang signifikan dalam kode sehingga suatu invarian ternyata dilanggar, 

adalah   penting   bagi   komentar   untuk   menjelaskannya,   sehingga   tidak   akan   ada   lagi 

operasi yang bergantung kepada invarian tersebut.

312
14.12 Daftar Kata­Kata

Istilah Arti
Struktur   data   yang   mengimplementasikan   sebuah   koleksi 

list menggunakan   sekumpulan   node­node   yang   saling 

terhubung.
Suatu   elemen   dalam   list,   biasanya   diimplementasikan 

node sebagai sebuah objek yang berisi acuan ke objek lain yang 

sama tipenya.
cargo Item data yang dikandung sebuah node.

link Sebuah acuan objek yang dimasukkan ke dalam objek.

generic data structure Sejenis struktur data yang berisi data dari tipe apapun.
Sebuah fakta yang harus bernilai  true  agar sebuah metode 
precondition
bisa bekerja dengan baik.
Sebuah fakta yang seharusnya bernilai  true  untuk sebuah 

invariant objek   sepanjang   waktu   (kecuali   mungkin   ketika   objek 

tersebut sedang dimodifikasi).
Sebuah   metode   yang   bertindak   sebagai   penengah   antara 

sebuah   metode   pemanggil   (caller)   dan   metode   penolong 


wrapper method
(helper   method),   seringkali   berupa   interface   yang   lebih 

bersih ketimbang metode penolongnya.

14.13 Latihan

Latihan 14.2

Mulailah dengan mengunduh file IntList.java dari http://thinkapjava/code/IntList. Link 

ini berisi definisi­definisi mengenai IntList dan Node dari bab ini, bersama kode yang 

313
mendemonstrasikan dan menguji beberapa metode. Compile lalu eksekusi program itu. 

Hasilnya akan tampak sebagai berikut:
(1, 2, 3)
(3, 2, 1)

Latihan berikut ini meminta Anda untuk menulis metode objek tambahan bagi kelas 

IntList. Tetapi mungkin Anda ingin menulis beberapa metode penolong dalam kelas 

Node seperti biasa.

Setelah Anda menulis masing­masing metode, tambahkan kode itu ke dalam main lalu 

ujilah.   Yakinlah   untuk   menguji   beberapa   kasus   khusus   seperti   list­list   kosong   atau 

singleton.

Untuk setiap metode, identifikasilah semua precondition yang diperlukan agar semua 

metode bisa berfungsi dengan benar lalu tambahkan komentar yang akan bisa menjadi 

dokumentasi untuknya. Komentar Anda juga harus mengindikasikan apakah masing­

masing metode merupakan konstruktor, fungsi, ataukah modifier.

a) Tulislah metode  removeFirst  yang mampu menghapus node pertama dari sebuah 

list. Metode ini mampu mengembalikan kargo yang dimiliki oleh list tersebut.

b) Tulislah metode set yang menggunakan sebuah index, i, dan sebuah item dari kargo. 

Metode ini mampu menukar kargo node urutan ke­i dengan kargo yang diberikan.

c) Tulislah metode add yang menggunakan sebuah index, i, dan sebuah item dari kargo. 

Metode ini akan menambahkan sebuah node baru yang berisi kargo yang diberikan 

ke posisi i.

d) Tulislah   metode  addLast  yang   menggunakan   sebuah   item   dari   kargo   lalu 

menambahkannya ke posisi buncit dalam list.

e) Tulislah metode reverse yang bisa memodifikasi IntList, yang dapat memutar­balik 

urutan node­node yang ada di dalamnya.  

314
f) Tulislah   metode  append  yang   menggunakan  sebuah   IntList   sebagai   parameter. 

Metode ini bisa menambahkan salinan dari node­node yang ada dalam parameter list 

(list yang menjadi parameter) ke posisi buncit dari list yang sedang aktif dipakai saat 

itu (current list).

g) Tulislah   metode  checkLength  yang  mengembalikan  nilai  true  jika  panjang  field 

yang ada sama dengan jumlah node yang ada dalam list, dan  false  jika sebaliknya. 

Metode ini tidak boleh menyebabkan terjadinya exception di bawah kondisi apapun, 

dan ia harus bisa berhenti bahkan jika list tersebut berisi perulangan.

Latihan 14.2

Satu   cara   untuk   merepresentasikan   angka   yang   sangat   besar   adalah   dengan 

menggunakan   sebuah   daftar   (list)   berisi   digit­digit,   yang   biasanya   disimpan   dalam 

posisi yang sudah terurut. Sebagai contoh, angka 123 akan direpresentasikan dengan list 

(3, 2, 1). 

Tulislah   sebuah   metode   yang   membandingkan   dua   bilangan   yang   direpresentasikan 

sebagai IntList dan yang bisa mengembalikan 1 jika bilangan pertama yang lebih besar, 

­1 jika yang kedua lah yang lebih besar, dan 0 jika keduanya sama.

315
Bab 15

Stacks

15.1 Tipe Data Abstrak 

Semua tipe data yang telah kita lihat sejauh ini merupakan tipe data konkret. Artinya, 

kita   harus   menentukan,   dengan   lengkap,   bagaimana   tipe   data­tipe   data   tersebut 

diimplementasikan.   Sebagai   contoh,   kelas  Card  merepresentasikan   sebuah   kartu 

menggunakan   dua   integer.   Sebagaimana   yang   telah   saya   kemukakan   sebelumnya, 

teknik   di   atas   bukanlah   satu­satunya   cara   untuk   merepresentasikan   sebuah   kartu; 

sebenarnya masih banyak cara lain untuk mengimplementasikannya.

Abstract   Data   Type  (Tipe   Data   Abstrak),   atau  ADT,   merupakan   suatu   kumpulan 

operasi   (atau   metode)   dan   bentuk   semantik   dari   operasi­operasi   tersebut   (apa   yang 

dilakukan   oleh   operasi)   tapi   dia   tidak   menentukan   implementasi   operasi­operasi   itu 

sendiri. Hal inilah yang membuat mereka abstrak. 

Kenapa ADT berguna?

● ADT   menyederhanakan   tugas   Anda   ketika   hendak   menentukan   sebuah 

algoritma jika Anda bisa mengidentifikasi operasi­operasi yang Anda butuhkan 

tanpa harus berpikir pada saat yang bersamaan mengenai bagaimana operasi­

operasi tersebut akan dikerjakan.

● Karena ada banyak alternatif cara untuk mengimplementasikan ADT, mungkin 

akan berguna bagi kita untuk menulis sebuah algoritma yang bisa digunakan 

untuk beberapa implementasi sekaligus.

● Varian­varian   ADT   yang   sudah   populer,   seperti  Stack   ADT  dalam   bab   ini, 

sering diimplementasikan di dalam pustaka standar (standard library) sehingga 

316
mereka bisa ditulis sekali dan langsung digunakan oleh banyak programmer. 

● Operasi­operasi   ADT   menyediakan   sebuah   level   bahasa   tingkat­tinggi   yang 

umum digunakan untuk memilih, menentukan, dan membahas suatu algoritma.

Ketika   kita   berbicara   mengenai   ADT,   kita   sering   membedakan   antara   kode   yang 

menggunakan ADT, disebut  client code, dari kode yang mengimplementasikan ADT, 

disebut  provider code  karena kode ini menyediakan sebuah kumpulan standar yang 

terdiri dari layanan­layanan.

15.2 The Stack ADT

Dalam bab ini, kita akan melihat salah satu ADT yang sudah banyak dikenal, yakni 

stack. Stack merupakan suatu koleksi (collection). Ini artinya, stack adalah struktur data 

yang berisi lebih dari satu elemen. Koleksi lain yang sudah kita lihat sebelumnya antara 

lain; array dan list.

Seperti yang sudah saya sebutkan, sebuah ADT didefinisikan dengan suatu  kumpulan 

yang terdiri dari operasi­operasi. Stack bisa melakukan operasi­operasi berikut ini:

Constructor :  membuat sebuah stack yang baru sekaligus kosong.

Push: menambahkan item baru ke dalam stack.

Pop: menghapus dan mengembalikan sebuah item dari stack. Item yang dikembalikan 

harus berupa item terakhir yang ditambahkan.

IsEmpty: memeriksa apakah stack dalam keadaan kosong.

Sebuah stack sering juga disebut dengan “last in, first out”, atau struktur data LIFO, 

karena   item   terakhir   yang   ditambahkan   akan   menjadi   item   pertama   yang   akan 

dihilangkan. 

317
15.3 Objek Stack dalam Java

Java   menyediakan   sebuah   tipe   objek   bawaan   yang   disebut  Stack  yang 

mengimplementasikan tipe data abstrak stack. Anda harus berusaha untuk membedakan 

kedua hal ini – versi ADT dan versi Java – dengan jelas. Sebelum menggunakan kelas 

Stack, kita harus mengimpornya terlebih dahulu dari java.util.

Berikut ini merupakan sintaks untuk membuat sebuah Stack yang baru:
Stack stack = new Stack ();
pada mulanya, stack yang kita buat tidak berisi satu elemen pun alias kosong, kita bisa 

mengkonfirmasi keadaan ini dengan metode isEmpty yang akan mengembalikan hasil 

berupa nilai boolean:
System.out.println (stack.isEmpty ());
Stack   merupakan   struktur   data   yang   bersifat   generik.   Ini   berarti   bahwa   kita   bisa 

menambahkan item bertipe apapun ke dalamnya. Meskipun begitu, dalam implementasi 

Java, kita hanya bisa menambahkan tipe­tipe objek. Untuk contoh pertama, kita akan 

menggunakan  objek  Node  yang   digunakan   dalam   bab   sebelumnya.  Mari   kita  mulai 

dengan membuat lalu mencetak sebuah daftar yang pendek (short list):
IntList list = new IntList ();
list.addFirst (3);
list.addFirst (2);
list.addFirst (1);
list.print ();

hasilnya   adalah  (1,   2,   3).   Untuk   meletakkan   sebuah   objek  Node  ke   dalam   stack, 

gunakan metode push:

stack.push (list.head);

Perulangan berikut ini akan menelusuri daftar tersebut dan memasukkan (push) semua 

318
node ke dalam stack.
for  (No de  nod e =  list .hea d;  nod e != nul l;  nod e =  node .nex t)  
{
stack .pus h (n ode) ;
}

Kita bisa mengambil/menghapus sebuah elemen dari stack menggunakan metode pop.

Object obj = stack.pop ();

Tipe kembalian dari  pop  berupa  Object!  Ini terjadi karena implementasi stack tidak 

benar­benar mengetahui tipe­tipe objek yang dikandungnya. Ketika kita memasukkan 

objek­objek Node, mereka dikonversikan secara otomatis menjadi Object. Ketika kita 

mengambil objek­objek tersebut dari stack, kita harus meng­cast mereka menjadi Node 

kembali.
Node node = (Node) obj;
System.out.println (node);
Sayangnya, programmer justru akan mengalami kesulitan besar untuk melacak jejak 

objek­objek dalam stack dan juga ketika hendak meng­cast  mereka kembali ke tipe 

yang benar sebelum mereka diambil. Jika Anda mencoba untuk meng­cast sebuah objek 

ke   dalam   tipe   yang   salah,   Anda   akan   mendapatkan   sebuah   pesan   error; 

ClassCastException.

Perulangan berikut ini merupakan idiom yang sering dipakai untuk mengambil semua 

elemen dari dalam stack, lalu berhenti ketika stack tersebut sudah kosong:
while (!stack.isEmpty ()) {
Node node = (Node) stack.pop ();
System.out.print (node + " ");
}

319
Hasilnya adalah  3 2 1. Dengan kata lain, kita baru saja menggunakan sebuah stack 

untuk mencetak elemen­elemen yang ada dalam daftar secara terbalik! Perhatikan, cara 

ini bukanlah format standar yang biasa digunakan untuk mencetak sebuah daftar, tapi 

dengan stack, hal ini justru sangat mudah dilakukan. 

Anda harus membandingkan kode ini dengan implementasi yang sudah kita gunakan 

untuk metode printBackward yang berada dalam bab sebelumnya. Terdapat semacam 

kaitan yang alamiah sekaligus parallel antara versi rekursif dari printBackward dengan 

algoritma   stack   di   sini.   Perbedaannya   adalah   karena  printBackward  menggunakan 

run­time stack untuk melacak keberadaan node­node ketika ia menelusuri suatu daftar, 

lalu   mencetak   hasilnya   secara   terbalik   dengan   rekursi.   Algoritma   stack   sebenarnya 

melakukan   hal   yang   sama,   hanya   saja     algoritma   ini   menggunakan   objek  Stack 

ketimbang menggunakan run­time stack.

15.4 Kelas Pembungkus

Untuk  setiap primitif dalam Java, terdapat sebuah objek bawaan yang disebut dengan 

kelas  pembungkus  (wrapper   classes).  Sebagai   contoh,  kelas  pembungkus untuk  int 

adalah Integer; untuk double disebut dengan Double.

Kelas pembungkus menjadi bermanfaat karena beberapa faktor:

● Anda bisa menginstansiasi kelas pembungkus lalu membuat objek­objek yang 

berisi nilai­nilai primitif. Dengan kata lain, Anda bisa membungkus sebuah nilai 

primitif   dengan   sebuah   objek.   Hal   ini   akan   bermanfaat   jika   Anda   ingin 

memanggil sebuah metode yang membutuhkan sebuah tipe objek.

● Setiap   kelas   pembungkus   berisi   nilai­nilai   khusus   (seperti   nilai   minimum   da 

maximum   untuk   sebuah   tipe),   dan   metode­metode   yang   berfungsi   untuk 

mengkonversi dari satu tipe ke tipe lainnya.

320
15.5 Membuat Kelas Pembungkus

Cara   yang   paling   cepat   untuk   membuat   sebuah   objek   pembungkus   adalah   dengan 

menggunakan konstruktornya sendiri:
Integer i = new Integer (17);
Double d = new Double (3.14159);
Character c = new Character (’b’);

Secara teknis, sebenarnya  String  bukanlah sebuah kelas pembungkus karena tipe ini 

tidak berhubungan dengan tipe primitif manapun, tapi sintaks untuk membuat objek 

String adalah sama seperti cara berikut:

String s = new String ("fred");

Di sisi lain, belum pernah ada seorang pun yang menggunakan konstruktor untuk objek­

objek String karena Anda bisa mendapatkan hasil yang sama dengan nilai String yang 

lebih sederhana:
String s = "fred";

15.6 Membuat Kelas Pembungkus Lagi

Beberapa kelas pembungkus memiliki  konstruktor  kedua yang menggunakan sebuah 

String  sebagai   argumennya   lalu   untuk   mengubahnya   ke   bentuk   yang   diinginkan. 

Sebagai contoh:
Integer i = new Integer ("17");
Double d = new Double ("3.14159");

Proses pengubahan/konversi tipe ini sayangnya tidak kokoh (robust). Sebagai contoh, 

jika String yang digunakan tidak berada dalam format yang benar maka String tersebut 

321
akan   menyebabkan   munculnya  NumberFormatException.   Semua   karakter   non­

numerik dalam String, termasuk spasi, akan mengakibatkan gagalnya proses konversi.

Integer i = new Integer ("17.1"); // WRONG!!
Double d = new Double ("3.1459 "); // WRONG!!

Adalah ide yang bagus untuk memeriksa format String yang digunakan sebelum Anda 

mencoba untuk mengubahnya.

15.7 Mengeluarkan Nilai­Nilai

Java mengetahui cara mencetak objek­objek pembungkus, cara termudah adalah dengan 

mengambil suatu nilai adalah cukup dengan mencetak objek tersebut:
Integer i = new Integer (17);
Double d = new Double (3.14159);
System.out.println (i);
System.out.println (d);

Alternatif lain yang bisa Anda gunakan adalah dengan memanfaatkan metode toString. 

Metode ini bisa Anda gunakan untuk mengubah isi objek pembungkus menjadi String;
String istring = i.toString();
String dstring = d.toString();

Akhirnya, jika Anda hanya ingin mengambil nilai primitif dari suatu objek, ada sebuah 

metode objek dalam tiap kelas pembungkus yang mengerjakan tugas ini:
int iprim = i.intValue ();
double dprim = d.doubleValue ();

Ada   juga   metode­metode   yang   bisa   digunakan   untuk   mengubah   objek­objek 

322
pembungkus ke tipe primitif yang berbeda­beda. Anda harus memeriksa dokumentasi 

untuk masing­masing kelas pembungkus untuk melihat apa saja yang bisa diubah dan 

apa yang tidak.

15.8 Metode­Metode Bermanfaat dalam Kelas Pembungkus

Seperti   yang   telah   saya   sebutkan,   kelas­kelas   pembungkus   berisi   metode­metode 

bermanfaat   yang   berkaitan   dengan   masing­masing   tipe.   Sebagai   contoh,   kelas 

Character  berisi metode­metode, dalam jumlah yang melimpah, yang bisa digunakan 

untuk mengubah karakter ke bentuk upper case dan lower case. Juga untuk memeriksa 

apakah sebuah karakter merupakan angka, huruf, ataukah simbol.

Kelas String juga berisi metode­metode untuk melakukan pengubahan ke bentuk upper  

dan  lower   case.   Meskipun   demikian,   Anda   harus   tetap   ingat   bahwa   mereka   adalah 

fungsi, bukan modifier (lihat subbab 7.9).

Untuk   contoh   tambahan,   kelas  Integer  juga   berisi   metode­metode   untuk 

menginterpretasikan dan mencetak integer­integer ke bentuk yang berbeda­beda. Jika 

Anda   mempunyai   sebuah  String  yang   berisi   angka   dalam   basis   6,   Anda   bisa 

mengubahnya ke basis 10 menggunakan parseInt.

String base6 = "12345";
int base10 = Integer.parseInt (base6, 6);
System.out.println (base10);

Karena  parseInt  merupakan sebuah metode kelas, Anda memanggilnya dengan cara 

menyebutkan nama kelas dan metodenya memakai notasi dot. 

Basis 6 mungkin tidak terlalu berguna, tetapi heksadesimal (basis 16) dan oktaf (basis 

8) merupakan sesuatu yang sangat sering dipakai dalam dunia ilmu komputer.

323
15.9 Ekspresi Postfix

Dalam   banyak   bahasa   pemrograman,   ekspresi­ekspresi   matematika   ditulis   dengan 

bantuan operator yang diletakkan di antara dua operan, seperti dalam  1 + 2. format 

seperti  ini   disebut  infix.  Format  alternatif  yang  digunakan  oleh   beberapa  kalkulator 

adalah postfix. Dalam postfix, operatornya mengikuti operan­operannya, misalnya 1 2 

+.

Alasan   yang   membuat   postfix   terkadang   berguna   adalah   bahwa   terdapat   semacam 

kecenderungan alamiah untuk mengevaluasi suatu postfix menggunakan sebuah stack.

● Dimulai   dari   depan/awal   sebuah   ekspresi,   ambil   satu   term   (operator   atau 

operan) dalam satu waktu.

● Jika termnya berupa operan, masukkan (push) dia ke dalam stack.

● Jika termnya berupa operator, ambil (pop) operan­operan tersebut dari 

dalam stack, kerjakan operasi untuk mereka, lalu masukkan hasilnya ke 

dalam stack lagi.

● Ketika   kita   sudah   sampai   ke   ujung/akhir   sebuah   ekspresi,   harusnya   sudah 

terdapat   sebuah   operan   yang   tertinggal   dalam   stack.   Operan   itulah   yang 

menjadi hasilnya.

Sebagai latihan, gunakan algoritma ini untuk mengerjakan ekspresi 1 2 + 3 *.

Latihan   ini   menunjukkan   salah   satu   kelebihan   postfix:   kita   tidak   perlu   lagi 

menggunakan tanda kurung untuk mengatur urutan suatu operasi. Untuk mendapatkan 

hasil yang sama dalam infix. Kita mungkin harus menulis (1 + 2) * 3. Sebagai latihan, 

tulislah ekspresi postfix yang ekuivalen dengan 1 + 2 * 3?

324
15.10 Parsing

Untuk mengimplementasikan algoritma yang ada di bab sebelumnya, kita harus bisa 

menelusuri suatu string lalu membaginya ke dalam dua kelompok yaitu; operan dan 

operator. Proses ini merupakan sebuah contoh  parsing  (penguraian), lalu hasilnya – 

yang berupa string individual –  disebut tokens.

Java   menyediakan   sebuah   kelas   bawaan   yang   disebut  StringTokenizer  yang   bisa 

menguraikan string lalu memecahnya menjadi token­token. Untuk menggunakan kelas 

ini, Anda harus mengimpornya dari java.util.

Dalam bentuknya yang paling sederhana,  StringTokenizer  menggunakan spasi­spasi 

untuk menandai batas antara tiap token. Sebuah karakter yang menandai suatu pembatas 

disebut delimiter.

Kita   bisa   membuat  StringTokenizer  dengan   cara   yang   sudah   sering   kita   gunakan, 

dengan melewatkan sebuah argumen berupa string yang akan kita uraikan.
StringTokenizer   st   =   new   StringTokenizer   ("Here   are  
four tokens.");

Perulangan   berikut   ini   merupakan   idiom   standar   untuk   mengambil  token­token   dari 

StringTokenizer.

while (st.hasMoreTokens ()) {
System.out.println (st.nextToken());
}

Hasilnya adalah:
Here
are

325
four
tokens.

Untuk menguraikan ekspresi­ekspresi, kita memiliki opsi untuk menentukan karakter 

tambahan yang akan kita gunakan sebagai delimiter.
StringTokenizer   st   =   new   StringTokenizer   ("11  
22+33*", " +­*/");

Argumen kedua adalah sebuah String yang berisi semua karakter yang akan digunakan 

sebagai delimiter. Hasilnya adalah:
11
22
33

Cara   ini   memang   bekerja   dengan   baik   untuk   mengambil   semua   operannya   tapi 

sayangnya kita juga akan kehilangan operator­operatornya. Untungnya, masih ada satu 

opsi lagi dari StringTokenizer.

StringTokenizer   st   =   new   StringTokenizer   ("11  


22+33*", " +­*/", true);

Argumen ketiga berkata, “Ya, kami ingin memperlakukan delimiter­delimiter sebagai 

token­token.” sekarang hasilnya adalah
11

22
+
33

326
*

Ini hanyalah token­token yang akan kita gunakan untuk mengevaluasi ekspresi­ekspresi 

ini.

15.11 Mengimplementasikan ADT

Salah satu tujuan dasar dari ADT adalah untuk memisahkan kebutuhan sang penyedia 

(provider), si penulis kode yang mengimplementasikan ADT, dan sang klien (client), 

orang yang menggunakan ADT. Sang penyedia hanya perlu mengkhawatirkan masalah 

benar­tidaknya pengimplementasian – apakah sudah sesuai dengan ketentuan dari ADT 

ataukah belum – bukan pada bagaimana kodenya akan digunakan.

Sebaliknya,   sang   klien  mengasumsikan  bahwa   implementasi   yang   diterapkan   untuk 

suatu ADT adalah sudah benar sehingga tidak perlu lagi mengkhawatirkan detailnya. 

Ketika   Anda   sedang   menggunakan   salah   satu   kelas   bawaan   Java,   Anda   memiliki 

kemewahan untuk berpikir secara eksklusif sebagai seorang klien.

Ketika   Anda   mengimplentasikan   sebuah   ADT,   di   sisi   yang   lain,   Anda   juga   harus 

menulis kode dari klien untuk mengujinya. Untuk kasus ini, Anda sebaiknya berhati­

hati terhadap aturan yang akan Anda terapkan untuk instan yang akan Anda gunakan.

Di   bagian   selanjutnya,   kita   akan   menukar  gears  dan   melihat   salah   satu   cara   untuk 

mengimplementasikan   stack   ADT   yakni   dengan   bantuan   array.   Sekarang   mulailah 

berpikir laksana seorang provider.

15.12 Implementasi Array untuk Stack ADT

Variabel­variabel   instan   untuk   mengimplementasikan   kasus   ini   adalah   sebuah   array 

yang berisi sekumpulan Object. Array ini sendiri nantinya akan berisi item­item yang 

berada dalam stack dan sebuah indeks, berupa integer, yang akan memberi tahu kita 

327
tentang sisa spasi yang ada dalam array. Pada mulanya, array ini kosong. Sementara 

indeksnya di­set dengan nilai 0.

Untuk menambahkan sebuah elemen ke dalam stack (push), kita akan menyalin acuan 

yang   mengacu   kepadanya   ke   dalam   stack   lalu   menaikkan   indeksnya   satu   per   satu 

(increment). Untuk mengambil sebuah elemen (pop), kita harus men­decrement indeks 

terlebih dahulu baru mengeluarkannya.

Berikut ini definisi kelasnya:
public class Stack {
    Object[] array;
    int index;
    public Stack () {
        this.array = new Object[128];
        this.index = 0;
    }
}

Seperti biasa, jika kita sudah menuliskan variabel­variabel instannya, maka otomatis 

kita juga akan menuliskan konstruktor di dalamnya. Untuk sekarang, jumlah elemen 

yang akan kita gunakan adalah 128 item. Nanti, kita akan mempelajari alternatif lain 

yang lebih baik untuk menangani kasus semacam ini.

Memeriksa kosong­tidaknya stack bisa dilakukan dengan cara yang sederhana.
public boolean isEmpty () {
    return index == 0;
}

Meskipun sederhana, penting untuk diingat bahwa jumlah elemen di dalam stack tidak 

sama   dengan   ukuran   array.   Pada   awalnya,   ukuran   array   adalah   128   tetapi   jumlah 

328
elemennya sama dengan 0.

Implementasi untuk push dan pop bisa dilakukan dengan cara seperti berikut.

public void push (Object item) {
    array[index] = item;
    index++;
}

public Object pop () {
    index­­;
    return array[index];
}

Untuk menguji kedua metode ini, kita bisa memanfaatkan kode klien yang sebelumnya 

kita   gunakan   untuk   menguji  Stack  bawaan.   Kemudian,   ketimbang   menggunakan 

impelementasi stack milik  java.util, program kita justru akan memakai implementasi 

yang telah kita tulis sebelumnya. 

Jika segala sesuatunya berjalan sesuai dengan rencana, program harusnya langsung bisa 

berfungsi tanpa perlu penambahan di sana­sini. Dan ingat, salah satu nilai lebih ketika 

menggunakan ADT adalah karena Anda bisa mengubah suatu implementasi tanpa harus 

mengubah kode kliennya.

15.13 Mengubah Ukuran Array

Sebuah   kelemahan   dari   penggunaan   implementasi   seperti   ini   adalah   karena   ia   telah 

membuat alokasi array secara kaku untuk setiap Stack yang akan dibuat. Jika pengguna 

memasukkan lebih dari 128 item ke dalam stack, maka program akan mengeluarkan 

eksepsi yang berbunyi ArrayIndexOutOfBounds.

329
Alternatif untuk kasus ini adalah dengan mengizinkan kode klien untuk menentukan 

ukuran array tersebut. Cara ini memang menyelesaikan masalahnya, tapi hal ini hanya 

bisa dilakukan dengan syarat bahwa sang klie harus tahu terlebih dahulu jumlah item 

yang dibutuhkan. Dan sayangnya, hal ini sepertinya tidak bisa terjadi setiap saat.

Berikut ini versi push yang telah diperbaiki:

public void push (Object item) {
    if (full ()) resize ();

// di sini kita bisa membuktikan bahwa 
// indeks < array.length

    array[index] = item;
    index++;
}

Sebelum meletakkan item baru ke dalam array, kita akan memeriksa apakah array sudah 

penuh?   Jika   ya,   kita   panggil   metode  resize.   Setelah   pernyataan  if,   kita   akan   tahu 

apakah; 

1. memang sudah terdapat ruang yang tersisa dalam array, atau

2. array sudah diubah ukurannya sehingga terdapat ruang yang tersisa di dalamnya.

Jika full dan resize sudah benar, maka selanjutnya kita bisa membuktikan bahwa index 

< array.length, dan oleh karena itu pernyataan berikutnya tidak akan menyebabkan 

eksepsi lagi.

Sekarang, yang harus kita lakuka adalah mengimplementasikan full dan resize.

private boolean full () {
    return index == array.length;
}

330
private void resize () {
        Object[]   newArray   =   new   Object[array.length   * 
2];

        //   kita   asumsikan   bahwa   array   yang   lama   sudah  


penuh 
    for (int i=0; i<array.length; i++) {
        newArray[i] = array[i];
    }
    array = newArray;
}

Kedua metode dideklarasikan secara private, ini berarti keduanya tidak bisa dipanggil 

dari kelas yang lain. Bisanya hanya dari kelas ini. Hal semacam ini bisa diterima dengan 

alasan karena memang tidak alasan bagi kode klien untuk menggunakan fungsi ini, atau 

bahkan   hanya   sekedar   ingin   menggunakannya,   karena   metode   ini   memang   sengaja 

dibuat untuk menjadi pembatas antara kode provider dengan kode klien.

Implementasi untuk metode full sangat sederhana; metode ini hanya memeriksa apakah 

indeks telah melampaui ukuran indeks yang telah ditetapkan sebelumnya.

Pun  begitu dengan implementasi  untuk metode  resize, hanya dengan  asumsi bahwa 

array yang lama sudah penuh. Dengan kata lain, asumsi tersebut merupakan prasayarat 

untuk  metode ini. Sangat mudah bagi kita untuk melihat bahwa prasyarat ini sudah 

memenuhi   syarat   karena   satu­satunya   cara   untuk   memanggil  resize  adalah   jika  full 

bernilai true. Nilai ini hanya bisa terjadi jika idex == array.length.

Di   akhir   metode  resize,   kita   mengganti   array   yang   lama   dengan   array   yang   baru 

331
(menyebabkan   array   lama   berstatus   “garbage   collected”).  array.length  yang   baru 

berukuran dua kali lebih besar ketimbang  array yang lama, sementara  index  belum 

berubah sehingga pernyataan index < array.length pastilah bernilai benar. Fakta­fakta 

di atas merupakan postcondition untuk resize; sesuatu yang harus bernilai true ketika 

metode telah selesai dieksekusi (selama prasyaratnya juga sudah dipenuhi).

Prasyarat,  postcondition,   dan  invariant  merupakan  tools  yang   sangat   berguna   untuk 

menganalisa   program   sekaligus   menunjukkan   tingkat   ketepatan   (correctness)   yang 

terkandung   di   dalamnya.   Dalam   contoh   ini   saya   telah   menunjukkan   sebuah   teknik 

pemrograman   yang   memfasilitasi   analisis   program   sekaligus   sebuah   teknik 

pendokumentasian yang bisa membantu peningkatan mutu keakuratannya.

15.14 Daftar Kata­Kata

Istilah Arti
Sebuah   tipe   data   (umumnya   merupakan   kumpulan   dari 

ADT objek) yang didefinisikan dengan sekumpulan operasi, tapi 

yang bisa diimplementasikan dengan berbagai cara.
Sebuah   program   yang   menggunakan   ADT   (atau   sebutan 
client
untuk orang yang menulis programnya).
Kode yang mengimplmentasikan suatu ADT (atau sebutan 
provider
untuk orang yang menulisnya).
Salah  satu  kelas  dalam  Java, seperti  Double  dan  Integer 

yang   memungkinkan   objek­objek   mengandung   tipe­tipe 


wrapper classes
primitif,   dan   metode­metode   yang   beroperasi   di   atas 

primitif.
private Kata kunci dalam Java yang mengindikasikan bahwa sebuah 

metode   atau   variabel   instan   tidak   bisa   diakses   dari   luar 

332
definisi kelasnya sendiri. 
Suatu   cara   dalam   menulis   ekspresi­ekspresi   matematika 

infix dengan   posisi   operator   yang   berada   di   antara   operan­

operannya.
Suatu   cara   dalam   menulis   ekspresi­ekspresi   matematika 

postfix dengan   posisi   operator   yang   berada   di   belakang   operan­

operannya.
Membaca sebuah string yang terdiri dari karakter­karakter 

parse atau token­token untuk menganalisa struktur tata bahasanya 

(grammatical structure).
Sekumpulan   karakter­karakter   yang   diperlakukan   sebagai 

token sebuah unit untuk tujuan parsing, seperti kata laiknya dalam 

bahasa alamiah.
Sebuah karakter yang digunakan untuk memisahkan token­
delimiter
token, seperti tanda baca laiknya dalam bahasa alamiah. 
Sebuah pernyataan matematis yang bisa bernilai benar atau 
predicate
salah.
Sebuah predikat yang harus bernilai benar di akhir sebuah 

postcondition metode   (dengan   catatan   bahwa   prasyaratnya   juga   bernilai 

benar di awal metode).

15.15 Latihan

Latihan 15.1

Tulislah metode reverse yang mengambil sebuah array berisi integer, menelusuri array 

itu, memasukkan item­item ke dalam stack, lalu mengambil item­item itu dari stack, 

333
meletakkan   kembali   ke   dalam   array   dalam   posisi   yang   terbalik   dari   keadaan 

sebelumnya.

Tujuan   latihan   ini   adalah   untuk   mempraktikkan   mekanisme   pembuatan   objek­objek 

pembungkus, memasukkan dan mengeluarkan objek­objek, dan meng­typecast  objek­

objek generik ke bentuk yang lebih spesifik.

Latihan 15.2

Latihan   ini   berdasarkan   solusi   dari   latihan   14.1.   mulailah   dengan   membuat   salinan 

impelemntasi Anda dari metode IntList yang disebut LinkedList.

a) Ubahlah implementasi linked list ke dalam sebuah list yang generik dengan membuat 

kargo   untuk   sebuah  Object  ketimbang   untuk   sebuah  integer.   Modifikasilah   kode 

pengujinya sesuai dengan kondisi sekarang lalu jalankan programnya.

b) Tulislah sebuah metode  LinkedList  dengan nama  split  yang menggunakan sebuah 

String, memecahnya menjadi kata­kata (menggunakan spasi debagai delimiter), lalu 

mengembalikan sebuah list yang berisi  String, dengan satu kata untuk setiap node 

dalam list  tersebut. Implementasi  Anda  haruslah efisien,  ini  berarti  bahwa waktu 

yang dihabiskan harus sesuai dengan jumlah kata yang ada dalam string.

c) Tulislah sebuah metode LinkedList dengan nama join yang mengembalikan sebuah 

String yang berisi representasi String dari setiap objek yang berada dalam list, terurut 

sesuai dengan urutan kemunculannya, dengan sebuah spasi yang menjadi pemisah.

d) Tulislah metode toString untuk LinkedList.

Latihan 15.3

Tulislah sebuah implementasi dari Stack ADT menggunakan implementasi LinkedList 

milik Anda sendiri sebagai struktur data utamanya. Ada dua pendekatan umum untuk 

kasus   ini:   stack   itu   kemungkinan   akan   berisi   sebuah  LinkedList  sebagai   sebuah 

variabel   instan,   atau   kelas   Stack   mungkin   akan   memperluas   kelas  LinkedList  itu 

334
sendiri. Pilihlah yang kedengarannya lebih baik untuk Anda, atau, jika Anda memang 

benar­benar   seorang   yang   berambisi,   impelementasikan   saja   keduanya   lalu   buatlah 

perbandingan antara keduanya. 

Latihan 15.4

Tulislah program Balance.java yang bisa membaca sebuah file dan memeriksa bahwa 

tanda kurung, (), dan kurung kotak, [], dan kurung kurawal, {}, telah   ditulis dengan 

seimbang dan diletakkan di tempat yang benar. 

Petunjuk:  Lihat bagian C untuk kode yang mampu membaca baris­baris dalam suatu 

file.

Latihan 15.4

Tulislah metode  evalPostfix  yang menggunakan sebuah String berisi ekspresi postfix 

dan   mampu   mengembalikan   nilai   bertipe   double   yang   mengandung   hasil 

perhitungannya. Anda bisa menggunakan String­Tokenizer untuk menguraikan String 

dan sebuah Stack berisi Double untuk mengevaluasi ekspresi tersebut. Langkah­langkah 

berikut ini adalah saran saya untuk pengembangan program milik Anda.

a) Tulislah   sebuah   program   yang   bisa   meminta   user   untuk   memasukkan   string 

sekaligus   mencetaknya,   berulang­ulang,   sampai   si   pengguna   mengetikkan   kata 

“quit”. Lihat  bagian  C untuk informasi mengenai cara memasukkan  data melalui 

keyboard. Anda bisa melihat kode berikut ini sebagai permulaan:
public  static  void  inputLoop  ()  throws  IOException  
{
BufferedReader stdin =
           new  BufferedReader (new  InputStreamReader 
(System.in));
while (true) {
  System.out.print ("=>"); // Cetak hasil masukan

335
  String s = stdin.readLine(); // ambil masukan
      if (s == null) break;
      // periksa apakah s sama dengan "quit"
      // cetak s
  }
}

b) Identifikasikan helper methods yang menurut Anda bisa dimanfaatkan, lalu tulis dan 

debug  mereka   dalam   lingkungan   yang   terisolir.   Saran:  isOperator,  isOperand, 

parseExpression, performOperation.

c) Kita tahu bahwa kita ingin menambahkan nilai int ke dalam stack lalu mengambilnya 

kembali,   dengan   kata   lain,   kita   akan   membutuhkan   sebuah   kelas   pembungkus 

(wrapper   classes).   Pastikan   Anda   tahu   bagaimana   cara   melakukannya   lalu   ujilah 

operasi­operasi tersebut dalam lingkungan yang terisolir. Mungkin membuat mereka 

menjadi helper methods.

d) Tulislah   versi  evaluate  yang   hanya   menangani   satu   jenis   operator   saja   (seperti 

penjumlahan). Ujilah dalam lingkungan yang terisolir.

e) Hubungkan evaluator Anda dengan perulangan input/output Anda sendiri.

f) Tambahkan operasi­operasi lainnya.

g) Ketika   Anda   tahu   bahwa   kode   ini   bekerja,   Anda   mungkin   ingin   mengevaluasi 

struktur  rancangannya. Bagaimana cara Anda membagi kode ini ke dalam kelas­

kelas? Variabel instan apa yang harus dimiliki oleh kelas­kelas tersebut? Parameter­

parameter apa yang harus dilewatkan?

h) Agar rancangan Anda tambah elegan, Anda juga harus bisa membuat kode Anda 

bersifat  bullet­proof,   maksudnya   adalah   agar   metode   ini   tidak   menyebabkan 

terjadinya eksepsi di bawah kondisi apapun, bahkan ketika si pengguna mengetikkan 

sesuatu yang aneh misalnya. 

336
 Bab 16

Antrian dan Antrian Prioritas

Bab   ini   akan   menyajikan   dua   ADT   sekaligus:   antrian   dan   antrian   prioritas.   Dalam 

kehidupan sehari­hari, sesuatu yang disebut dengan antrian adalah sederetan pelanggan 

yang   menunggu   untuk   suatu   pelayanan   tertentu.   Dalam   banyak   kasus,   pelanggan 

pertama   yang   berada   dalam   barisan   biasanya   akan   dilayani   terlebih   dahulu.   Tetapi 

tunggu dulu, karena ternyata tidak semua kasus serta merta seperti itu. Sebagai contoh, 

di bandara, calon penumpang yang pesawatnya akan terbang sesaat lagi akan langsung 

ditaruh di pertengahan antrian. Begitu juga di supermarket, seorang pelanggan yang 

baik hati biasanya mendahulukan pelanggan lain yang belanjaannya lebih sedikit.

Aturan   untuk   menentukan   siapa   yang   harus   dilayani   berikutnya   disebut  queueing 

discipline (disiplin antrian). Aturan yang paling sederhana adalah FIFO, atau “First In  

First Out”. Aturan yang paling umum digunakan disebut  priority queueing, di sini 

masing­masing   pelanggan   akan   diberi   tingkat   prioritas,   pelanggan   yang   memiliki 

prioritas paling tinggi akan didahulukan, tanpa melihat kapan si pelanggan itu datang. 

Alasan   yang   membuat   saya   menyebutnya   sebagai   aturan   yang   paling   umum   adalah 

karena prioritas itu sendiri bisa berdasarkan pada apa pun yang memungkinkan: kapan 

sebuah   penerbangan   akan   dilaksanakan,   berapa   banyak   barang   yang   dimiliki   oleh 

pelanggan, atau seberapa  penting  si pelanggan tersebut jika dibandingkan pelanggan 

lainnya. Tapi tentu, tidak semua aturan antrian bersifat “adil”, toh bukankah keadilan itu 

sendiri sejatinya berada dalam persepsi masing­masing individu.

ADT Antrian (The Queue ADT) dan ADT Antrian Prioritas (The Priority Queue ADT) 

337
mempunyai sekumpulan operasi dan antarmuka yang sama. Perbedaannya terletak di 

dalam   semantik   operasi­operasinya:   satu   Antrian   menggunakan   kebijakan   FIFO, 

sementara Antrian Prioritas (seperti namanya) menggunakan kebijakan pemrioritasan 

dalam antrian.

Laiknya sebagian besar ADT, ada beberapa cara untuk mengimplementasikan antrian. 

Karena antrian sendiri merupakan kumpulan item, kita bisa menggunakan mekanisme 

dasar manapun untuk menyimpan koleksi­koleksi tersebut, termasuk array dan list. Di 

sini kita akan memilih teknik yang unjuk kerjanya paling bagus – berapa lama waktu 

yang dibutuhkannya untuk melaksanakan operasi­operasi yang kita inginkan – dan tentu 

saja dalam hal kemudahan penggunaannya.

16.1 ADT Antrian

ADT antrian akan didefinisikan oleh operasi­operasi berikut ini:

constructor: membuat satu antrian baru yang kosong.

add: menambahkan satu item baru ke dalam antrian.

remove:   menghapus   dan   mengembalikan   satu   item   dari   antrian.   Item   yang   dikem­

balikan pertama kali adalah item yang pertama kali ditambahkan.

isEmpty: memeriksa apakah suatu antrian dalam keadaan kosong ataukah tidak.

Berikut ini adalah implementasi dari antrian secara umum, berdasarkan kelas bawaan 

java.util.LinkedList:

public class Queue {
    private LinkedList list;

    public Queue () {
        list = new LinkedList ();
    }

338
    public boolean isEmpty () {
        return list.isEmpty ();
    }

    public void add (Object obj) {
        list.addLast (obj);
    }

    public Object remove () {
        return list.removeFirst ();
    }
}

Satu objek berisi satu variabel instan, yakni list yang mengimplementasikannya. Untuk 

metode­metode lainnya, yang harus kita lakukan hanyalah memanggil salah satu metode 

dari kelas LinkedList.

Kita bisa menulis implementasi yang sama sedikit lebih jelas dengan memanfaatkan 

fitur inheritance:
public class Queue extends LinkedList {

    public Object remove () {
        return removeFirst ();
    }
}

Oke, kelihatannya sudah lebih jelas keltimbang sebelumnya! Karena Queue merupakan 

perluasan (anak) dari  LinkedList, kita akan mewarisi konstruktornya, yakni  isEmpty 

339
dan add. Kita juga mewarisi remove, tetapi sayang versi remove yang kita dapat dari 

kelas  LinkedList  tidak   melakukan   apa   yang   kita   maksudkan;   metode   ini   justru 

menghapus   elemen  terakhir  dalam  list   (daftar),  bukan   yang   pertama.   Kita   akan 

mengatasinya dengan membuat remove versi baru yang akan meng­override versi yang 

kita warisi.

Pilihan   yang   akan   kita   ambil   bergantung   pada   beberapa   faktor.   Pewarisan   memang 

dapat menyebabkan suatu implementasi menjadi lebih jelas, selama masih ada metode­

metode dalam kelas induk yang bisa dimanfaatkan. Tetapi, fitur ini juga bisa membuat 

suatu implementasi justru lebih sulit untuk dibaca dan di­debug. Hal ini terjadi karena 

metode­metode untuk kelas yang baru tersebut tidak berada di tempat yang sama. Selain 

itu,   fitur  ini  juga   bisa  menyebabkan  munculnya  perilaku   yang  mungkin   tidak  Anda 

harapkan. Ini terjadi karena kelas yang baru akan mewarisi  semua  metode dari kelas 

induk, tidak hanya yang Anda butuhkan. Keadaan seperti ini akan mengakibatkan kelas 

Queue  versi   kedua   juga   memiliki   metode­metode   seperti  removeLast  dan  clear. 

Meskipun keduanya bukan merupakan bagian dari ADT Queue. Implementasi pertama 

lebih aman; dengan mendeklarasikkan satu variabel instan yang bersifat  private, kita 

bisa   mencegah   klien   yang   ingin   memanggil   metode­metode   yang   berada   dalam 

LinkedList.

16.2 Veneer

Dengan menggunakan  sebuah  LinkedList  untuk mengimplementasikan satu Antrian, 

kita bisa mengambil manfaat dari kode yang sudah ada; kode yang baru saja kita tulis 

hanya   menerjemahkan   metode­metode  LinkedList  ke   dalam  metode­metode   Queue. 

Implementasi seperti ini disebut  veneer  (kayu pelapis nan tipis). Dalam kehidupan di 

dunia nyata, veneer adalah sebuah lapisan tipis yang terbuat dari kayu berkualitas baik 

340
yang digunakan dalam pembuatan mebel untuk melapis kayu berkualitas kurang baik di 

bawahnya.   Ilmuwan   komputer   menggunakan   metafora   ini   untuk   mendeskripsikan 

sebuah   kode   kecil   yang   menyembunyikan   detail   suatu   implementasi   sekaligus 

menyediakan antarmuka yang lebih sederhana dan terstandardisasi.

Contoh   kasus   tentang   Antrian   akan   mendemonstrasikan   salah   satu   hal   menarik 

mengenai veneer, yakni kemudahan dalam implementasi, dan salah satu bahaya ketika 

menggunakan veneer adalah karena performace hazard!

Normalnya, ketika kita memanggil sebuah metode, sebenarnya pada saat itu kita tidak 

terlalu peduli mengenai detail implementasinya. Tapi ada satu “detail” yang mungkin 

ingin kita ketahui – karakter unjuk kerja dari suatu metode. Berapa lama waktu yang 

diperlukan oleh metode, sebagai sebuah fungsi dari angka item­item yang berada dalam 

list (daftar)?

Untuk menjawab pertanyaan di atas, kita harus mengetahui lebih banyak hal mengenai 

implementasi.   Jika   kita   mengasumsikan   bahwa  LinkedList  benar­benar   di­

implementasikan   sebagai   sebuah  linked   list  (daftar   yang   saling   terkait),   maka   im­

plementasi dari metode removeFirst mungkin akan kelihatan seperti ini:

public Object removeFirst () {
    Object result = head;
    if (head != null) {
        head = head.next;
    }
    return result.cargo;
}

Kita  mengasumsikan bahwa  head  mengacu ke node pertama  dalam list, dan bahwa 

setiap node­nya berisi kargo serta sebuah acuan yang mengarah ke node berikutnya 

341
dalam list. 

Tidak ada pemanggilan perulangan atau fungsi di sini. Akibatnya, run­time metode ini 

hampir  selalu   sama   setiap   waktu.   Metode   seperti   ini   disebut   dengan  constant   time 

operation. Dalam realita, metode ini mungkin akan terlihat lebih cepat ketika list sedang 

kosong. Hal ini terjadi karena metode akan melompati bagian badan (body) dari bagian 

persyaratan (conditional), tapi perbedaannya tidak terlalu signifikan.

Unjuk   kerja  addLast  sangat   berbeda.   Berikut   ini   adalah   sebuah   implementasi   yang 

bersifat hipotesis:
public void addLast (Object obj) {
    // special case: list kosong
    if (head == null) {
        head = new Node (obj, null);
        return;
    }
    Node last;
    for   (last   =   head;   last.next   !=   null;   last   =   las ­
t.next) {
 
    //   telusuri   list   untuK   menemukan   node  
terakhir
    }
    last.next = new Node (obj, null);
}

Syarat pertama menangani kasus khusus, yakni penambahan sebuah node baru ke dalam 

list kosong. Dalam kasus ini, lagi­lagi, run time tidak bergantung kepada panjang list. 

Meskipun   begitu,   dalam   kasus   yang   lebih   umum,   kita   harus   menelusuri   list   untuk 

342
menemukan elemen terakhir agar kita bisa membuatnya mengacu ke node yang baru.

Penelusuran ini menghabiskan waktu yang sesuai dengan panjang list. Karena run time  

merupakan fungsi linear dari panjang, kita bisa mengatakan bahwa metode ini termasuk 

linear time. Dibandingkan dengan constant time, linear time bisa dikategorikan sebagai 

yang buruk sekali.

16.3 Linked Queue

Kita menginginkan sebuah implementasi dari ADT Antrian yang bisa melakukan semua 

operasi dalam waktu yang konstan. Salah satu cara untuk menyelesaikan masalah ini 

adalah dengan mengimplementasikan linked queue. Cara ini bisa dibilang sama dengan 

linked list karena ia terdiri dari objek­objek  Node  yang saling terhubung, mulai dari 

yang berjumlah 0 (tanpa  Node) atau lebih dari itu. Perbedaannya adalah bahwa suatu 

antrian memelihara acuan yang berasal dari node pertama dan terakhir, seperti tampak 

dalam gambar.

Inilah tampilan implementasi linked Queue:

public class Queue {
    public Node first, last;
    public Queue () {
        first = null;
        last = null;

343
    }
    public boolean isEmpty () {
    return first == null;
  }
}

Sampai sejauh ini, tampaknya implementasi ini masih biasa­biasa saja. Di dalam antrian 

yang kosong, baik first maupun last diisi dengan null. Untuk memeriksa apakah suatu 

list sedang kosong ataukah tidak, kita hanya perlu memeriksa salah satu diantaranya.

Implementasi metode  add  tampaknya lebih rumit karena kita harus berurusan dengan 

beberapa kasus khusus.
public void add (Object obj) {
    Node node = new Node (obj, null);
    if (last != null) {
        last.next = node;
    }
    last = node;
    if (first == null) {
        first = last;
    }
}

Syarat pertama memeriksa dan memastikan bahwa last sudah mengacu ke sebuah node; 

jika ya, maka kita harus membuatnya mengacu ke node yang baru.

Syarat yang kedua berurusan dengan kasus khusus di mana list pada awalnya memang 

berstatus kosong. Dalam kasus ini, baik first maupun last mengacu ke node yang baru.

Metode remove juga berurusan dengan beberapa kasus khusus.

344
public Object remove () {
    Node result = first;
    if (first != null) {
        first = first.next;
    }
    if (first == null) {
        last = null;
    }
    return result;
}

Syarat   pertama   memeriksa   apakah   ada   node   di   dalam   antrian.   Jika   ya,   kita   harus 

menyalin node next ke first. Syarat kedua terkait dengan kasus khusus bahwa list pada 

saat yang bersamaan sedang kosong, dalam hal ini kita harus membuat  last  menjadi 

null.

Untuk  latihan, buatlah diagram­diagram yang menunjukkan operasi­operasi ini, baik 

dalam   kasus   normal   maupun   kasus   khusus,   dan   yakinkan   diri   Anda   sendiri   bahwa 

diagram­diagram tersebut memang benar adanya.  

Jelas sekali, implementasi ini tentu lebih rumit ketimbang implementasi veneer, dan 

lebih   sulit   lagi   untuk   membuktikan   bahwa   implementasi   ini   memang   benar. 

Keuntungannya adalah karena kita telah berhasil mencapai tujuan yang kita inginkan: 

add dan remove adalah metode yang bersifat constant time operation.

16.4 Circular Buffer

Implementasi umum lainnya dari antrian adalah  circular buffer. “Buffer” merupakan 

nama   umum   untuk   menyebutkan   sebuah   lokasi   penyimpanan   yang   sifatnya 

345
sementara/temporer,   meskipun   ia   juga   sering   digunakan   untuk   menyebutkan   suatu 

array,  seperti  yang  terjadi   dalam   kasus   ini.  Sekarang  Anda   tentu  akan  lebih  paham 

dengan apa yang dimaksud dengan kata “circular” di sini.

Implementasi   dari   circular   buffer   sama   dengan   implementasi   array   untuk   stack   di 

subbab 15.12. Item­item antrian disimpan di dalam sebuah array, dan kita menggunakan 

indeks untuk mengetahui posisi kita di dalam array. Dalam implementasi stack, ada 

sebuah indeks tunggal yang menunjuk ke ruang (space) berikutnya yang masih kosong. 

Dalam implementasi antrian, terdapat dua indeks: first menunjuk ke ruang dalam array 

yang   berisi   pelanggan   pertama   dalam   barisan   sementara  next  menunjuk   ke   ruang 

berikutnya yang masih kosong.

Gambar   berikut   ini   menunjukkan   sebuah   queue   dengan   dua   item   (direpresentasikan 

dengan titik­titik).

Ada dua cara untuk memikirkan variabel­variabel untuk  first  dan  last. Secara literal, 

keduanya bertipe integer, dan nilai mereka ditunjukkan dalam kotak di sebelah kanan. 

Walaupun begitu, secara abstrak, mereka merupakan indeks dari sebuah array. Oleh 

karena itulah, mereka sering digambarkan sebagai sebuah anak panah yang menunjuk 

ke lokasi dalam array. Representasi anak panah sebenarnya sangat bagus, tapi Anda 

harus ingat bahwa indeks­indeks tersebut bukanlah acuan; mereka hanyalah integer.

Berikut ini merupakan implementasi array dari sebuah antrian yang belum lengkap:
public class Queue {
    public Object[] array;
    public int first, next;
    public Queue () {
          array = new Object[128];
          first = 0;

346
          next = 0;
    }
    public boolean isEmpty () {
          return first == next;
    }

Variabel­variabel instan dan konstruktornya tampak normal dan biasa­biasa saja, tapi 

kita   lagi­lagi   menjumpai   masalah   ketika   dihadapkan   dengan   ukuran   yang   harus 

digunakan untuk array. 

Nantinya   kita   akan   menyelesaikan  masalah   ini,   sebagaimana   yang   telah  kita   lakkan 

dengan stack, dengan cara mengubah ukuran array­nya ketika array tersebut sudah terisi 

penuh.

Implementasi  isEmpty  terkesan   agak   mengejutkan.   Anda   mungkin   harus   berpikir 

bahwa  first   ==   0  akan   mengindikasikan   sebuah   antrian   kosong,   tapi   itu   menge­

yampingkan   fakta   bahwa   kepala   antrian   tidaklah   harus   berada   di   depan   array.   Se­

baliknya, kita tahu bahwa antrian dikatakan kosong jika  head  sama dengan  next, di 

mana dalam kasus ini berarti sudah tidak ada lagi item­item yang tersisa. Sekali saja 

kita melihat implementasi add dan remove, kondisi tersebut akan lebih masuk akal.

public void add (Object item) {
    array[next] = item;
    next++;
}
public Object remove () {
    Object result = array[first];
    first++;
    return result;
}

347
Metode  add  terlihat seperti  push  di subbab 15.12; ia meletakkan item baru ke dalam 

ruang kosong di bagian berikutnya lalu menaikkan nilai indeksnya.

Implementasi remove sama saja. Metode ini mengambil item pertama dari antrian lalu 

menaikkan first sehingga ia mengacu ke kepala baru milik antrian. Gambar berikut ini 

menunjukkan seperti apa tampilan antrian ketika kedua item sudah dihapus.

Adalah selalu benar bahwa next menunjuk ke ruang yang masih kosong. Jika first  telah 

melebihi next dan menunjuk ke ruang yang sama, maka first sedang mengacu ke lokasi 

yang “kosong”. Saya memberi tanda kutip pada kata kosong karena ada kemungkinan 

bahwa   lokasi   yang   ditunjuk   oleh  first  sebenarnya   memiliki   suatu   nilai   (kita   tidak 

melakukan apapun untuk memastikan apakah lokasi yang kosong berisi  null); di sisi 

lain, karena kita sudah mengetahui kalau antrian itu memang kosong; kita tidak akan 

pernah   membaca   lokasi   ini,   jadi   kita   bisa   menganggapnya,   secara   abstrak,   sebagai 

sesuatu yang kosong.

Latihan 16.1 

Modifikasilah  remove  sehingga ia bisa mengembalikan  null  jika suatu antrian sedang 

kosong.

Masalah berikutnya dari implementasi ini adalah karena ia akan menghabiskan banyak 

ruang. Ketika kita menambahkan sebuah item, kita juga menaikkan nilai next dan ketika 

348
kita   kita   menghapus   sebuah   item   kita   menaikkan  first,   tapi   sayangnya   kita   tidak 

menurunkan nilai keduanya. Apa yang akan terjadi jika kita sudah sampai di ujung 

array?

Gambar   berikut   ini   menunjukkan   keadaan   antrian   setelah   kita  menambahkan   empat 

item lagi:

array­nya   sekarang   telah   penuh.   Tidak   ada   lagi   “ruang   kosong   berikutnya”.   Jadi 

sekarang next tidak bisa menunjuk ke mana­mana lagi. Satu kemungkinan adalah kita 

bisa   mengubah   ukuran  array,  seperti  yang   telah  kita  lakukan   dengan  impelementasi 

untuk  stack. Tapi di kasus  itu, array­nya akan terus membesar tanpa peduli dengan 

berapa banyak jumlah item yang sedang berada di dalam antrian. Solusi yang lebih baik 

adalah   dengan   melakukan   “wrap   around”   (baca:   putaran)   ke   awal   array   lalu 

menggunakan kembali ruang­ruang yang masih ada di sana. “wrap around” seperti ini 

adalah alasan kenapa implementasi ini disebut dengan “circular buffer”.

Salah   satu   cara   untuk   memutar   indeks   adalah   dengan   menambahkan   sebuah   kasus 

khusus dimanapun kita menaikkan nilai sebuah indeks:
next++;
if (next == array.length) next = 0;

Alternatif yang lebih cantik adalah dengan menggunakan operator modulus:
next = (next + 1) % array.length;

349
Sampai   di   sini   kita   masih   memiliki   satu   masalah   terakhir   yang   harus   diselesaikan. 

Bagaimana   kita   bisa   tahu   kalau   antrian   benar­benar   sudah   penuh,   maksudnya;   kita 

sudah  tidak bisa lagi menambahkan item lainnya? Gambar berikut ini menunjukkan 

tampilan antrian ketika sedang berstatus “penuh”.

Masih tersisa satu ruang kosong di dalam array, tapi antrian itu sudah penuh karena jika 

kita   menambahkan   item   lainnya,   maka   kita   harus   menaikkan  next  sedemikian   rupa 

sehingga  next   ==   first,   dan   dalam   kasus   ini,   antrian   akan   kelihatan   sedang   berada 

dalam status kosong! 

Untuk menghindari hal kondisi seperti di atas, kita akan mengorbankan satu ruag dalam 

array. Jadi bagaimana kita bisa bilang kalau antrian itu sudah penuh?
if ((next + 1) % array.length == first)
Dan apa yang harus kita lakukan jika array­nya penuh? Dalam kasus ini, mengubah 

ukuran array mungkin adalah satu­satunya cara.

Latihan 16.2

Tulislah   sebuah   impelementasi   antrian   menggunakan   circular   buffer   yang   bisa 

mengubah ukurannya sendiri ketika sedang perlu.

350
16.5 Priority Queue

ADT  Antrian Prioritas mempunyai antarmuka yang sama seperti ADT Antrian, tapi 

semantiknya berbeda. Antarmukanya adalah sebagai berikut:

constructor: membuat sebuah antrian yang baru sekaligus kosong.

Add: menambahkan sebuah item baru ke dalam antrian.

remove:   menghapus   dan   mengembalikan   sebuah   item   dari   antrian.   Item   yang 

dikembalikan adalah item yang mempunyai prioritas tertinggi.

isEmpty: memeriksa apakah antriannya kosong ataukah tidak.

Yang dimaksud dengan perbedaan semantik adalah bahwa item yang telah dihapus dari 

antrian   tidaklah   harus   berupa   item   yang   pertama   kali   dimasukkan/   ditambahkan. 

Sebaliknya, item tersebut harus berstatus sebagai item dengan prioritas tertinggi. Apa 

yang   dimaksud   dengan   prioritas,   dan   bagaimana   mereka   dibandingkan   dengan   satu 

sama   lainnya   tidak   ditentukan   oleh   implementasi   Antrian   Prioritas.   Semuanya 

tergantung dari item­item apa yang berada di dalam antrian tersebut.

Sebagai contoh, jika item­item di dalam antrean mempunyai nama, kita mungkin akan 

memilih mereka secara sesuai urutan alfabet. Jika mereka merupakan skor permainan 

bowling,   kita   mungkin   memilih   dari   urutan   tertinggi   ke   urutan   terendah,   tapi   jika 

mereka   itu   skor   permainan   golf,   mungkin   kita   akan   memprioritaskan   angka/item 

terendah ke yang tertinggi.

Jadi sekarang kita mempunyai masalah baru. Kita menginginkan sebuah implementasi 

Antrean Prioritas yang sifatnya generik – harus bisa bekerja dengan objek apapun – tapi 

pada saat yang bersamaan, kode yang mengimplementasikan Antrian Prioritas harus 

memiliki kemampuan untuk membandingkan objek­objek yang dikandungnya.

351
Kita   sudah   melihat   satu   cara   untuk   mengimplementasikan   struktur   data   generik 

menggunakan Object, tapi itu tidak menyelesaikan masalah ini, karena tidak ada cara 

untuk membandingkan Object kecuali kita sudah tahu objek itu bertipe apa.

Jawabannya terdapat dalam sebuah fitur Java yang disebut metaclass.

16.6 Metaclass

Metaclass   adalah   suatu   kumpulan   kelas   yang   menyediakan   satu   kumpulan   metode. 

Definisi metaclass mengharuskan sebuah kelas untuk memenuhi persyaratan yang sudah 

ditentukan agar bisa menjadi anggota dari suatu kumpulan. 

Terkadang metaclass­metaclass memiliki nama yang diakhiri dengan kata “able” untuk 

mengindikasikan   kemampuan   dasar   (fundamental)   yang   dibutuhkan   oleh   metaclass. 

Sebagai   contoh,   semua   kelas   yang   menyediakan   metode   dengan   nama  draw  bisa 

menjadi   anggota   dari   metaclass  Drawable.   Semua   kelas   yang   mengandung   metode 

start bisa menjadi anggota dari metaclass Runnable.

Java   menyediakan   sebuah   metaclass   bawaan   yang   bisa   kita   gunakan   dalam   sebuah 

implementasi untuk Antrian Prioritas. Metaclass ini disebut  Comparable, dan artinya 

sesuai dengan namanya. Semua kelas yang menjadi anggota metaclass  Comparable 

harus   menyediakan   sebuah   metode   dengan   nama  compareTo  yang   mampu 

membandingkan   dua   objek   lalu   mengembalikan   sebuah   nilai   yang   mengindikasikan 

apakah   satu   argumen   lebih   besar   atau   lebih   kecil   ketimbang   argumen   lainnya,   atau 

apakah keduanya merupakan dua argumen yang sama.

Umumnya kelas­kelas bawaan Java merupakan anggota dari metaclass  Comparable, 

termasuk kelas­kelas pembungkus numerik seperti Integer dan Double.

Di subbab berikutnya saya akan menunjukkan bagaimana caranya menulis sebuah ADT 

352
yang bisa memanipulasi sebuah metaclass. Lalu kita akan melihat bagaimana caranya 

menulis sebuah kelas baru yang akan menjadi anggota dari metaclass yang sudah ada. 

Di   bab   berikutnya   kita   akan   melihat   bagaimana   caranya   mendefinisikan   sebuah 

metaclass baru.

16.7 Implementasi Array untuk Antrian Prioritas

Dalam implementasi Antrian Prioritas, setiap kali kita menentukan tipe item­item yang 

berada   dalam   antrian,   kita   menentukan   metaclass  Comparable.   Sebagai   contoh, 

variabel­variabel instan berikut merupakan sebuah array yang berisi Comparable  dan 

sebuah integer:
public class PriorityQueue {
private Comparable[] array;
private int index;
}

Seperti biasa, index merupakan indeks dari ruang berikutnya yang masih tersisa/kosong 

dalam array. Variabel­variabel instan dideklarasikan dengan  private  agar kelas­kelas 

lainnya tidak bisa mengakses mereka secara langsung.

Konstruktor   dan  isEmpty  masih   sama   dengan   yang   pernah   kita   lihat   sebelumnya. 

Ukuran awal dari array­nya silahkan Anda tentukan sendiri. 
public PriorityQueue () {
array = new Comparable [16];
index = 0;
}

public boolean isEmpty () {
return index == 0;

353
}

add sama dengan push:

public void add (Comparable item) {
     if (index == array.length) {
     resize ();
    }
    array[index] = item;
    index++;
}

Satu­satunya metode penting dalam kelas adalah remove, yang harus menelusuri array 

untuk menemukan lalu menghapus item terbesar:
public  Comparable  remove  () {
      if (index  ==  0) return  null;
     
      int maxIndex  = 0;

        //   find   the   index   of   the   item   with   the   highest  


priority
    for  (int  i=1;  i<index;  i++)  {
         if  (array[i].comp areTo  (array[max   Index])  > 0) {
          maxIndex  = i;
         }
      }

      Comparable  result  = array[maxInd ex];

      // move  the  last item  into  the  empty  slot


      index­ ­;

354
      array[maxIndex ] =  array[index];
      return  result;
}

Ketika kita menelusuri array, maxIndex menjaga jejak elemen terbesar yang sudah kita 

lihat sejauh ini. Yang dimaksud dengan “terbesar” di sini akan ditentukan oleh metode 

compareTo. Dalam kasus ini, metode compareTo disediakan oleh kelas Integer, dan ia 

melakukan   apa   yang   memang   kita   inginkan   –   angka   terbesar   (lebih   positif)   adalah 

pemenangnya.

16.8 Klien Antrian Prioritas

Implementasi Antrian Prioritas seluruhnya ditulis menggunakan susut pandang objek­

objek  Comparable, tapi tidak ada objek yang bisa disebut sebagai sebuah objek dari 

metaclass Comparable! Kalau tidak percaya, cobalah untuk membuat satu objek saja:

Comparable comp = new Comparable (); // ERROR

Anda   akan   melihat   pesan  compile­time  yang   berbunyi   “java.lang.Comparable   is   an 

interface. It can't be instantiated”.  Di Java, metaclass­metaclass juga disebut dengan 

interface (antarmuka). Sampai sejauh ini saya telah menghindari kata ini karena ia juga 

memiliki beberapa arti sekaligus, tapi sekarang Anda semua harus tahu.

Kenapa metaclass­metaclass itu tidak bisa diinstansiasi? Karena sebuah metaclass hanya 

menentukan   apa­apa   yang   sudah   disyaratkan   (Anda   harus   mempunyai   metode 

compareTo); ia sendiri tidak menyediakan suatu implementasi.

Untuk   membuat   sebuah   objek  Comparable,   Anda   harus   membuat   satu   objek   yang 

dimiliki oleh satu paket  Comparable, seperti  Integer. Kemudian barulah Anda bisa 

menggunakan objek tersebut dimanapun metaclass Comparable dipanggil.

PriorityQueue pq = new PriorityQueue ();

355
Integer item = new Integer (17);
pq.add (item);

Kode ini akan membuat satu Antrian Prioritas yang baru sekaligus kosong, juga sebuah 

objek  Integer.   Kemudian   kode   ini   akan   menambahkan  Integer  ke   dalam   antrian. 

Metode  add  mengharapkan sebuah  Comparable  sebagai sebuah parameter, jadi dia 

dengan senang hati menerima sebuah  Integer. Jika kita mencoba untuk melewatkan 

sebuah  Rectangle  yang   bukan   merupakan   anggota  Comparable,   kita   akan 

mendapatkan   sebuah   pesan  compile­time  yang   berbunyi,   “Incompatible   type   for 

method. Explicit cast needed to convert java.awt.Rectangle to java.lang.Comparable”.

Itulah yang dikatakan oleh compiler kepada kita. Jadi, jika kita ingin membuat konversi 

itu   terjadi,   maka   kita   harus   melakukannya   secara   eksplisit.   Kita   mungkin   akan 

melakukan apa yang dikatakan oleh compiler tersebut:
Rectangle rect = new Rectangle ();
pq.add ((Comparable) rect);

Tetapi di dalam kasus seperti ini kita justru menerima pesan error yang terkait dengan 

ClassCastException.   Ketika  Rectangle  mencoba   untuk   melewatkan   sebagai   sebuah 

Comparable,   sistem  run­time  akan   memeriksa   apakah   cara   ini   memenuhi   semua 

persyaratan, lalu menolaknya. Jadi, itulah yang akan kita dapatkan jika kita mengikuti 

saran dari compiler.

Untuk mengeluarkan item­item dari antrian, kita harus membalik prosesnya:
while (!pq.isEmpty ()) {
item = (Integer) pq.remove ();
System.out.println (item);
}

356
Perulangan   ini   menghapus   semua   item   dari   antrian   lalu   mencetaknya.   Proses   ini 

mengasumsikan bahwa item­item   yang berada di dalam antrian  merupakan  Integer. 

Karena   jika   mereka   bukan  Integer,   kita   akan   mendapatkan   sebuah 

ClassCastException.

16.9 Kelas Golfer

Akhirnya, mari kita lihat bagaimana caranya membuat sebuah kelas baru yang akan 

menjadi   anggota  Comparable.   Sebagai   sebuah   contoh   atas   sesuatu   dengan   definisi 

yang tidak biasa tentang prioritas “tertinggi” kita akan menggunakan para pemain golf 

(golfers):
public class Golfer implements Comparable {
    String name;
    int score;

public Golfer (String name, int score) {
    this.name = name;
    this.score = score;
   }
}

Definisi   kelas   dan   konstruktor   selalu   hampir   sama   dengan   yang   sudah   kita   buat 

sebelumnya; bedanya adalah karena untuk saat ini kita harus bisa membuat deklarasi 

agar   kelas  Golfer  bisa   mengimplementasikan   metaclass  Comparable    (Golfer 

implement Comparable). Dalam kasus ini kata kunci implement berarti bahwa Golfer 

mengimplementasikan antarmuka yang ditentukan oleh Comparable.

357
Jika sekarang kita mencoba untuk meng­compile  Golfer.java, kita akan mendapatkan 

pesan   yang   berbunyi   “class   Golfer   must   be   declared   abstract.   It   doesn't   define   int 

compareTo (java.lang.Object) from interface java.lang. Comparable”. Dengan kata lain, 

agar   bisa   menjadi  Comparable,  Golfer  harus   menyediakan   sebuah   metode   dengan 

nama compareTo. Oke, kalau begitu, mari kita tulis sekarang juga:

public int compareTo (Object obj) {
    Golfer that = (Golfer) obj;

    int a = this.score;
    int b = that.score;

    // dalam golf, yang kecil itu lebih baik
    if (a<b) return 1;
    if (a>b) return ­1;
    return 0;
}

Dua hal yang ada di sini membuat kita sedikit terkejut. Satu, parameternya merupakan 

sebuah  Object. Ini karena secara umum si pemanggil tidak mengetahui objek bertipe 

apa yang sedang dibandingkan. Sebagai contoh, dalam PriorityQueue.java, ketika kita 

memanggil compareTo, kita juga melewatkan sebuah Comparable sebagai parameter. 

Kita tidak perlu tahu apakah ia termasuk Integer, Golfer, atau apapun itu. 

Di  dalam  compareTo, kita  harus mengubah   parameter dari   sebuah  Object  menjadi 

Golfer. Seperti biasa, akan ada risiko ketika kita menggunakan tipe cast seperti ini: jika 

kita meng­cast ke tipe yang salah maka kita akan mendapatkan pesan eksepsi.

Akhirnya, kita bisa membuat beberapa pemain golf:

358
Golfer tiger = new Golfer ("Tiger Woods", 61);
Golfer phil = new Golfer ("Phil Mickelson", 72);
Golfer hal = new Golfer ("Hal Sutton", 69);

Lalu memasukkan mereka ke dalam antrian:
pq.add (tiger);
pq.add (phil);
pq.add (hal);

Ketika kita mengeluarkan mereka:
while (!pq.isEmpty ()) {
golfer = (Golfer) pq.remove ();
System.out.println (golfer);
}

Mereka akan ditampilkan dalam urutan terbalik (khusus untuk pemain golf):
Tiger Woods  61
Hal Sutton  69
Phil Mickelson  72

Ketika kita beralih dari Integer ke Golfer, kita tidak perlu membuat perubahan apapun 

dalam  PriorityQueue.java.   Sama  sekali   tidak!   Jadi   sekarang   kita   telah   berhasil 

mengatasi   jurang   antara  PriorityQueue  dan   kelas­kelas   yang   menggunakannya. 

Dengan   kondisi   ini,   kita   bisa   menggunakan   ulang   kode   tersebut   tanpa   harus 

mengubahnya. Lebih jauh lagi, kita bisa memberikan kendali kepada kode klien melalui 

definisi yang sudah kita buat untuk compareTo. Dengan cara seperti ini, implementasi 

PriorityQueue akan menjadi lebih adaptif.

359
16.10 Daftar Kata­Kata

Istilah Arti
Sekumpulan objek yang sedang menantikan suatu layanan 
queue
atau sejenisnya.
Aturan yang menentukan anggota antrian mana yang akan 
queueing discipline
dihapus lebih dulu. 
“first in first out”, sebuah aturan antrian di mana anggota 

FIFO yang pertama kali datang akan menjadi yang pertama kali 

dihapus.
Suatu aturan antrian di mana setiap anggotanya mempunyai 

prioritas   yang   ditentukan   oleh   faktor­faktor   eksternal. 


priority queue
Anggota yang mempunyai prioritas tertinggi adalah anggota 

yang pertama kali kita hapus.
Sebuah   ADT   yang   mendefinisikan   operasi­operasi   yang 

Priority Queue mungkin   akan   dilakukan   oleh   seseorang   terkait   dengan 

antrian berprioritas.
Suatu   definisi   kelas   yang   mengimplementasikan   sebuah 

ADT dengan definisi­definisi metode yang merupakan hasil 

pemanggilan dari metode­metode lainnya, terkadang dengan 
veneer
beberapa perubahan kecil. Veneer tidak mengerjakan fungsi 

yang   signifikan,   tapi   dia   bisa   meningkatkan   atau 

menstandardisasi antarmuka yang dilihat oleh klien. 
Bahaya   yang   terkait   dengan   penggunaan   veneer   ketika 

beberapa metode mungkin diimplementasikan secara tidak 
performance hazard
efisien sehingga metode tersebut justru malah tidak tampak 

oleh klien.

360
Operasi   yang   memiliki  run­time  yang   tidak   bergantung 
constant time
kepada ukuran struktur datanya.
Operasi yang run­time­nya berupa fungsi linear dari ukuran 
linear time
struktur datanya.
Implementasi antrian menggunakan linked list dan acuan ke 
linked queue
node pertama dan terakhir.
Implementasi   antrian   menggunakan   array  dan   indeks   dari 

circular buffer elemen pertama dan ruang kosong yang ada di sebelahnya 

(next available space).
Kumpulan   kelas­kelas.   Spesifikasi   metaclass   berisi 

metaclass persyaratan­persyaratan   yang   harus   dipenuhi   oleh   suatu 

kelas agar bisa dimasukkan ke dalam kumpulan.
Istilah   Java   untuk   menyebut   metaclass.   Jangan   sampai 
interface
dibingungkan dengan arti kata interface yang lebih luas.

16.11 Latihan

Latihan 16.3

Pertanyaan ini berdasarkan Latihan 9.3.

Tulislah sebuah compareTo untuk kelas Rational yang memungkinkan Rational untuk 

mengimplementasikan Comparable. 

Petunjuk: jangan lupa bahwa parameter adalah sebuah Object.

Latihan 16.4

Tulislah   definisi   kelas   untuk  SortedList  yang   merupakan   perluasan   dari   kelas 

LinkedList. SortedList sama dengan LinkedList; bedanya, elemen­elemen SortedList 

361
harus menjadi anggota Comparable, dan list­nya tersusun dalam urutan terbalik.

Tulislah sebuah metode objek add untuk SortedList yang menggunakan Comparable 

sebagai parameter dan mampu menambahkan objek baru ke dalam list, pada lokasi yang 

tepat sehingga list­nya tetap berada dalam posisi terurut.

Jika Anda mau, Anda bisa menulis satu metode helper dalam kelas Node.

Latihan 16.5

Tulislah satu metode objek,  maximum, untuk kelas  LinkedList  yang bisa dipanggil 

melalui objek LinkedList. Metode ini bisa mengembalikan objek kargo terbesar dalam 

list, atau null jika list­nya kosong.

Anda   bisa   mengasumsikan   bahwa   semua   elemen   kargo   menjadi   milik   kelas   yang 

menjadi anggota metaclass Comparable, dan setiap dua elemen bisa dibandingkan satu 

sama lainnya.

Latihan 16.6

Tulislah   implementasi   untuk   Antrian   Prioritas   menggunakan   linked   list.   Ada   tiga 

tahapan yang harus Anda proses:

● Antrian   Prioritas   mungkin   berisi   sebuah   objek   LinkedList   sebagai   sebuah 

variabel instan.

● Antrian Prioritas mungkin berisi sebuah acuan ke objek Node pertama dalam 

linked list.

● Antrian Prioritas diwarisi dari kelas LinkedList yang sudah ada.

Pikirkan mengenai pro dan kontra dari ketiga tahapan di atas kemudian pilihlah salah 

satu  diantaranya. Selain itu,  Anda juga  bisa memilih;  untuk menjaga list  agar  tetap 

terurut (slow add, fast remove), atau tidak terurut (slow remove, fast add).

362
Latihan 16.7

Antrian Kegiatan adalah sebuah struktur data yang menjaga urutan kegiatan, di mana 

setiap   kegiatan   mempunyai   waktu   pelaksanaan   yang   terkait   dengannya.   Berikut   ini 

adalah ADT­nya:

constructor: membuat antrian kegiatan yang baru dan kosong

add:  menambahkan   sebuah   kegiatan   baru   ke   dalam   antrian.   Parameternya   adalah 

kegiatan   yang   merupakan   sebuah  Object,   dan   waktu   pelaksanaan   kegiatan   tersebut 

yang berupa objek Date. Objek kegiatannya tidak boleh bernilai null.

nextTime:   mengembalikan  Date  untuk   pelaksanaan   kegiatan   berikutnya,   kegiatan 

“berikut”   di   sini   adalah   kegiatan   di   dalam   antrian   yang   dimulai   lebih   dulu.   Jangan 

menghapus kegiatan ini dari antrian. Kembalikan nilai null jika antriannya kosong.

nextEvent:   mengembalikan   kegiatan   berikutnya   (sebuah  Object)   dari   antrian   lalu 

menghapusnya dari antrian. Kembalikan nilai null jika antriannya kosong.

Kelas  Date  didefinisikan dalam  java.util. Kelas ini mengimplementasikan metaclass 

Comparable. Menurut dokumentasinya, metode compareTo­nya mengembalikan “the 

value 0 if the argument Date  is equal to this Date; a value less than 0 if this Date is 

before  the Date argument; and a value  greater than 0 if this Date is after the Date 

argument”.

Tulislah   sebuah   implementasi   untuk   antrian   kegiatan   menggunakan   ADT 

PriorityQueue. Anda tidak boleh membuat asumsi mengenai bagaimana PriorityQueue 

diimplementasikan.

Hint: buatlah sebuah kelas, Event, yang berisi Date dan sebuah Object kegiatan. Kelas 

ini harus mengimplementasikan Comparable dengan tepat.

363
Bab 17

Pohon (Trees)

17.1 Simpul Pohon

Laiknya list, pohon terdiri dari simpul­simpul. Salah satu pohon yang paling banyak 

dikenal adalah pohon biner (binary tree). Setiap simpul pohon ini berisi sebuah acuan 

yang   mengacu   ke   dua   simpul   lainnya   (kemungkinan   null).   Definisi   kelasnya   akan 

tampak sebagai berikut:
public class Tree {
Object cargo;
Tree left, right;
}

Seperti simpul­simpul dalam list, simpul­simpul pohon juga berisi kargo: dalam hal ini 

berupa  Object  yang generik. Variabel­variabel instan lainnya dinamai  left  dan  right, 

yang sesuai dengan standar mata kita ketika direpresentasikan menggunakan gambar:

Puncak pohon (simpul yang diacu dengan nama tree) disebut akar (root). Agar sesuai 

364
dengan istilah­istilah dalam dunia perpohonan (baca: metafora pohon), simpul­simpul 

lain akan disebut cabang­cabang (branches). Sementara simpul yang berada di posisi 

bagian bawah yang mengacu ke null disebut daun­daun (leaves). Mungkin di sini kita 

telah melakukan sesuatu yang ganjil dengan menggambar akar di atas sementara daun­

daun malah di bawah. Tapi tunggu dulu, itu bukanlah hal teraneh. 

Untuk membuatnya lebih aneh lagi, ilmuwan komputer mengombinasikannya dengan 

metafora lain: pohon keluarga (the family tree). Simpul yang berada di atas biasanya 

disebut  parent  (induk)   sementara   simpul­simpul   yang   diacunya   disebut  children 

(anak).   Simpul­simpul   dengan   induk   yang   sama   disebut  siblings,   begitu   juga 

sebaliknya.

Akhirnya,   kita   juga   akan   menjumpai   kosakata   bidang   geometri   ketika   berbicara 

mengenai pohon. Saya sudah menyebutkan kanan dan kiri, dan sekarang ada lagi “up” 

(menuju ke induk/akar)  dan “down” (menuju ke anak/daun). Selain itu, semua simpul 

yang mempunyai jarak yang sama dari akar merupakan level dari sebuah pohon.

Saya sendiri tidak tahu kenapa kita harus menggunakan tiga metafora sekaligus ketika 

berbicara tentang pohon, tapi itulah fakta yang ada.

17.2 Membuat Pohon

Proses penyusunan simpul­simpul pohon mirip dengan proses ketika kita merangkai 

list.   Kita   mempunyai   sebuah   konstruktor   untuk   simpul­simpul   pohon   yang 

menginisialisasi variabel­variabel instan.
public Tree (Object cargo, Tree left, Tree right) {
this.cargo = cargo;
this.left = left;
this.right = right;
}

365
Awalnya kita akan mengalokasikan tempat untuk simpul­simpul anak terlebih dahulu:
Tree left = new Tree (new Integer(2), null, null);
Tree right = new Tree (new Integer(3), null, null);

Kita bisa membuat simpul induk lalu mengaitkannya ke simpul anak pada saat yang 

bersamaan:
Tree tree = new Tree (new Integer(1), left, right);

Kode ini menghasilkan keadaan seperti yang ditunjukkan pada gambar sebelumnya. 

17.3 Menelusuri Pohon

Cara paling alami untuk menelusuri sebuah pohon adalah dengan memakai metode yang 

rekursif. Sebagai contoh, untuk menambahkan semua integer ke dalam satu pohon, kita 

bisa menulis metode kelas sebagai berikut:
public static int total (Tree tree) {
if (tree == null) return 0;
Integer cargo = (Integer) tree.cargo;
return   cargo.intValue()   +   total   (tree.left)   + 
total (tree.right);
}

Metode   di atas merupakan  metode kelas karena kita akan  menggunakan  null  untuk 

merepresentasikan pohon yang kosong. Nantinya, pohon kosong inilah yang akan kita 

jadikan base case metode rekursif kita. Jika suatu pohon diketahui kosong, metode kita 

akan  mengembalikan   nilai 0.  Kalau  tidak,  metode ini  akan  membuat  dua  panggilan 

bersifat rekursif untuk menemukan nilai total dari dua anaknya. Akhirnya, metode ini 

akan menambahkan nilai total ini ke dalam kargonya lalu mengembalikan nilai total.

366
Meskipun   metode   ini   bekerja   dengan   baik,   ada   beberapa   kesulitan   yang   akan 

menghadang   kita   ketika   kita   hendak   mengimplementasikannya   dengan   konsep 

pemrograman berorientasi objek. Metode ini harusnya tidak boleh muncul dalam kelas 

Tree  karena   ia   membutuhkan   kargo   untuk   menjadi   objek­objek  Integer.   Jika   kita 

membuat asumsi ini dalam Tree.java maka kita akan kehilangan manfaat­manfaat yang 

bisa kita ambil dari penggunaan struktur data generik.

Di sisi lain, kode ini mengakses variabel­variabel instan simpul­simpul pohon. Jadi dia 

“mengetahui” lebih banyak ketimbang yang seharusnya mengenai implementasi suatu 

pohon.   Jika   kita  mengubah   implementasi   ini,   kodenya   nanti  rusak   (baca:   tidak  bisa 

dipakai) .  

Nanti   di   bagian   lain   dalam   bab   ini,   kita   akan   mengembangkan   sebuah   cara   untuk 

menyelesaikan  masalah  ini,  membolehkan  kode  klien  untuk   menelusuri  pohon  yang 

berisi   objek   apapun   tanpa   merusak   perbedaan   abstraksi   antara   kode   klien   dan 

implementasinya. Sebelum kita sampai ke sana, mari kita melihat sebuah aplikasi yang 

memanfaatkan konsep pohon ini.

17.4 Pohon Ekspresi

Pohon merupakan cara alami untuk merepresentasikan struktur/susunan suatu ekspresi 

matematika. Tidak seperti notasi dalam bidang lain, pohon mampu merepresentasikan 

proses komputasi tanpa harus mendatangkan ambiguitas. Sebagai contoh, ekspresi infix 

untuk 1 + 2 * 3 termasuk yang mendatangkan ambiguitas, kecuali kalau kita mengetahui 

bahwa unsur perkalian diproses lebih dahulu ketimbang unsur penjumlahan.

Gambar berikut ini menunjukkan komputasi yang sama:

367
Simpul­simpul di atas bisa saja merupakan sebuah operan seperti 1 dan 2 atau berupa 

operator­operator   seperti   +   dan   *.   Operan­operan   merupakan   simpul­simpul   daun; 

sementara simpul­simpul operator berisi acuan yang mengacu ke operan­operan mereka 

(semua operator di sini disebut operator  biner  (binary), karena mereka mempunyai 

tepat dua operan).

Berdasarkan   gambar   di   atas,   tidak   usah   ditanya   lagi   bagaimana   urutan   operasi   ini 

terjadi: unsur perkalian dikerjakan terlebih dahulu sebelum proses penjumlahan terjadi.

Pohon ekspresi seperti ini mempunyai banyak manfaat. Contoh yang akan kita lihat 

adalah dalam proses pengubahan (baca: penerjemahan) dari satu format (postfix) ke 

format lainnya (infix). Pohon­pohon yang sama digunakan di dalam  compiler  untuk 

melakukan proses penguraian (parse), optimalisasi dan menerjemahkan program. 

17.5 Penelusuran

Saya sebelumnya sudah menunjukkan bahwa rekursi sebenarnya merupakan cara yang 

alami untuk menelusuri satu pohon. Kita bisa mencetak isi suatu pohon ekspresi dengan 

cara seperti ini:

368
public static void print (Tree tree) {
if (tree == null) return;
System.out.print (tree + " ");
print (tree.left);
print (tree.right);
}

Dengan   kata   lain,   untuk   mencetak   satu   pohon,   langkah   pertama   adalah   dengan 

mencetak   isi   akarnya,   lalu   mencetak   semua   subpohon   sebelah   kiri,   baru   kemudian 

mencetak seluruh subpohon yang ada di bagian kanan. Cara penelusuran seperti ini 

disebut preorder, karena isi dari akar muncul sebelum isi anak­anaknya muncul.

Untuk ekspresi contoh tadi, outputnya adalah + 1 * 2 3. Hasil ini berbeda dari hasil yang 

didapat   ketika   menggunakan   postfix   atau   infix;   output   ini   adalah   notasi   baru   yang 

dikenal   dengan   istilah  prefix.   Dalam   notasi   ini,   operator­operator   muncul   sebelum 

operan­operan mereka.

Anda mungkin sudah menduga bahwa jika kita menelusuri suatu   pohon   dengan   urutan 

yang berbeda maka kita akan mendapatkan ekspresi dalam notasi yang berbeda pula. 

Sebagai contoh, jika kita mencetak subpohon dulu, lalu dilanjutkan dengan simpul akar:

public static void printPostorder (Tree tree) {
if (tree == null) return;
printPostorder (tree.left);
printPostorder (tree.right);
System.out.print (tree + " ");
}

Kita   akan   mendapatkan   ekspresi   postfix   (1   2   3   *   +)!   Seperti   namanya,   urutan 

369
penelusuran seperti ini disebut  postorder. Akhirnya, untuk menelusuri sebuah pohon 

secara  inorder,   kita   cetak   dulu   bagian   kiri   pohon,   kemudian   akar,   diakhiri   dengan 

bagian kanannya:

public static void printInorder (Tree tree) {
if (tree == null) return;
printInorder (tree.left);
System.out.print (tree + " ");
printInorder (tree.right);
}

Hasilnya adalah 1 + 2 * 3, yang merupakan ekspresi infix.

Jujur   saja,   saya   harus   mengatakan   bahwa   sebenarnya   saya   telah   mengacuhkan 

komplikasi penting. Terkadang, ketika kita menulis sebuah ekspresi infix, kita harus 

menggunakan   tanda   kurung   (parentheses)   untuk   menjaga   urutan   operasi­operasinya. 

Jadi,   penelusuran   secara  inorder  belumlah   cukup   untuk   menghasilkan   satu   ekspresi 

infix.

Meskipun begitu, dengan beberapa perbaikan, pohon ekspresi dan ketiga penelusuran 

rekursif tersebut mampu memberikan teknik/cara yang umum untuk menerjemahkan 

ekspresi dari satu format ke format lainnya.

17.6 Enkapsulasi

Seperti yang sudah saya katakan sebelumnya, masih ada masalah dengan teknik/cara 

yang   kita   ambil   dalam   menelusuri   pohon­pohon:   cara   ini   membuat   kita   harus 

memisahkan   kode   klien   (aplikasi   yang   menggunakan   pohon)   dengan   kode  provider 

(implementasi Pohon). Idealnya, suatu pohon harusnya bersifat umum; ia tidak harus 

370
tahu segala sesuatu tentang pohon­pohon ekspresi. Sementara kode yang menghasilkan 

sekaligus   menelusuri   pohon­pohon   ekspresi   tidak   perlu   tahu   segala   sesuatu   tentang 

implementasi   pohon­pohon.   Prinsip/standar   perancangan   seperti   ini   disebut  object 

encapsulation (enkapsulasi objek). Istilah ini digunakan agar Anda tidak kebingungan 

dengan istilah yang sudah ada dalam subbab 6.6, yakni method encapsulation.

Untuk versi saat ini, kode Tree tahu terlalu banyak tentang kliennya. Sebaliknya, kelas 

Tree harus menyediakan kemampuan/kapabilitas umum untuk melakukan penelusuran 

satu pohon dengan beragam cara. Ketika penelusuran sedang dilakukan, ia harus bisa 

memproses operasi di setiap simpul yang ditentukan oleh klien. 

Untuk memfasilitasi perbedaan kepentingan ini, kita akan membuat sebuah metaclass 

baru yang disebut Visitable. Item­item yang disimpan dalam sebuah pohon disyaratkan 

agar   bisa   dikunjungi   (visitable).   Ini   berarti   bahwa   item­item   tersebut   akan 

mendefinisikan sebuah metode – visit – yang akan melakukan apapun yang diinginkan 

oleh klien terhadap masing­masing simpul. Dengan cara ini, Pohon kita akan mampu 

melakukan penelusuran sementara klien mampu mengerjakan operasi­operasi simpul.

Berikut ini adalah langkah­langkah yang harus kita kerjakan untuk membuat metaclass 

yang bisa digunakan oleh kedua kubu sekaligus, klien dan provider:

1. Definisikanlah sebuah metaclass yang mampu mengidentifikasi metode­metode 

yang   akan   dibutuhkan   oleh   kode  provider  untuk   melakukan   pemanggilan 

melalui komponen­komponennya.

2. Tulislah kode  provider  sebagai satu metaclass yang baru, sebagai lawan dari 

Object yang bersifat generik.

3. Definisikanlah sebuah kelas yang menjadi bagian dari metaclass dan mampu 

mengimplementasikan metode­metode yang memang dibutuhkan oleh klien.

4. Tulislah kode klien untuk menggunakan kelas yang baru tersebut.

371
Subbab berikutnya akan mendemonstrasikan langkah­langkah ini.

17.7 Mendefinisikan metaclass

Sebenarnya   terdapat   dua   cara   untuk   mengimplementasikan   sebuah   metaclass   dalam 

Java, sebagai interface atau sebagai abstract class. Perbedaan antara keduanya tidaklah 

terlalu   penting   untuk   saat   ini,   jadi   kita   akan   mulai   dengan   mendefinisikan   sebuah 

antarmuka (interface).

Definisi antarmuka tampak seperti definisi kelas, dengan dua perbedaan:

● kata kunci class diganti dengan interface, dan

● definisi metode tidak mempunyai badan (bodies).

Definisi   antarmuka   menentukan   metode­metode   yang   harus   diimplementasikan   oleh 

sebuah kelas agar bisa menjadi anggota metaclass. Syarat­syarat yang harus dipenuhi 

antara lain; nama, tipe­tipe parameter, dan tipe pengembalian dari setiap metode.

Definisi Visitable adalah sebagai berikut

public interface Visitable {
public void visit ();
}

Itu saja, cukup! Definisi  visit  tampak seperti definisi metode pada umumnya, kecuali 

bahwa   sekarang   kita   tidak   memerlukan   badan.   Definisi   ini   mengindikasikan   bahwa 

semua kelas yang mengimplementasikan  Visitable  harus mempunyai metode dengan 

nama visit yang tidak membutuhkan parameter apapun dan mengembalikan void.

Seperti definisi kelas lainnya, definisi antarmuka memiliki nama file yang sama dengan 

nama kelasnya (dalam hal ini Visitable.java).

372
17.8 Mengimplementasikan Metaclass

Jika   kita   menggunakan   sebuah   pohon   ekspresi   untuk   menghasilkan   infix,   maka 

“mengunjungi” satu simpul berarti mencetak isi­isinya. Karena isi dari sebuah pohon 

ekspresi   berupa  token,   kita   akan   membuat   kelas   baru   yakni  Token  yang 

mengimplementasikan Visitable.

public class Token implements Visitable {
String str;
public Token (String str) {
this.str = str;
}

public void visit () {
System.out.print (str + " ");
}
}

Ketika   kita   meng­compile  definisi   kelas   ini   (yang   berada   dalam  file  Token.java), 

compiler  akan   memeriksa   apakah   metode­metode   itu   memenuhi   persyaratan   yang 

ditentukan oleh metaclass. Jika tidak, ia akan menyebabkan munculnya pesan  error. 

Sebagai   contoh,   jika   kita   salah   menyebutkan   nama   metode   yang   dikira  visit,   kita 

mungkin akan menerima sesuatu seperti, “class Token must be declared abstract. It does 

not  define void visit() from interface Visitable.” Ini  adalah satu dari sekian banyak 

pesan  error  yang solusinya tidak tepat. Ketika  compiler  tersebut mengatakan bahwa 

suatu kelas “must be declared abstract,” apa yang dimaksud dengan pernyataan tersebut 

adalah  bahwa  Anda   harus  memperbaiki  kelas   itu   sehingga  ia   mengimplementasikan 

antarmuka dengan tepat. Terkadang saya sampai berpikir untuk melawan orang yang 

373
menulis pesan ini.

Langkah berikutnya adalah memodifikasi parser untuk meletakkan objek­objek Token 

ke dalam pohon ketimbang String. Berikut ini contoh kecilnya:

String expr = "1 2 3 * +";
StringTokenizer   st   =   new   StringTokenizer   (expr,   " 
+­*/", true);
String token = st.nextToken();
Tree   tree   =   new   Tree   (new   Token   (token),   null,  
null));

Kode   ini   menggunakan  token  pertama   dalam   string   lalu   membungkusnya   ke   dalam 

objek Token, kemudian meletakkan Token tersebut ke dalam satu simpul pohon. Jika 

Tree di sini membutuhkan kargo agar bisa masuk ke dalam metaclass Visitable, ia akan 

mengubah  Token  sehingga   bisa   menjadi   bagian   dari   objek  Visitable.   Ketika   kita 

menghapus Visitable dari pohon, kita harus meng­cast­nya kembali ke bentuk Token.

Latihan 17.1

Tulislah versi printPreorder dengan nama visitPreorder yang menelusuri pohon dan 

memanggil visit di setiap simpul dalam preorder.

Alur eksekusi untuk metode­metode seperti  visitPreorder  tampak tidak biasa. Klien 

memanggil sebuah metode yang disediakan oleh implementasi Tree, lalu implementasi 

Tree    ini  akan  memanggil satu  metode  yang  disediakan oleh  klien.  Pola  seperti  ini 

disebut  callback; adalah langkah yang baik untuk membuat kode  provider  yang lebih 

umum tanpa harus memecah abstraksi yang sudah dibuat.

17.9 Kelas Vector

Vector  merupakan kelas bawaan Java yang berada dalam paket  java.util. Kelas ini 

374
merupakan implementasi dari sebuah array yang berisi Object dengan fitur tambahan, 

yakni   kemampuan   untuk   mengubah   ukurannya   secara   otomatis,   sehingga   kita   tidak 

perlu capek­capek melakukannya.

Sebelum   menggunakan   kelas  Vector  ini,   Anda   harus   memahami   beberapa   konsep 

terlebih dahulu. Setiap Vector mempunyai kapasitas masing­masing, yakni ruang yang 

sudah dialokasikan untuk menyimpan nilai­nilai dan ukuran yang merupakan banyak 

nilai yang berada dalam vektor.

Gambar berikut ini merupakan diagram sederhana dari sebuah vektor yang berisi tiga 

elemen, tapi kapasitasnya tujuh.

Ada dua kelompok metode untuk mengakses elemen­elemen yang berada dalam vektor. 

Metode­metode tersebut menyediakan semantik dan kemampuan  error­checking  yang 

berbeda­beda. Hati­hati, mungkin mereka akan sering membuat Anda kebingungan.

Metode paling sederhana adalah  get  dan  set. Dua metode ini menyediakan semantik 

yang   mirip   dengan   apa   yang   dimiliki   oleh   operator   indeks   array,   [].   Metode  get 

menggunakan indeks integer dan mengembalikan elemen yang berada pada posisi yang 

diinginkan.   Sementara  set  menggunakan   sebuah   indeks   dan   satu   elemen,   lalu 

menyimpan   elemen   yang   baru   itu   pada   posisi   yang   diinginkan,   mengganti   elemen 

sebelumnya yang sudah berada di dalam posisi itu.

Metode  get  dan  set  tidak digunakan untuk mengubah ukuran vektor (jumlah elemen). 

Hal  ini  merupakan tanggung jawab kode klien untuk memastikan agar suatu vektor 

mempunyai   ukuran   yang   cukup   sebelum  get  dan  set  dipanggil.   Metode  size 

mengembalikan jumlah elemen yang ada dalam vektor. Jika Anda mencoba mengakses 

satu elemen yang tidak eksis/ada (yaitu elemen dengan indeks 3 sampai 6), Anda akan 

375
menerima eksepsi ArrayIndexOutOfBounds. 

Kumpulan metode lain mengikutsertakan beberapa versi dari add dan remove. Metode­

metode ini mampu mengubah ukuran vektor dan kapasitasnya, jika diperlukan. Salah 

satu versi dari add menggunakan satu elemen sebagai parameter lalu menambahkannya 

ke   ujung   vektor   (baca:   bagian   belakang).   Metode   ini   lebih   aman   karena   tidak 

menyebabkan eksepsi.

Versi   lain   dari  add  menggunakan   satu   indeks   dan   satu   elemen.   Seperti  set,   ia 

meletakkan   elemen   baru   di   posisi   yang   diinginkan.   Bedanya,  add  tidak   mengganti 

elemen yang sudah ada sebelumnya. Metode ini akan menaikkan ukuran vektor, lalu 

menggeser   elemen­elemen   yang   ada   ke   sebelah   kanan   untuk   memberi   ruang   bagi 

elemen   yang   baru.   Oleh   karena   itu,   pemanggilan   metode   seperti   ini;  v.add   (0,   elt) 

berarti menambahkan elemen baru di awal vektor. Sayangnya, metode ini selain tidak 

aman   juga   kurang   efisien;   ia   bisa   menyebabkan   eksepsi   berupa 

ArrayIndexOutOfBounds  dan, dalam banyak implementasi, metode ini termasuk ke 

dalam linear time (sesuai dengan ukuran vektornya).

Secara umum, para klien tidak perlu khawatir mengenai kapasitas. Kapanpun ukuran 

vektor berubah, kapasitas akan diperbaharui secara otomatis. Karena alasan unjuk kerja, 

beberapa aplikasi memegang kendali atas fungsi ini, yang sekaligus menjadi penyebab 

kenapa ada metode­metode tambahan untuk menaikkan dan menurunkan kapasitas.

Karena kode klien tidak mempunyai akses untuk menggunakan implementasi vektor, 

adalah tidak jelas bagaimana cara kita menelusurinya. Tentu saja, satu kemungkinan 

adalah dengan memakai variabel perulangan sebagai indeks untuk vektor:
for (int i=0; i<v.size(); i++) {
System.out.println (v.get(i));
}

376
Tidak ada yang salah dengan kode di atas, tapi ada cara lain yang juga bisa digunakan 

untuk   mendemonstrasikan   kelas  Iterator.   Vektor­vektor   menyediakan   satu   metode, 

yakni  iterator,  yang   bisa   mengembalikan   objek­objek  Iterator  sehingga 

memungkinkan metode ini untuk melakukan penelusuran vektor.

17.10 Kelas Iterator

Iterator adalah antarmuka yang berada dalam java.util.package. Antarmuka ini terdiri 

dari tiga metode:

hasNext: apakah iterasi ini mempunyai elemen yang lebih?

next:   mengembalikan   elemen   berikutnya,   atau   mengembalikan   sebuah   eksepsi   jika 

kosong

remove: menghapus elemen yang paling baru dari struktur data yang kita telusuri

Contoh   berikut   ini   menggunakan   sebuah   iterator   untuk   menelusuri   dan   mencetak 

elemen­elemen yang terdapat dalam satu vektor.
Iterator it = vector.it ();
while (it.hasNext ()) {
System.out.println (it.next ());
}

Setelah  Iterator  dibuat,   ia   akan   menjadi   objek   yang   terpisah   dari  Vector  aslinya. 

Perubahan yang terjadi berikutnya tidak akan memengaruhi  Iterator  itu sendiri. Pada 

kenyataannya, jika Anda memodifikasi Vector setelah membuat Iterator, Iterator itu 

akan   menjadi   tidak   valid.   Jika   Anda   mengakses  Iterator  itu   lagi,   hal   ini   akan 

menyebabkan eksepsi ConcurrentModification.

377
Dalam subbab sebelumnya kita menggunakan metaclass  Visitable  untuk mengizinkan 

satu   klien  menelusuri   struktur   data   tanpa   harus   mengetahui   detail   implementasinya. 

Iterator­iterator   menyediakan   cara   lain   bagi   kita   untuk   melakukan   hal   yang   sama. 

Dalam kasus yang pertama,  provider  melakukan perulangannya lalu memanggil kode 

klien untuk “mengunjungi” masing­masing elemen. Dalam kasus berikutnya,  provider 

memberikan kliennya satu objek yang bisa digunakannya untuk memilih satu elemen 

pada suatu waktu. 

Latihan 17.2

Tulislah   sebuah   kelas,  PreIterator,   yang   mengimplementasikan   antarmuka  Iterator 

lalu buatlah sebuah metode, preorderIterator untuk kelas Tree  yang mengembalikan 

satu PreIterator yang mampu memilih elemen­elemen Tree secara preorder.

PETUNJUK: 

Cara termudah untuk membuat Iterator adalah dengan meletakkan elemen­elemen ke 

dalam   sebuah   vektor   yang   urutannya   sesuai   dengan   apa   yang   Anda   inginkan. 

Kemudian Anda bisa memanggil metode iterator melalui vektor tersebut.

17.11 Daftar Kata­Kata

Istilah Arti
Pohon yang tiap simpulnya mengacu ke 0, 1, atau 2 simpul 
binary tree
yang saling terkait satu sama lainnya. 
Simpul tertinggi yang ada pada sebuah pohon, yang tidak 
root
diacu oleh simpul manapun.
Simpul terbawah pada sebuah pohon yang tidak mengacu ke 
leaf
simpul manapun..
parent Simpul   yang   mengacu   ke   salah   satu   atau   banyak   simpul 

378
dalam pohon.
child Salah satu simpul yang diacu oleh simpul lainnya.
Kumpulan simpul yang masing­masing memiliki jarak yang 
level
sama ke root.
Sebuah   teknik   penelusuran   pohon   di   mana   setiap   simpul 
preorder
dikunjungi lebih dahulu sebelum simpul anak­anaknya.
Sebuah   teknik   penelusuran   pohon;   kunjungi   simpul   anak 
postorder
dari semua simpul sebelum simpul itu sendiri.
Sebuah   teknik   penelusuran   pohon;   kunjungi   subpohon 

inorder bagian  kiri, kemudian akarnya, lalu baru kunjungi bagian 

kanannya.
Implementasi antrian menggunakan linked list dan acuan ke 
linked queue
node pertama dan terakhir.
Variabel static yang dideklarasikan di luar semua metode. 
class variable
Variabel ini bisa diakses dari metode manapun.
binary operator Operator yang menggunakan dua operan.
Suatu   rancangan   yang   tujuannya   adalah   untuk   menjaga 

implementasi   dari   satu   objek   agar   selalu   terpisah   dari 

object encapsulation implementasi objek lainnya. Begitu juga dengan kelas. Satu 

kelas   tidak   harus   mengetahui   detail   implementasi   kelas 

lainnya.
Suatu   rancangan   yang   tujuannya   adalah   untuk   menjaga 

method encapsulation antarmuka   dari   suatu   metode   terpisah   dari   detail 

implementasinya.
Alur   eksekusi   di   mana   kode  provider  memanggil   sebuah 
callback
metode yang disediakan oleh klien.

379
17.12 Latihan

Latihan 17.3

a) Apa hasil ekspresi postfix 1 2 + 3 * ?

b) Ekspresi postfix apa yang ekuivalen dengan ekspresi infix 1 + 2 * 3?

c) Apa   hasil   ekspresi   postfix  17   1   –   5   /,   asumsikan   bahwa   simbol  /  melakukan 

pembagian integer?

Latihan 17.4

Tinggi sebuah pohon adalah jalur terpanjang dari akar ke daun manapun. Tinggi bisa 

didefinisikan secara rekursif se[erti berikut:

● Tinggi dari pohon yang null adalah 0.

● Tinggi dari pohon yang tidak null adalah 1 + max (leftHeight, rightHeight), di 

mana  leftHeight  adalah tinggi dari simpul anak sebelah kiri dan  rightHeight 

adalah tinggi dari simpul anak sebelah kanan.

Tulislah metode height yang bisa menghitung tinggi dari parameter yang berupa Tree.

Latihan 17.5

Bayangkan   kita   sedang   mendefinisikan   sebuah  Tree  yang   berisi   objek­objek 

Comparable sebagai kargo:

public class ComparableTree {
Comparable cargo;
Tree left, right;
}

Tulislah   metode   kelas  Tree,  findMax,   yang   mengembalikan   kargo   terbesar   dalam 

380
pohon. Kata “terbesar” di sini ditentukan oleh metode compareTo.

Latihan 17.6

Pencarian biner pohon merupakan pohon khusus di mana setiap simpul pohon 

N:

semua kargo di sebelah kiri subpohon N < kargo dalam simpul N

dan

kargo yang ada di simpul N < semua kargo di sebelah kanan subpohon N

Dengan   menggunakan   definisi   kelas   seperti   di   atas,   buatlah   sebuah   metode   objek 

contains  yang menggunakan satu  Object  sebagai argumen lalu mengembalikan nilai 

True  jika   objeknya   muncul   dalam   pohon,   atau  False  jika   tidak.   Anda   bisa 

mengasumsikan bahwa objek yang menjadi target dan semua objek yang berada dalam 

pohon merupakan anggota dari metaclass Comparable.

public class SearchTree {
Comparable cargo;
SearchTree left, right;
}

Latihan 16.7

Dalam matematika, satu himpunan (set) merupakan suatu kumpulan elemen yang tidak 

ada   duplikasi   di   dalamnya.   Antarmuka  java.util.Set  digunakan   untuk   memodelkan 

himpunan matematika. Metode yang dibutuhkannya adalah add, contains, containsAll, 

remove, size, dan iterator.

Tulislah   kelas  TreeSet  yang   mewarisi   kelas  SearchTree  sekaligus   mampu 

mengimplementasikan Set. Agar semuanya bisa tetap berjalan dengan sederhana, Anda 

bisa mengasumsikan bahwa null tidak akan muncul dalam pohon atau sebagai argumen 

381
dari metode manapun.

Latihan 17.8

Tulislah   metode  union  yang   menggunakan   dua  Set  sebagai   argumen   lalu 

mengembalikan sebuah TreeSet baru yang berisi semua elemen yang muncul di kedua 

Set itu. 

Anda   bisa   memasukkan   metode  ini   ke   dalam   implementasi  TreeSet,   atau   membuat 

kelas baru yang mewarisi java.util.TreeSet yang menyediakan union di dalamnya.

Latihan 17.9

Tulislah   metode  intersection  yang   menggunakan   dua  Set  sebagai   parameter   lalu 

mengembalikan sebuah  TreeSet  baru yang berisi semua elemen yang muncul dalam 

kedua Set tersebut.

Metode  union  dan  intersection  bersifat generik karena parameter­parameternya bisa 

bertipe apa saja dalam metaclass Set. Bahkan kedua parameter itu tidak harus memiliki 

tipe yang sama.

Latihan 17.10

Salah   satu   alasan   kenapa   antarmuka  Comparable  bermanfaat   adalah   karena   ia 

mengizinkan   satu   tipe   objek   untuk   memutuskan   bahwa   semua   teknik   pengurutan 

sebenarnya tepat. Untuk tipe­tipe seperti Integer dan Double, teknik pengurutan yang 

tepat sudah jelas, tapi ada banyak contoh di mana suatu pengurutan bergantung pada 

apa yang ingin direpresentasikan oleh si objek. Dalam golf, sebagai contoh saja, skor 

yang lebih rendah lebih baik ketimbang yang lebih tinggi; jika kita membandingkan dua 

objek Golfer, objek yang mempunyai skor lebih rendah akan menjadi pemenangnya.

a) Tulislah   definisi kelas  Golfer  yang   berisi  nama  dan  skor  bertipe   integer  sebagai 

variabel   instan.   Kelas   ini   harus   mengimplementasikan  Comparable  dan 

382
menyediakan metode compareTo yang bisa memberikan prioritas lebih tinggi untuk 

skor yang lebih rendah.

b) Tulislah sebuah program yang bisa membaca file yang berisi nama­nama dan skor­

skor  dari  kumpulan (Set)  pegolf. Program ini harus bisa membuat objek  Golfer, 

meletakkan objek­objek tersebut ke dalam Antrian Prioritas lalu mengeluarkan dan 

mencetak   mereka.   Mereka   harus   ditampilkan   dalam   urutan   terbalik   (descending) 

berdasarkan prioritas. Hal ini sama saja dengan kenaikan urutan berdasarkan skor.
Tiger Woods  61
Hal Sutton  69
Phil Mickelson  72
Allen Downey  158

PETUNJUK:

Lihat bagian C untuk kode yang bisa membaca baris­baris dalam suatu file.

Latihan 17.11

Tulislah   implementasi  Stack  menggunakan  Vector.   Coba   pikirkan,   apakah 

memasukkan   (push)   elemen   baru   ke   posisi   awal   stack   akan   lebih   baik   ketimbang 

memasukkannya ke posisi terakhir?

383
Bab 18

Heap

18.1 Implementasi Pohon menggunakan Array

Apa   yang   dimaksud   dengan   mengimplementasikan   pohon?   Sejauh   ini   kita   hanya 

melihat satu implementasi pohon yang menggunakan linked list. Tetapi sebenarnya ada 

struktur   lain   yang   bisa   kita   identifikasi   sebagai   pohon.   Dan   segala   hal   yang   bisa 

melakukan operasi pohon “dasar” bisa disebut sebagai pohon.

Jadi apa saja operasi operasi pohon itu? Dengan kata lain bagaimana   mendefinisikan 

pohon ADT?

constructor: Membangun sebuah pohon kosong.

getLeft: Mengembalikan anak kiri dari simpul.

getRight: Mengembalikan anak kanan dari simpul.

getParent: Mengembalikan orang tua dari simpul.

getCargo: Mengembalikan muatan dari simpul.

setCargo: Memasukkan sebuah objek muatan pada simpul ini (dan   membuat simpul 

jika dibutuhkan).

Pada implementasi dengan linked list. Pohon kosong diwakili dengan nilai spesial null. 

getLeft  dan  getRight  dilakukan   dengan   mengakses   variabel   instans   dari   simpul, 

demikian   hal   nya   dengan  getCargo  dan  setCargo.   Dalam   hal   ini   kita   belum 

mengimplementasikan  getParent( anda bisa berpikir bagaimana untuk melakukan hal 

ini)

384
Ada implementasi pohon lain yang menggunakan array dan indeks sebagai ganti objek 

dan referensi. Untuk melihat bagaimana ia bekerja, kita akan memulai dengan melihat 

implementasi campuran yang menggunakan array dan objek.

Gambar di bawah ini memperlihatkan sebuah pohon seperti sebelumnya yang pernah 

kita lihat. Pada sisi kanan ada sebuah array dari referensi yang mengacu pada muatan 

dari sebuah simpul.

Setiap simpul pada pohon memiliki indeks yang unik. Indeks ditempatkan pada simpul 

menurut pola yang ditentukan, dengan aturan seperti di bawah:

1. Anak kiri dari simpul dengan indeks i memiliki indeks 2i.

2. Anak kanan dari simpul dengan indeks i memiliki indeks 2i+1.

3. Orang   tua   dari   simpul   dengan   indeks   i   memiliki   indeks   i/2   (pembulatan   ke 

bawah). 

Menggunakan   rumus   ini,   kita   bisa   mengimplementasikan   getLeft,   getRight,   dan 

getParent   dengan   hanya   menggunakan   aritmatika;   kita   tidak   harus   menggunakan 

referensi untuk semua hal!

Karena kita tidak menggunakan referensi, berarti apa yang digunakan sekarang hanya 

objek muatan dan tidak ada yang lain. Sehingga kita bisa mengimplementasikan pohon 

sebagai sebuah array dari objek muatan.

385
Di bawah ini contoh implementasi pohon menggunakan array: 

public class ArrayTree {

    Object[] array;

    int size;

    public ArrayTree () {

        array = new Object [128];

    }

  Sejauh ini tidak ada yang baru. Satu satunya variabel instans adalah array dari objek 

yang berisi muatan pohon. Konstruktor menginisialisasi array dengan kapasitas tertentu; 

Hasilnya adalah sebuah pohon kosong. 

Berikut ini implementasi sederhana dari getCargo dan setCargo. 

public Object getCargo (int i) {

    return array[i];

public void setCargo (int i, Object obj) {

    array[i] = obj;

Metode ini tidak melakukan pengecekan error apapun, jadi jika parameter salah, metode 

dapat menghasilkan eksepsi ArrayIndexOutOfBounds.

Implementasi dari getLeft, getRight, dan getParent hanya menggunakan operasi 

aritmatika: 

public int getLeft (int i) { return 2*i; }

public int getRight (int i) { return 2*i + 1; }

public int parent (int i)   { return i/2; }

386
Akhirnya kelas pohon menggunakan array telah siap digunakan. Pada kelas lain (klien), 

kita bisa menulis:

ArrayTree tree = new ArrayTree ();

tree.setCargo (1, "cargo for root"); 

Konstruktor   membangun   sebuah   pohon   kosong.   Memanggil   setCargo   meletakkan 

kalimat “cargo for root” kedalam simpul akar. 

Untuk menambah anak pada simpul akar:

tree.setCargo (tree.getLeft(1), "cargo for left");

tree.setCargo (tree.getRight(1), "cargo for right");

Pada kelas pohon kita dapat menyediakan sebuah metode yang mencetak isi dari pohon 

dalam bentuk preorder.

public void print (int i) {

    Object cargo = tree.getCargo (i);

    if (cargo == null) return;

    System.out.println (cargo);

    print (getRight (i));

    print (getLeft (i));

Untuk memanggil metode ini, kita harus melewatkan indeks akar sebagai 

parameter.

tree.print (1);

Keluarannya adalah:

cargo for root

cargo for left

cargo for right

387
Implementasi   ini   menyediakan   operasi   dasar   yang   mendefinisikan   sebuah   pohon. 

Seperti   yang   telah   saya   tunjukkan   sebelumnya,   implementasi   pohon   menggunakan 

linked list menyediakan operasi yang sama tetapi dengan sintaks yang berbeda. 

Dalam beberapa hal, implementasi menggunakan array sedikit aneh. Pada suatu saat kita 

mengasumsikan   bahwa   muatan   null   menunjukkan   simpul   yang   tidak   ada,   tetapi   itu 

berati kita tidak dapat meletakkan objek null pada pohon sebagai muatan.

Masalah   lain   adalah   subpohon   tidak   direpresentasikan   sebagai   objek;     Mereka 

direpresentasikan dengan indeks pada array. Untuk melewatkan simpul pohon sebagai 

parameter, kita harus melewatkan sebuah referensi ke objek pohon dan indeks ke array. 

Akibatnya beberapa operasi yang mudah dilakukan pada implementasi dengan linked 

list,   seperti   mengganti   keseluruhan   subtree,   lebih   sulit   dilakukan   pada   implementasi 

dengan array.

Pada sisi lain, implementasi dengan array hemat dalam hal ruang penyimpanan, karena 

tidak ada nya hubungan antara simpul, dan ada beberapa operasi yang lebih mudah dan 

cepat jika pohon diimplementasikan dengan array. 

Heap   adalah   implementasi   dari   PriorityQueue   ADT   yang   berdasarkan   atas 

implementasi  pohon menggunakan array. Yang  akan lebih efisien jika dibandingkan 

dengan implementasi lain.

Untuk membuktikan klaim ini, akan kita lakukan dalam beberapa langkah. Pertama, kita 

akan   membangun   cara   untuk   membandingkan   kinerja   dari   beberapa   implementasi. 

Berikutnya, kita akan melihat implementasi yang dilakukan heap. Dan terakhir kita akan 

388
membandingkan implementasi PriorityQueue menggunakan heap dengan yang lainnya 

(array dan list) dan melihat mengapa implementasi heap dianggap lebih efisien.

8.2 Analisis Kinerja 

Ketika   kita   membandingkan   algoritma,   kita   harus   memiliki   cara   untuk   mengetahui 

kapan suatu algoritma lebih cepat dibandingkan dengan yang lain, atau menggunakan 

ruang   yang   lebih   sedikit,   atau   menggunakan   sumber   daya   lain   yang   lebih   sedikit. 

Pertanyaan ini berat untuk dijawab secara detil, karena waktu dan ruang penyimpanan 

yang digunakan suatu algoritma bergantung pada implementasi dari algoritma tersebut, 

masalah tertentu yang akan diselesaikan, dan perangkat keras dimana program berjalan. 

Tujuan dari bab ini adalah untuk mencari cara untuk mengetahui kinerja yang tidak 

tergantung pada semua hal itu, dan hanya bergantung pada algoritm itu sendiri. Untuk 

memulai, kita akan fokus pada waktu eksekusi; selanjutnya kita akan berbicara tentang 

sumber daya yang lain.

Adapun masalah­masalah yang kita hadapi adalah:

1. Pertama, kinerja algoritma bergantung pada perangkat keras dimana ia berjalan, 

jadi   kita   tidak   akan   berbicara   tentang   waktu   eksekusi   dengan   satuan   mutlak 

seperti detik. Sebagai gantinya, kita menghitung operasi abstrak yang dilakukan 

suatu algoritma.

2. Kedua, kinerja sering bergantung pada masalah tertentu yang sedang kita coba 

untuk menyelesaikannya – beberapa masalah lebih mudah dibandingkan dengan 

yang   lain.   Untuk   membandingkan   algoritma,   kita   akan   fokus   pada   skenario 

terburuk atau skenario rata rata (umum).

3. Ketiga, Kinerja bergantung pada ukuran masalah (biasanya, tetapi tidak selalu, 

banyak   elemen   dalam   sebuah   collection).   Kita   menyelesaikan   masalah   ini 

389
dengan menganggap waktu eksekusi sebagai fungsi dari besar ukuran masalah.

4. Kinerja   bergantung   pada   implementasi   detail   sebuah   algoritma   seperti 

pengalokasian objek dan pengeksekusian metode. Kita tidak akan mengurusi hal 

ini karena tidak terlau berpengaruh pada tingkat kompleksitas seperti banyak 

operasi abstrak menambah ukuran masalah.

Untuk   membuat   masalah   proses   lebih   nyata,   perhatikan   dua   algoritma 

pengurutan bilangan bulat yang telah kita lihat. Yang pertama adalah  selection sort, 

yang telah kita lihat pada bagian 12.3. Berikut ini pseudocode dari algoritma tersebut.

selectionsort (array) {

    for (int i=0; i<array.length; i++) {

      // find the lowest item at or to the right of i

      // swap the ith item and the lowest item

    }

Untuk   melakukan   operasi   yang   dispesifikasikan   pada   pseudocode,   kita   menuliskan 

metode yang bernama findLowest dan swap. Berikut ini pseudocode metode findLowest  

dan swap: 

 // find the index of the lowest item between

 // i and the end of the array

 findLowest (array, i) {

     // lowest contains the index of the lowest item so far

     lowest = i;

     for (int j=i+1; j<array.length; j++) {

        // compare the jth item to the lowest item so far

390
        // if the jth item is lower, replace lowest with j

     }

     return lowest;

 }

 swap (i, j) {

     // store a reference to the ith card in temp

     // make the ith element of the array refer to the jth card

     // make the jth element of the array refer to temp

 }

Untuk menganalisa kinerja algoritma ini, langkah pertama adalah menentukan operasi 

apa yang akan dihitung. Seyogyanya program melakukan banyak hal seperti: menambah 

i, membandingkannya dengan panjang  deck,  mencari elemen terbesar pada array, dan 

lain lain. Sehingga tidaklah terlalu jelas hal mana yang akan dihitung.

Pilihan yang baik adalah berapa kali kita membandingkan dua item. Banyak pilihan lain 

yang   akan   menghasilkan   hasil   yang   sama   pada   akhirnya,   tetapi   menggunakan 

pembandingan   item   akan   mudah   kita   lakukan   dan   kita   akan   bisa   membandingkan 

algoritma pengurutan apapun dengan mudah. 

Langkah   berikutnya   adalah   mendefinisikan   “ukuran   masalah”.   Pada   kasus   ini   kita 

memilih ukuran array, yang akan kita sebut n. Langkah terakhir, kita akan menurunkan 

sebuah   fungsi   yang   memberitahu   berapa   banyak   operasi   abstrak   (dalam   kasus   ini, 

perbandingan) yang harus kita lakukan, sebagai fungsi dari n.

391
Swap mengkopi beberapa referensi, tetapi tidak melakukan pembandingan apapun, jadi 

kita   mengabaikan   waktu   untuk   mengeksekusi  swap.   findLowest  dimulai   pada   i   dan 

menjelajahi array, membandingkan setiap item dengan lowest. Banyak item yang akan 

dibandingkan adalah sebesar n­i, sehingga jumlah total perbandingan adalah n­i­1. 

Selanjutnya   kita   akan   melilhat   berapa   kali  findLowest  dipanggil   serta   nilai   i   nya. 

Terakhir kali dipanggil, i bernilai  n­2 sehingga jumlah perbandingan adalah 1. Iterasi 

sebelumnya   melakukan   dua   perbandingan   dan   demikian   seterusnya.   Selama   iterasi 

pertama, i bernilai 0 dan jumlah perbandingan adalah n­1.

Jadi jumlah perbandingan total adalah 1+2+...+n­1. Jumlahan ini sama dengan  n 2 /2 − 

n/2. Untuk menjelaskan algoritma ini, kita akan mengabaikan n/2 dan menganggap total 

perbandingan adalah n2.

18.3 Analisis Merge Sort

Pada bagian 12.6 saya mengklaim bahwa mergesort membutuhkan waktu nlogn, tetapi 

saya tidak menjelaskan bagaimana atau mengapa. Sekarang saya akan menjelaskannya. 

Kembali, kita mulai dengan melihat pseudocode algoritma. 

mergeSort (array) {

  // find the midpoint of the array

  // divide the array into two halves

  // sort the halves recursively

  // merge the two halves and return the result

392
Pada setiap level rekursi. Kita membagi array dalam dua bagian, memanggil dua metode 

rekursif, dan kemudian menggabungkannya. Secara grafis, proses nya adalah sebagai 

berikut:

Setiap baris pada diagram adalah tingkat rekursi. Pada baris teratas, array tunggal dibagi 

menjadi dua bagian. Pada baris paling bawah, n array dengan satu elemen tiap bagian 

digabung menjadi n/2 array dengan dua elemen setiap bagian.

Dua kolom pertama pada tabel memperlihatkan banyak array pada setiap tingkatan dan 

banyak   elemen   dalam   setiap   array.   Kolom   ketiga   memperlihatkan   berapa   kali 

penggabungan dilakukan setiap tingkatan rekursi. Kolom berikutnya memperlihatkan 

banyak perbandingan setiap penggabungan dilakukan.

Jika   and   melihat   pada   pseudocode   (atau   pada   implementasi   anda)   tentang 

penggabungan, anda pasti menyadari kasus terburuk nya adalah sebanyak m­1. Dimana 

m adalah banyak elemen yang akan digabungkan.

Langkah  berikutnya adalah mengalikan  banyak penggabungan  tiap tingkatan  dengan 

banyak perbandingan setiap penggabungan. Hasilnya adalah kerja total tiap tingkatan. 

Pada titik ini kita mengambil keuntungan dari trik kecil. Kita tahu pada akhirnya kita 

hanya   tertarik   pada   pangkat   depan   dari   hasil   yang   didapatkan,   sehingga   kita   bisa 

393
mengabaikan ­1 pada bagian perbandingan tiap penggabungan. Jika kita melakukannya, 

total kerja tiap tingkatan hanya n.

Berikutnya   kita   perlu   tahu   jumah   tingkatan   sebagai   fungsi   dari   n.   Kita   akan   mulai 

dengan array dengan n elemen dan membaginya dalam dua bagian sampai mendapatkan 

1   elemen  tiap  bagian.  Hal  ini  sama  dengan  mulai  dari  1  dan mengalikan   dengan  2 

sampai mendapatkan n. Dengan kata lain, kita ingin mengetahui berapa kali kita harus 

mengalikan   2   sebelum   kita   mendapatkan  n.  Jawabannya   adalah   banyak   tingkatan,   l 

adalah logaritma basis dua dari n. 

Terakhir, kita mengalikan total kerja tiap tingkatan, n, dengan banyak tingkatan, log 2 n 

untuk mendapatkan n log2 n. 

18.4 Overhead

Pertama kita mengabaikan sebagian besar operasi pada program dan menghitung hanya 

pembandingan. Kemudian kita hanya akan melihat pada kinerja pada kasus terburuk. 

Ketika   kita   menerjemahkan   hasil   dari   analisis   ini,   kita   harus   menyimpannya   pada 

ingatan. Karena mergesort n log2 n, kita bisa menganggapnya lebih baik dari selection 

sort, tetapi ini tidak berati bahwa mergesort selalu lebih cepat. Ini hanya berarti jika kita 

mengurutkan array yang lebih dan lebih besar, mergesort akan menang.

Lama   pengeksekusian   sepenuhnya   tergantung   pada   implementasi   detail   algoritma, 

termasuk   pekerjaan   tambahan,   disamping   pembandingan   yang   telah   kita   hitung. 

Pekerjaan   tambahan   ini   kadang   kadang   disebut  overhead.  Ia   tidak   mempengaruhi 

analisis kinerja, tetapi mempengaruhi waktu eksekusi algoritma tersebut.

394
Sebagai   contoh,   implementasi   mergesort   kita   sebenarnya   mengalokasikan   subarray 

sebelum   membuat   pemanggilan   secara   rekursif.   Dan   kemudian   membiarkan   mereka 

ditangani   oleh  garbage   collector  setelah   digabungkan.   Lihat   kembali   pada   diagram 

mergesort, kita bisa melihat jumlah total ruang yang dialokasikan sama dengan  n log 2 

n,   dan   jumlah   objek   total   yang   dialokasikan   adalah   2n.   Selalu   benar   bahwa 

implementasi   buruk   dari   algoritma   yang   baik   adalah   lebih   baik   dibandingkan 

implementasi baik dari algoritma yang buruk.

18.5 Implementasi PriorityQueue

Pada bab 16 kita telah melihat sebuah implementasi dari PriorityQueue yang dibuat 

dengan array. Elemen pada array tidak terurut, sehingga mudah untuk menambahkan 

elemen   baru,   tetapi   akan   lebih   susah   untuk   menghapus   elemen,   karena   kita   harus 

mencari item dengan prioritas tertinggi. 

Sebagai alternatif implementasi dibuat berdasarkam  sorted list.  Pada kasus ini ketika 

kita menambah item baru kita menjelajahi list dan meletakkan item baru pada tempat 

yang benar. Implementasi ini menggunakan kemampuan dari list, dimana akan mudah 

menambah   simpul   baru   pada   pertengahan   list.   Begitu   juga   menghapus   item   dengan 

prioritas tertinggi, dimana ia akan selalu terdapat pada awal list. 

Analisis kinerja dari operasi ini cukup mudah. Menambahkan item pada akhir array atau 

menghapus simpul dari awal list menggunakan waktu yang sama tanpa memperhatikan 

jumlah   item   yang   ada   pada   list.   Jadi   kedua   operasi   ini   menggunakan   waktu   yang 

konstan. 

Setiap kali kita menjelajahi array atau list, menggunakan operasi dengan waktu yang 

395
konstan tiap elemen, waktu sebanding dengan jumlah item. Itulah mengapa, menghapus 

sesuatu dari array dan menambahkan sesuatu pada list keduanya menggunakan waktu 

yang konstan. 

Jadi berapa lama waktu yang digunakan untuk menambah dan kemudian menghapus n 

item dari PriorityQueue? Untuk implementasi array, n menggunakan waktu sebanding 

dengan   n   tetapi   penghapusan   menggunakan   waktu   lebih   lama.   Penghapusan   yang 

pertama harus menjelajahi semua n elemen; kedua harus menjelajahi n­1 dan demikian 

seterusnya, sampai penghapusan terakhir, yang hanya harus mencari pada 1 elemen. 

Sehingga   total   waktu   nya   adalah   1+2+...+n,   yang   menghasilkan   n2/2+n/2.   Jadi   total 

untuk penambahan dan penghapusan adalah jumlah fungsi linear dan fungsi kuadrat, 

yang kita bisa tahu akan menghasilkan fungsi kuadrat. 

Analisis   pada   implementasi   list   sama.   Penambahan   pertama   tidak   membutuhkan 

penjelajahan, tetapi setelah itu kita harus menjelajahi list setiap kali kita menambah 

sebuah item baru. Pada umumnya kita tidak mengetahui berapa banyak elemen pada list 

yang  harus kita jelajahi, karena ia bergantung pada data dan dengan cara bagaiman 

mereka ditambahkan, tetapi kita bisa mengasumsikan rata rata kita harus menjelajahi 

setengah dari list. Sayangnya bahkan menjelajahi setengah dari list adalah operasi yang 

linear.

Jadi,   sekali   lagi,   untuk   menambah   dan   menghapus   n   item   membutuhkan   waktu   n 2. 

Sehingga   berdasarkan   analisis   kita   tidak   bisa   mengatakan   implementasi   mana   yang 

lebih baik; implementasi array dan list keduanya merupakan operasi kuadratik. 

Jika kita mengimplementasikan priority queue menggunakan heap, kita bisa melakukan 

396
penambahan dan penghapusan dengan waktu  logn.  Sehingga total waktu untuk n item 

adalah   nlogn,   yang   lebih   baik   dari  n2.   Itulah   mengapa   pada   awal   bab   ini,   saya 

menyebutkan bahwa heap adalah implementasi efisien dari priority queue.

18.6 Definisi Heap 

Heap adalah salah satu jenis pohon. Ia memiliki dua sifat yang tidak selalu dimiliki oleh 

pohon lain:

completeness : pohon komplet, yang berarti simpul ditambahkan dari atas ke  bawah, 

kiri ke kanan, tanpa meninggalkan satu ruang pun. 

heapness: Item pada pohon dengan prioritas tertinggi ada pada puncak pohon,  begitu 

juga pada setiap subpohon. 

Kedua sifat ini membutuhkan sedikit penjelasan. Gambar berikut memperlihatkan 

jumlah pohon yang komplet dan tidak komplet. 

Pohon kosong selalu dianggap komplit. Kita bisa mendefinisikan completeness lebih 

dalam dengan membandingkan tinggi subpohon. Dari pelajaran sebelumnya kita ketahui 

bahwa tinggi pohon adalah banyak tingkatan yang ada. 

397
Dimulai dari akar, jika pohon komplit, lalu tinggi subpohon kiri dan tinggi subpohon 

kanan harus sama, atau subpohon kiri bisa lebih tinggi satu. Pada kasus lain, pohon 

tidak disebut komplit. Dengan demikian jika pohon komplit, maka hubungan antara 

subpohon harus selalu benar untuk setiap simpul pada pohon. 

Sifat heap adalah rekursif. Agar pohon disebut heap, nilai terbesar pada pohon harus 

ada pada akar, dan hal yang sama harus benar pada setiap subpohon. 

Latihan 18.1 Tulis metode yang mengambil pohon sebagai parameter dan  mengecek 

apakah komplit atau tidak. 

Petunjuk: Anda dapat menggunakan metode height dari latihan 17.4

Latihan 18.2 Tulis metode yang mengambil pohon sebagai parameter dan mengecek 

apakah ia memiliki sifat heap.

18.7 Penghapusan pada heap

Mungkin kelihatan ganjil kita akan menghapus sesuatu dari heap sebelum menambah 

apapun, tetapi saya pikir penghapusan lebih mudah untuk dijelaskan. Sekilas, kita 

mungkin berpikir mengapus item dari heap adalah operasi yang konstan, karena item 

dengan prioritas tertinggi selalu berada pada akar. Masalahnya adalah setiap kita 

menghapus simpul akar, kita ditinggalkan sesuatu yang bukan lagi heap. Sebelum kita 

dapat mengembalikan hasilnya, kita harus mempebaiki sifat heap. Kita menyebut 

operasi ini reheapify.

Situasi ini digambarkan pada gambar berikut:

398
Simpul akar memiliki prioritas r dan dua subpohon, A dan B. nilai pada akar subpohon 

A adalah a dan nilai pada subpohon B adalah b. 

Kita mengasumsikan sebelum kita menghapus r dari pohon, pohon adalah heap. Ini 

mengakibatkan r adalah nilai terbesar dalam heap dan bahwa a dan b adalah nilai 

terbesar dalam subpohon mereka. Ketika kita menghapus r, kita harus membuat pohon 

yang dihasilkan kembali menjadi heap. Dengan kata lain kita butuh meyakinkan ia 

memiliki sifat completeness dan heapness. 

Cara terbaik untuk menjamin completeness adalah dengan menghapus elemen paling 

bawah, yang paling kanan, yang kita sebut c dan meletakkan nilai nya pada akar. Pada 

implementasi pohon, kita harus menjelajahi pohon untuk mencari simpul ini, tetapi pada 

implementasi array, kita dapat mencarinya pada waktu konstan karena ia akan selalu 

elemen non null terakhir pada array.

Tentu, nilai terakhir bukan yang tertinggi, jadi meletakkanyya pada akar akan merusak 

sifat heapness. Untungnya mudah untuk diperbaiki. Kita tahu bahwa nilai terbesar 

399
dalam heap setelah r dihapus adalah a atau b. Itulah mengapa kita bisa memilih yang 

mana yang lebih besar dan menggantinya dengan nilai pada akar.

Mari kita anggap b adalah yang terbesar. Karena kita tahu ia adalah nilai tertinggi pada 

kiri heap, kita bisa meletakkannya pada akar dan meletakkan c pada puncak subpohon 

B. Sekarang situasinya akan seperti di bawah ini:

lagi, c adalah nilai yang kita kopi dari elemen terakhir dalam array dan b adalah nilai 

tertinggi dalam heap. Karena kita tahu kita tidak pernah mengganti subpohon A, kita 

mengetahui ia masih merupakan heap. Satu satunya masalah adalah kita tidak dapat 

mengetahui apakah subpohon B adalah heap, karena kita hanya menempel sebuah nilai 

(kemungkinan rendah) pada akarnya.

Akan lebih baik jika kita memiliki metode yang bisa reheapify subpohon B? 

Tunggu.... kita punya

18.8 Penambahan Heap 

Menambahkan sebuah item baru pada heap adalah operasi yang mirip dengan 

penghapusan heap, perbedaanya bahwa kita tidak menghamburkan elemen dari atas 

400
tetapi kita menghamburkan elemen ke atas dari bawah heap. 

Untuk menjamin sifat completeness, kita menambah elemen baru pada elemen paling 

bawah pada pohon, yang merupakan ruang kosong berikutnya pada array. Lalu untuk 

mengembalikan sifat heap, kita membandingkan nilai baru dengan tetangganya. Situasi 

nya akan terlihat seperti ini:

Nilai baru adalah c. Kita bisa mengembalikan sifat heap pada subpohon ini dengan 

membandingkan c dengan a. Jika c lebih kecil, maka sifat heap telah dipenuhi. Jika c 

lebih besar maka kita mengganti c dan a. Proses swap akan memenuhi sifat heap karena 

kita tahu c harus lebih besar dari b, karena c>a dan a>b.

Sekarang subtree telah menjadi heap kembali, selanjutnya proses dilanjutkan ke simpul 

atas (a atau c) dengan membandingkan dengan orang tua nya  demikian seterusnya 

sampai mencapai akar. 

18.9 Kinerja Heap 

Untuk penambahan dan penghapusan, kita menggunakan operasi dengan waktu 

yang konstan untuk penambahan dan penghapusan yang sebenarnya, tetapi kemudian 

kita harus melakukan reheapify pada pohon. Pada satu kasus kita mulai dari akar dan 

401
dilanjutkan ke bawah, membandingkan elemen dan secara rekursif melakukan 

reheapify pada subpohon. Pada kasus lain kita mulai pada daun dan bekerja ke atas, 

kembali kita membandingkan elemen pada tiap level pada pohon. 

Seperti biasa, ada beberapa operasi yang akan kita hitung, seperti pembandingan dan 

pertukaran. Kedua pilihan akan bekerja; masalah sebenarnya adalah banyak level pada 

pohon yang kita periksa dan berapa banyak usaha yang kita lakukan setiap level. Pada 

kedua kasus kita tetap bekerja pada sebuah level pohon sampai kita mengembalikan 

sifat heap, yang berarti kita mungkin hanya berkunjung sekali, atau pada kasus terburuk 

kita harus mengunjungi semua elemen, sekarang mari kita lihat pada kasus terburuk.

Pada setiap level, kita melakukan hanya operasi dengan waktu yang konstan seperti 

pembandingan dan penggantian. Jadi total kerja sebanding dengan banyak tingkatan 

pada pohon, dengan kata lain tinggi. Jadi kita bisa berkata operasi operasi ini 

berbanding lurus denga tinggi pohon, tetapi “ukuran masalah” yang menarik bukan 

tinggi nya, tetapi banyak elemen pada heap. 

Dalam fungsi n, tinggi pohon adalah log2n. Ini tidak selalu benar untuk semua pohon, 

tetapi hanya benar untuk pohon yang lengkap. Untuk mengetahui kenapa, pikirkan 

banyak simpul pada setiap level dari pohon. Level pertama berisi 1, level 2 berisi 2, 

level ketiga berisi 4, demikian seterus nya. Level ke i akan berisi 2i simpul dan jumlah 

elemen di semua level sampai i adalah 2i­1. Dengan kata lain 2h = n, yang berarti 

h=log2n. 

Sehingga, keduanya  penambahan dan penghapusan menggunakan waktu yang 

logaritmik. Untuk menambah dan menghapus n elemen maka akan menggunakan waktu 

402
nlog2n. 

18.10 Heapsort

Hasil dari bagian yang lalu bisa menjadi inspirasi untuk algoritma pengurutan. Terdapat 

n elemen, kita menambahkan mereka ke dalam Heap kemudian menghapusnya. Karena 

sifat heap, mereka akan keluar dalam keadaan terurut. Kita telah memperlihatkan 

algoritma ini, yang disebut heapsort, ia menggunakan waktu sebanding dengan nlog2n, 

yang lebih baik dari selection sort dan sama dengan mergesort.

Semakin besar nilai, kita berharap heapsort akan lebih cepat dari selection sort, tetapi 

analisis kinerja tidak menunjukkan cara untuk mengetahui apakah ia akan lebih cepat 

dari mergesort. Kita akan berkata kedua algoritma memiliki order of growth yang sama 

karena waktu kinerja mereka bertambah dengan bentuk fungsi yang sama. Cara lain 

untuk mengatakan hal yang sama adalah mereka memiliki kompleksitas yang sama.

Kompleksitas kadang kadang ditulis dalam “notasi big­O”. misalnya O(n^2), diucapkan 

dengan “oh of en squared” adalah kumpulan fungsi yang berkembang tidak lebih cepat 

dari n^2 untuk nilai n yang besar. Untuk mengatakan sebuah algoritma adalah O(n^2) 

sama dengan algoritma tersebut kuadratik. Untuk kasus kompleksitas lain yang telah 

kita lihat, dengan urutan kinerja menurun, adalah 

O(1)       constant time

O(log n)   logarithmic

O(n)       linear

O(n log n) “en log en”

O(n2 )     quadratic

O(2n )     exponential

403
Sejauh ini tidak ada algoritma yang telah kita lihat memiliki kompleksitas eksponensial. 

Untuk nilai n yang besar, algoritma ini cepat menjadi tidak praktis. Namun demikian 

frase “pertumbuhan eksponensial” muncul lebih sering bahkan pada bahasa yang tidak 

teknis. Ia sering digunakan tidak tepat jadi saya ingin memasukkan arti teknis nya.

Orang sering menggunakan eksponensial untuk menjelaskan kurva yang bertambah dan 

berakselerasi (kurva yang memiliki kemiringan positif dan lekukan). Tentu saja ada 

banyak kurva lian yang sesuai dengan penjekasan ini, termasuk fungsi kuadrat (dan 

polinomilal tingkat yang lebih tinggi) dan bahkan fungsi seperti nlogn. Sebagian besar 

kurva ini tidak memiliki (bahkan merusak) sifat eksplosif dari eksponensial. 

18.11 Daftar Kata Kata

selection sort: Algoritma pengurutan sederhana pada bab 12.3.

mergesort: Algoritma pengurutan yang lebih baik dari bab 12.6.

heapsort: Algoritma pengurutan yang lain.

kompleksitas: kumpulan algoritma yang kinerja nya (biasanya waktu eksekusi) 

memiliki order of growth yang sama.

order of growth: Kumpulan fungsi dengan pangkat awal yang sama, dan karena 

itu sama dalam sifat kualitatif untuk nilai n yang besar.

overhead: waktu atau sumber daya tambahan yang dikonsumsi oleh sebuah 

program dalam melakukan suatu operasi selain dari operasi abstrak yang 

diperhitungkan pada analisis kinerja. 

404
18.12 Latihan

latihan 18.3

a) Gambar Heap yang direpresentasikan pada array di bawah ini.

b)  Perlihatkan susunan array ketika 68 ditambahkan ke dalam heap.

Latihan 18.4 

Asumsikan terdapat n elemen dalam heap. Untuk mencari nilai tengah dari elemen, kita 

dapat menghapus n/2­1 elemen dan mengembalikan nilai elemen ke n/2. Kemudian kita 

harus meletakkan n/2 elemen kembali ke dalam heap. Berapa order of growth dari 

algoritma ini?

Latihan 18.5

Berapa kali loop di bawah ini dieksekusi? Kemukakan jawaban mu sebagai fungsi dari 

n:

while (n > 1) {

    n = n / 2;

Latihan 18.6 

Berapa banyak pemanggilan rekursif yang dilakukan zippo? Kemukakan jawabanmu 

sebagai fungsi dari x atau n atau keduanya.

public static double zippo (double x, int n) {

    if (n == 0) return 1.0;

    return x * zippo (x, n­1);

405
Latihan 18.7 

Tulis implementasi dari Heap berdasarkan implementasi pohon dengan array. Waktu 

eksekusi add dan remove harus sebanding dengan log n, diman n adalah banyak elemen 

dalam heap. 

406
BAB 19

Maps

19.1 Array, Vector, Map

Array adalah struktur data yang secara umum sangat berguna, tetapi array 

memiliki dua keterbatasan utama yaitu:

● Ukuran array tidak bergantung terhadap jumlah elemen yang ada di dalamnya. 

Jika array lebih besar dibanding jumlah elemen di dalamnya  maka akan 

menghabiskan tempat. Sedangkan jika terlalu kecil (Ukuran array lebih kecil) 

maka kemungkinan dapat menyebabkan kesalahan. Atau kita harus menulis 

kode untuk mengubah ukurannya.

● Meskipun array dapat berisi tipe apapun, indeks array harus bertipe integer. 

Kita tidak dapat misalnya menggunakan String untuk digunakan sebagai indeks.

Pada bab 17.9 kita telah melihat bagaimana kelas Vector yang merupakan kelas yang 

disediakan oleh Java bisa menyelesaikan masalah pertama. Ketika sebuah kode 

menambah elemen, maka Vector akan membesar secara otomatis. Dan juga 

memungkinkan untuk memperkecil Vector sehingga kapasitasnya sama dengan jumlah 

elemen yang ada di dalamnya.

Tetapi Vector tidak dapat menolong pada masalah kedua. Indeks Vector masih harus 

bertipe integer.  Masalah ini bisa diselesaikan dengan struktur data Map ADT. Map 

serupa dengan Vector, perbedaannya adalah Map dapat menggunakan tipe objek apapun 

sebagai indeks. Indeks pada Map disebut sebagai kunci.

407
Sebagaimana anda menggunakan indeks untuk mengakses nilai pada Vector, anda juga 

menggunakan kunci untuk mengakses nilai pada Map. Setiap kunci diasosiasikan 

dengan sebuah nilai, itulah mengapa Map kadang kadang disebut array assosiatif. 

Assosiasi antara sebuah kunci dengan sebuah nilai disebut entri.

Contoh umum dari struktur data Map adalah kamus, yang memetakan kata kata (kunci) 

pada definisinya (nilai). Karena hal ini Map juga kadang disebut kamus. 

19.2 Map ADT

Seperti ADT lain yang telah kita lihat, Maps didefinisikan dengan himpunan operasi 

yaitu:

contructor: Membuat sebuah Map kosong

put: Menciptakan sebuah entri yang mengasosiasikan sebuah nilai dengan sebuah kunci

get:  Untuk sebuah kunci yang diberikan, cari nilai yang bersesuaian

containsKey: Mengembalikan true jika terdapat entri pada Map dengan kunci yang 

diberikan

keySet: Mengembalikan struktur data Set yang berisi semua kunci pada Map

19.3 HashMap built­in

Java menyediakan implementasi dari Map ADT pada paket java.util.HashMap. 

Selanjutnya pada bab ini kita akan lihat mengapa disebut HashMap

408
Untuk mendemonstrasikan penggunaan HashMap kita akan menulis sebuah program 

sederhana yang menjelajahi sebuah String dan menghitung jumlah kemunculan suatu 

kata.

Kita akan membuat kelas baru yaitu WordCount yang akan membangun Map dan 

mencetak isinya. Setiap WordCount berisi HashMap sebagai variabel instance.

public class WordCount{

HashMap Map;

public WordCount(){

Map = new HashMap();

Metode publik pada WordCount adalah processLine, yang mengambil sebuah String 

dan menambah kata katanya pada Map, dan print, yang bertugas mencetak hasil 

pemrosesan.

ProcessLine memecah String menjadi kata kata menggunakan StringTokenizer (untuk 

mennggunakan StringTokenizer anda harus mengimpornya terlebih dahulu, dengan 

menambahkan baris import java.util.* sebelum deklarasi class) dan melewatkan setiap 

kata pada processWord.

public void processLine(String s){

409
StringTokenizer st = new StringTokenizer(s,”,.”);

while(st.hasMoreTokens()){

String word = st.nextToken();

processWord(word.toLowerCase());

public void processWord (String word) {

    if (Map.containskunci (word)) {

        integer i = (integer) Map.get (word);

        integer j = new integer (i.intValue() + 1);

        Map.put (word, j);

    } else {

        Map.put (word, new integer (1));

    }

Jika kata telah ada dalam Map, maka kita mengambil variabel pencacahnya, 

menambahkan satu, dan memasukkannya (put) kembali pada Map. Jika tidak, kita 

hanya akan menaruh entri baru pada Map dengan pencacah di beri nilai satu.

Untuk mencetak semua entri pada Map, kita harus bisa menjelajahi seluruh kunci dalam 

Map. Untungnya, HashMap menyediakan metode keySet, yang mengembalikan sebuah 

objek Set, dan Set menyediakan sebuah metode iterator yang mengembalikan objek 

Iterator.

410
Berikut ini cara untuk menggunakan keySet untuk mencetak isi dari HashMap:

//catatan agar kode bisa fungsional anda harus menambahkan baris import java.util.*  

sebelum //deklarasi kelas

public void print () {

    Set set = Map.keySet();

    Iterator it = set.iterator();

    while (it.hasNext ()) {

        String kunci = (String) it.next ();

        integer value = (integer) Map.get (kunci);

        System.out.println ("{ " + kunci + ", " + value + " }");

    }

Setiap elemen pada iterator adalah sebuah Objek, tetapi karena kita tahu bahwa mereka 

adalah kunci, kita bisa mengcastingnya menjadi String. Ketika kita mengambil sebuah 

nilai pada Map, mereka juga bertipe Objek, tetapi kita tahu bahwa mereka adalah 

pencacah, jadi kita bisa mengcastingnya menjadi bertipe integer.

Berikut ini cara untuk menghitung kata kata pada sebuah kalimat:

        WordCount wc = new WordCount ();

        wc.processLine ("you spin me right round baby " +

                        "right round like a record baby " +

                        "right round round round");

        wc.print ();

411
Keluarannya adalah

{ you, 1 }

{ round, 5 }

{ right, 3 }

{ me, 1 }

{ like, 1 }

{ baby, 2 }

{ spin, 1 }

{ record, 1 }

{ a, 1 }

Elemen elemen pada Iterator tidak diurutkan berdasarkan aturan tertentu. Satu satunya 

jaminan adalah semua kunci pada Map akan muncul.

Berikut ini kode kelas WordCount secara keseluruhan:

import java.util.*;

public class WordCount {

HashMap Map;

     public WordCount () {

         Map = new HashMap ();

public void processLine (String s) {

StringTokenizer st = new StringTokenizer (s, " ,.");

412
while (st.hasMoreTokens()) {

String word = st.nextToken();

processWord (word.toLowerCase ());

public void processWord (String word) {

if (Map.containsKey (word)) {

integer i = (integer) Map.get (word);

integer j = new integer (i.intValue() + 1);

Map.put (word, j);

} else {

Map.put (word, new integer (1));

public void print () {

Set set = Map.keySet();

Iterator it = set.iterator();

while (it.hasNext ()) {

String kunci = (String) it.next ();

integer value = (integer) Map.get (kunci);

System.out.println ("{ " + kunci + ", " + value + " }");

public static void main(String [] args){

WordCount wc = new WordCount ();

413
wc.processLine ("you spin me right round baby " +

"right round like a record baby " +

"right round round round");

wc.print ();

19.4 Implementasi Dengan Vector

Cara yang mudah untuk mengimplementasikan Map ADT adalah menggunakan entri 

dengan struktur data Vector, dimana setiap entri adalah sebuah objek yang berisi sebuah 

kunci dan sebuah nilai. Definisi kelas dari Entry seperti di bawah ini:

class Entry {

    Object kunci, value;

    public Entry (Object kunci, Object value) {

        this.kunci = kunci;

        this.value = value;

    }

    public String toString () {

        return "{ " + kunci + ", " + value + " }";

    }

Lalu implementasi dari Map seperti di bawah ini:

414
public class MyMap {

    Vector entries;

    public Map () {

        entries = new Vector ();

    }

Untuk menaruh entri baru pada Map, kita hanya menambah sebuah objek Entry pada 

Vector:

public void put (Object kunci, Object value) {

    entries.add (new Entry (kunci, value));

Kemudian untuk melihat sebuah kunci pada Map kita harus menjelajahi Vector dan 

mencari sebuah Entry dengan kunci yang sesuai.

public Object get (Object kunci) {

    Iterator it = entries.iterator ();

    while (it.hasNext ()) {

        Entry entry = (Entry) it.next ();

        if (kunci.equals (entry.kunci)) {

            return entry.value;

        }

    }

  return null;

415
}

Cara untuk menjelajahi Vector telah kita lihat pada bagian 17.10.  Ketika kita 

membandingakan kunci,  kita menggunakan metode equal (deep quality) daripada 

operator == (shallow quality). Hal ini membuat diperbolehkannya tipe data kunci untuk 

menspesifikasikan definisi persamaan yang digunakan, Pada contoh di atas, tipe data 

kunci adalah String, jadi metode get akan menggunakan metode equals  yang ada pada 

kelas String.

Karena equals adalah metode objek. Implementasi dari get tidak bekerja jika kunci 

berisi null, Untuk mengatasi kunci yang berisi null, kita harus menambahkan kasus 

khusus untuk mengambil dan menulis sebuah metode  pada kelas yang membandingkan 

kunci dan mengurusi parameter null dengan aman. Tapi hal ini tidak akan kita bahas 

secara detail.

Sekarang kita telah memiliki metode get, kita bisa menulis versi dari put yang lebih 

lengkap. Jika telah terdapat entri pada Map dengan kunci yang diberikan, put akan 

memperbaharuinya( memberinya nilai yang baru), dan mengembalikan nilai yang lama( 

atau null jika belum ada). ini adalah implementasi metode yang menyediakan fitur ini:

public Object put (Object kunci, Object value) {

    Object result = get (kunci);

    if (result == null) {

        Entry entry = new Entry (kunci, value);

        entries.add (entry);

    } else {

        update (kunci, value);

416
    }

    return result;

private void update (Object kunci, Object value) {

    Iterator it = entries.iterator ();

    while (it.hasNext ()) {

        Entry entry = (Entry) it.next ();

        if (kunci.equals (entry.kunci)) {

            entry.value = value;

            break;

        }

Metode update bukan merupakan bagian dari Map ADT, jadi ia dideklarasikan private.  

Ia menjelajahi Vector sampai mendapatkan objek Entry yang tepat lalu memparbaharui 

atribut nilai nya. Perlu diperhatikan bahwa kita tidak memodifikasi Vector, kita hanya 

salah satu objek yang ada di dalamnya.

Metode yang belum kita implementasikan adalah containsKey dan keySet. Metode 

containsKey hampir sama dengan metode get kecuali ia mengembalikan nilai true atau 

false sebagai ganti objek atau null.

Latihan 19.1 Implementasikan metode keySet dengan membuat dan mengembalikan 

objek TreeSet. Gunakan implementasi TreeSet anda pada bab 17.7 atau implementasi 

yang telah disediakan pada paket java.util.TreeSet

417
Implementasi lengkap Map menggunakan Vector:

import java.util.*;

public class MyMap {

Vector entries;

public MyMap () {

entries = new Vector ();

public Object get (Object kunci) {

Iterator it = entries.iterator ();

while (it.hasNext ()) {

Entry entry = (Entry) it.next ();

if (kunci.equals (entry.kunci)) {

return entry.value;

return null;

public Object put (Object kunci, Object value) {

Object result = get (kunci);

if (result == null) {

Entry entry = new Entry (kunci, value);

entries.add (entry);

} else {

418
update (kunci, value);

return result;

private void update (Object kunci, Object value) {

Iterator it = entries.iterator ();

while (it.hasNext ()) {

Entry entry = (Entry) it.next ();

if (kunci.equals (entry.kunci)) {

entry.value = value;

break;

public Set keySet(){

Iterator it = entries.iterator ();

  Set s = new TreeSet();

while (it.hasNext ()) {

Entry entry = (Entry) it.next ();

s.add(entry.kunci);

return s;

public boolean containsKey(Object kunci){

if(get(kunci)==null)

419
return false;

else

return true;

class Entry {

     Object kunci, value;

     public Entry (Object kunci, Object value) {

         this.kunci = kunci;

         this.value = value;

     public String toString () {

         return "{ " + kunci + ", " + value + " }";

Contoh kelas WordCount menggunakan implementasi Map dengan Vector

import java.util.*;

public class WordCountVector {

MyMap Map;

    

public WordCountVector () {

         Map = new MyMap ();

420
public void processLine (String s) {

StringTokenizer st = new StringTokenizer (s, " ,.");

while (st.hasMoreTokens()) {

String word = st.nextToken();

processWord (word.toLowerCase ());

public void processWord (String word) {

if (Map.containsKey (word)) {

integer i = (integer) Map.get (word);

integer j = new integer (i.intValue() + 1);

Map.put (word, j);

} else {

Map.put (word, new integer (1));

public void print () {

Set set = Map.keySet();

Iterator it = set.iterator();

while (it.hasNext ()) {

String kunci = (String) it.next ();

integer value = (integer) Map.get (kunci);

System.out.println ("{ " + kunci + ", " + value + " }");

421
public static void main(String [] args){

WordCountVector wc = new WordCountVector ();

wc.processLine ("you spin me right round baby " +

"right round like a record baby " +

"right round round round");

wc.print ();

19.5 Kelas Abstrak List

Paket java.util mendefinisikan sebuah kelas abstrak yang menspesifikasikan himpunan 

operasi yang sebuah kelas harus mengimplementasikan agar dapat disebut List, Ini tidak 

berarti bahwa setiap kelas yang mengimplementasikan List harus merupkan struktur 

data linked list.

Tidak aneh bahwa kelas bawaan LinkedList adalah implementasi dari List. Dan yang 

mengejutkan kelas Vector juga merupakan implementasi dari kelas List.

Metode metode pada definisi List merliputi add, get, dan iterator. Pada kenyataannya, 

semua metode dari kelas Vector yang digunakan untuk mengimplementasikan Map 

didefinisikan pada kelas abstrak List. Ini berarti sebagai ganti kelas Vector, kita dapat 

menggunakan implementasi kelas abstrak List apa pun. Pada implementasi Map yang 

telah kita buat kita dapat mengganti Vector dengan LinkedList dan program masih bisa 

422
bekerja dengan baik. 

Tipe umum seperti ini dapat berguna untuk meningkatkan performa sebuah program. 

Anda dapat membuat program dalam bentuk  kelas abstrak seperti List lalu mengetes 

program tersebut dengan beberapa implementasi yang berbeda untuk melihat 

implementas mana yang menghasilkan performa terbaik.

19.6 Implementasi dengan HashMap

Alasan implementasi bawaan Map ADT disebut HashMap karena ia menggunakan 

sebuah implementasi Map yang efisien menggunakan tabel hash.

Untuk lebih memahami implementasi HashMap dan mengapa ia dianggap efisien. Kita 

akan memulai dengan menganalisa performa dari  implementasi List.

Dengan melihat pada implementasi put, kita melihat bahwa terdapat dua kasus. Jika 

kunci belum terdapat dalam Map, kita lalu hanya akan membuat entri baru dan 

menambahkannya pada Map, kedua operasi ini merupakan operasi dengan waktu yang 

konstan.

Pada kasus lain, kita harus menjelajahi List untuk mencari suatu entri. Yang merupakan 

operasi dengan waktu linear. Untuk alasan yang sama get dan containsKey juga 

memiliki waktu yang linear.

Meskipun operasi linear  sering sudah dianggap mencukupi , tetapi kita dapat 

melakukannya lebih baik.  Ada sebuah cara untuk mengimplementasikan Map ADT 

sehingga put dan get dilakukan pada waktu yang konstan.

423
Kuncinya adalah pengetahuan tentang waktu penjelajahan List yang linear dengan 

panjang List. Jika kita dapat meletakkan batas atas pada panjang List maka kita dapat 

meletakkan batas atas pada waktu penjelajahan, maka apapun dengan batas atas yang 

pasti adalah waktu konstan yang bisa diperhitungkan.

Tetapi bagaimana kita dapat membatasi panjang List tanpa membatasi banyak item pada 

Map? Solusinya adalah dengan menambah jumlah List. Sebagai ganti satu List yang 

panjang kita akan menggunakan banyak List pendek.

Sepanjang kita tahu List mana yang akan dicari, kita dapat meletakkan batas pada 

jumlah pencarian.

19.7 Fungsi Hash

Dan itulah dimana fungsi hash bisa dipergunakan. Kita membutuhkan cara untuk 

melihat sebuah kunci dan tahu tanpa mencari, pada List mana ia berada. Kita akan 

mengasumsikan bahwa List ada di dalam array (atau Vector) jadi kita bisa 

mereferensinya dengan dengan index.

Solusi yang bisa dilakukan adalah dengan menggunakan teknik pemetaan. Untuk setiap 

kemungkinan kunci dipastikan terdapat sebuah indeks tunggal, tetapi ada kemungkinan 

banyak kunci yang dipetakan pada index yang sama.

Sebagai contoh, Sebuah array dengan 8 List dan sebuah Map yang dibuat dengan kunci 

bertipe integer dan nilai yang bertipe String. Untuk mendapatkan indeks digunakan 

metode intValue pada kelas integer sebagai indeks, yang merupakan tipe yang benar, 

424
tetapi ada banyak bilangan integer (bulat) yang tidak berada antara 0 dan 7, padahal 

indeks yang legal harus berada antara 0 dan 7.

Operator modulus menyediakan cara yang sederhana dan efisien untuk memetakan 

semua bilangan bulat (integer) antara 0 dan 7. Perhitungan

kunci.intValue % 8

dijamin menghasilkan nilai dalam rentang ­7 sampai 7 (termasuk keduanya). Jika anda 

mengambil nilai absolut (menggunakan Math.abs) anda akan mendapatkan indeks yang 

sah.

Untuk tipe yang lain, dapat diterapkan cara yang sama. Misalnya untuk mengkonversi 

variabel bertipe Character menjadi bilangan bulat, kita dapat menggunakan metode 

bawaan Character.getNumericValue dan untuk tipe Double dapat digunakan metode 

intValue.

Untuk String kita bisa mendapatkan nilai bilangan tiap karakter dan menambahkannya, 

atau kita mungkin bisa menggunakan operasi shifted sum. Untuk menghitung nilai 

shifted sum, anda secara bergiliran menambahkan nilai baru kedalam akumulator dan 

menggeser akumulator ke kiri. “geser ke kiri” berarti “menambahkan dengan bilangan 

konstan.”

Untuk melihat bagaimana ini bekerja, ambil daftar bilangan  1, 2, 3, 4, 5, 6 dan hitung 

shifted sum dengan cara sebagai berikut, pertama inisialisasi akumulator dengan 0, lalu

1. Kalikan akumulator dengan 10.

2. Tambahkan elemen berikut dari daftar pada akumulator.

3. Ulangi sampai semua bilangan pada daftar telah dikalikan semua.

425
Sebagai latihan, tulis sebuah metode yang menghitung shifted sum nilai bilangan semua 

karakter pada String menggunakan pengali 16.

Untuk setiap tipe, kita bisa membuat fungsi yang mengambil nilai dengan tipe tersebut 

dan menghasilkan nilai bulat yang bersesuaian. Fungsi ini dinamakan fungsi hash, 

karena mereka sering terlibat membuat sebuah hash pada komponen sebuah objek. Nilai 

hash dari sebuah objek disebut hash code.

Ada satu cara lain yang dapat dilakukan untuk mengasilkan hash code untuk objek Java. 

Setiap objek java menyediakan metode hashCode yang mengembalikan integer yang 

bersesuaian dengan objek tersebut. Untuk tipe bawaan java, metode hashCode  

diimplementasikan sehingga jika dua objek yang memiliki data yang sama, mereka akan 

memiliki hash code yang sama. Dokumentasi dari metode ini menjelaskan apa itu 

fungsi hash. Anda lebih baik mengeceknya untuk mengetahui lebih lanjut.

Untuk tipe yang didefinisikan pengguna, hal ini tergantung pada pengimplementasi 

untuk menyediakan fungsi hash  yang sesuai. Fungsi hash default, yang disediakan pada 

kelas Object, Sering menggunakan lokasi objek untuk mengasilkan hash code, jadi 

notasi nya untuk suatu kesamaan adalah “shallow equality”.  Sering ketika kita mencari 

sebuah kunci pada Map kesamaan yang menggunakan  shallow equality bukan 

merupakan yang kita inginkan.

Terlepas dari bagaimana cara menghasilkan hash code, langkah terakhir adalah 

menggunakan modulus dan fungsi nilai absolut untuk memetakan hash code pada 

426
rentang indeks yang legal.

19.8 Mengubah Ukuran Hash Map.

Sebuah hash table berisi sebuah array (atau Vector) yang elemennya merupakan sebuah 

List. Dimana setiap List berisi jumlah entri yang kecil. Untuk menambah entri baru 

pada Map, kita menghitung hash code pada kunci yang baru dan menambah entri 

tersebut pada List yang sesuai.

Untuk mencari sebuah kunci, kita menghitung hash lagi dan mencarinya pada List yang 

sesuai. Jika panjang List terbatas maka waktu pencarian juga terbatas.

Jadi bagaimana cara membuat List tetap pendek?  Salah satu tujuan adalah bagaimana 

sebisa mungkin semua List tersebut tetap seimbang. Jadi tidak akan ada List yang sangat 

panjang dan pada saat yang sama List lain kosong.  Hal ini bukan hal yang mudah untuk 

dilakukan secara sempurna, ia tergantung pada seberapa baik kita memilih fungsi hash.

Bahkan dengan keseimbangan yang sempurna, rata rata panjang List berkembang secara 

linear dengan jumlah entri.  Dan kita harus meletakkan titik henti pada saat itu.

Solusinya adalah dengan mengikuti rata rata jumlah entri untuk setiap List, yang disebut 

load factor. Jika load factor terlalu tinggi kita harus mengubah ukuran hash table. 

Untuk mengubah ukuran, kita membuat hash table baru, biasanya dua kali lebih besar 

dari yang asli, ambil semua entri yang ada pada hash table yang lama. Mengenainya 

dengan fungsi hash. Dan meletakkannya kembali pada hash table yang baru. Biasanya 

kita bisa menggunaka fungsi hash yang sama. Kita hanya menggunakan nilai yang 

427
berbeda untuk operator modulus.

19.9 Kinerja dari pengubahan ukuran

Berapa lama waktu yang dibutuhkan untuk mengubah ukuran hash table? Yang jelas ia 

sebanding dengan banyak entri. Itu berarti sebagian besar waktu put membutuhkan 

waktu yang konstan, tetapi sesekali ketika kita melakukan pengubahan ukuran ia akan 

membutuhkan waktu yang linear.

Pada awalnya hal ini memang buruk. Bukankah ini menyalahi klaim saya bahwa kita 

melakukan put dengan waktu yang konstan? Terus terang ya. Tetapi dengan sedikit 

pengaitan, kita bisa memperbaikinya.

Beberapa operasi put membutuhkan waktu yang lebih lama dibandingkan dengan yang 

lain, mari kita gambarkan waktu rata rata dalam operasi put. Rata rata dilambangkan 

dengan c yaitu waktu konstan untuk put yang sederhana. Ditambah dengan p,  

prosentase waktu sebelum dilakukan pengubahan ukuran, di kali dengan kn, maka biaya 

untuk mengubah ukuran adalah.

t(n) = c + p ∙ kn 

(19.1)

Kita tidak tahu melambangkan apa c dan k, tetapi kita bisa menggambarkan apakah p 

itu. Bayangkan kita baru saja mengubah ukuran hash Map dengan memperbesar dua 

kali ukurannya. Jika terdapat n entri lalu kita dapat menambahkan tambahan n entri 

sebelum kita harus mengubah ukrannya lagi. Jadi persentasi waktu sebelum harus 

428
dilakukan pengubahan ukuran kembali adalah 1/n.

Dengan dimasukkan pada persamaan maka kita dapatkan

t(n) = c + 1/n ∙ kn = c + k 

(19.2)

Dengan kata lain, t(n) adalah waktu yang konstan.

19.10 Daftar Kata

map : Sebuah ADT(Abstract Data Type) yang mendefinisikan operasi pada kumpulan 

entri.

entri : Elemen pada map yang berisi sebuah kunci dan sebuah nilai.

kunci : Indeks , dapat berupa objek  apapun, digunakan untuk mencari nilai dalam map.

value : Elemen, dapat berupa objek apapun, disiman dalam map.

dictionary : nama lain dari map.

array assosiatif : nama lain dari dictionary.

hash map :  Sebuah implementasi efisien dari map.

fungsi hash : fungsi yang memetakan nilai pada tipe tertentu kepada bilangan bulat.

hash code: bilangan bulat yang berhubungan dengan sebuah nilai.

shifted sum : fungsi hash sederhana yang sering digunakan untuk objek majemuk 

seperti String

load factor : banyak entri dalam hashmap dibagi dengan banyak List dalam hashmap;  

sebagai contoh rata rata banyak entri tiap List.

429
19.11 Latihan

latihan 19.2

a. Hitung shift sum dari bilangan bilangan 1, 2, 3, 4, 5, 6 menggunakan pengali 10

b. Hitung shift sum dari bilangan bilangan 11,1 2,1 3,1 4,15, 16 menggunakan 

pengali 100

c. Hitung shift sum dari bilangan bilangan 11,1 2,1 3,1 4,15, 16 menggunakan 

pengali 10

latihan 19.3 

Bayangkan anda memiliki sebuah hash table yang berisi 100 List. Jika anda ingin 

mengambil sebuah nilai yang bersesuaian dengan kunci tertentu, dan kode hash dari 

kunci tersebut adalah 654321, pada indeks List keberapakah kunci tersebut akan berada 

(jika berada dalam map)?

Latihan 19.4

Jika terdapat 100 List dan terdapat 89 entri pada map dan List terpanjang  berisi 3 entri, 

dan panjang list tengah (median) adalah 1 dan 19% list adalah kosong, berapakah load  

factor nya?

Latihan 19.5

Bayangkan terdapat banyak orang pada sebuah pesta. Anda ingin mengetahui apakah 

ada diantara mereka yang memiliki hari ulang tahun yang sama. Pertama anda 

mendesain sebuah objek Java yang mewakili hari ulang tahun dengan dua variabel 

instance: bulan yang merupakan bilangan bulat antara 1 dan 12, dan hari yang 

merupakan bilangan bulat antara 1 dan 31.

430
Selanjutnya, anda membuat sebuah array dari objek hariulangtahun yang berisi satu 

objek untuk tiap orang pada pesta. 

a. Tulis sebuah metode equals untuk hariulangtahun sehingga hari ulang tahun 

dengan bulan dan hari yang sama adalah sama (equal).

b. Tulis sebuah metode bernama hasDuplicate yang mengambil sebuah array  

objek hariulangtahun dan mengembalikan true jika terdapat dua atau lebih orang 

yang memiliki hari ulang tahun sama. Algoritma anda harus hanya menjelajahi 

array objek hariulangtahun sekali.

c. Tulis sebuah metode yang bernama randomBirthdays dengan parameter integer 

n  dan mengembalikan array dengan n objek hariulangtahun yang atribut atribut 

nya diisi secara acak. Agar lebih sederhana, anda bisa mengganggap semua 

bulan adalah 30 hari.

d. Bangkitkan 100 array acak, masing masing array 10 objek hariulangtahun, dan 

lihat berapa banyak array yang berisi hari ulang tahun yang sama.

e. Jika terdapat 20 orang pada pesta, berapa kemungkinan satu atau lebih peserta 

pesta memiliki hari ulang tahun yang sama.

Latihan 19.6

Sebuah Map disebut invertible jika setiap kunci dan setiap nilai hanya muncul sekali. 

Pada HashMap selalu benar bahwa setiap kunci hanya muncul sekali, tetapi ada 

memnungkinkan nilai yang sama muncul beberapa kali. Itulah mengapa, beberapa 

HashMap invertible, dan beberapa tidak.

Tulis sebuah metode yang bernama isInvertible dengan parameter HashMap dan 

mengembalikan true jika map invertible dan false jika tidak.

431
Latihan 19.7

Tujuan latihan ini adalah untuk mencari 20 kata kata yang paling sering dipakai pada 

buku ini (buku ini yang masih dalam bahasa inggris). Tulislah kode yang menggunakan 

HashMap untuk menghitung frekuensi kemunculan kata. Download teks buku pada 

alamat http://kleq.web.ugm.ac.id/images/thinkapjava.txt. Pikirkan bagaimana 

seharusnya program anda menangani tanda baca dan hal hal lain yang muncul pada 

berkas.

Tulis program untuk menjawab pertanyaan pertanyaan di bawah ini:

a. Berapa banyak kata yang ada pada buku ini?

b. Berapa banyak kata yang berbeda muncul pada buku ini? 

c. Berapa kali kata “encapsulation” muncul?

d. Apa saja 20 kata kata yang paling sering muncul? Petunjuk: Ada struktur data 

lain yang mungkin bisa membantu untuk bagian latihan ini.

Latihan 19.8

Tulis sebuah metode untuk LinkedList yang mengecek apakah list mengandung loop.  

Anda tidak boleh mengasumsikan bahwa panjang List telah benar. 

Latihan 19.9

Tulis implementasi Map ADT yang menggunaka hash table(seperti yang didefinisikan 

pada bagian 19.2). Ujilah dengan program program yang telah anda buat sebelumnya.

a. Mulailah dengan implementasi Vector pada buku ini 

b. Ubah implementasi dengan menggunakan array dari LinkedList atau Vector  

yang berisi LinkedList.

Latihan 19.10 

432
Buat implementasi Set menggunakan HashMap

Latihan 19.11

Paket java.util menyediakan dua implementasi Map, yaitu  HashMap dan TreeMap,  

HashMap dibangun dengan meniru hash table seperti yang dijelaskan pada bab ini. 

TreeMap dibuat berdasarkan red­black tree, yang mirip dengan pohon pencarian pada 

latihan 17.6.

Meskipun kedua implementasi ini meyediakan antar muka yang sama, kita 

mengharapkannya mencapai kinerja yang berbeda. Sejalan dengan banyak entri n 

bertambah, kita berharap add dan contains menggunakan waktu konstan untuk 

implementasi hash table. Dan waktu yang logaritmik untuk implementasi dengan 

pohon.

Lakukan percobaan untuk mengkonfirmasi (atau membantah) prediksi ini, Buat sebuah 

program yang menambah n entri pada HashMap atau TreeMap, lalu panggil contains  

untuk setiap kunci pada entri tersebut. Catat waktu pengeksekusian program terhadap 

nilai n dan buat grafiknya. Apakah kinerja sesuai dengan perkiraan kita?

433
BAB 20

Kode Huffman

20.1 Variabel­length codes

Jika anda familiar dengan kode morse, anda mengetahui bahwa morse adalah sistem 

untuk mengkodekan huruf pada alfabet menjadi titik dan garis. Misalnya sinyal terkenal 

...­­­... mewakili huruf SOS yang termasuk kode panggilan internasional untuk meminta 

pertolongan.

Tabel berikut memperlihatkan kode tersebut:

Perhatikan bahwa beberapa kode lebih panjang dibandingkan dengan yang lain. Pada 

perancangan, huruf yang paling sering digunakan memiliki kode terpendek. Karena 

terbatasnya kode pendek sehingga huruf huruf dan simbol yang lain memiliki kode yang 

lebih panjang. Suatu pesan akan memiliki lebih banyak kode pendek dibandingkan kode 

yang panjang, sehingga meminimalisasi rata rata transmisi per huruf.

434
Kode seperti ini disebut variable­length codes. Pada bab ini kita akan melihat algoritma 

untuk membangkitkan variable­length codes yang disebut kode Huffman. Huffman 

merupakan algoritma yang menarik, tetapi juga merupakan latihan yang berguna karena 

implementasinya menggunakan banyak struktur data yang telah kita pelajari.

Di bawah ini garis besar untuk beberapa bagian berikutnya:

● Pertama, kita akan menggunakan sebuah contoh teks dalam bahas inggris untuk 

menghasilkan tabel frekuensi. Tabel frekuensi mirip seperti histogram, ia 

menghitung berapa kali setiap huruf muncul pada teks contoh.

● Inti dari kode huffman adalah pohon huffman. Kita akan menggunakan tabel 

frekuensi untuk membangun pohon huffman, lalu menggunakan pohon untuk 

mengkodekan dan memecah kode dari rangkaian yang ada.

● Langkah terakhir, kita akan menjelajahi phon huffman dan memangun tabel 

kode, yang berisi rangkaian titik dan garis untuk setiap pohon.

20.2 Tabel frekuensi 

Karena tujuannya adalah memberikan kode pendek pada kata yang umum, kita harus 

tahu berapa kali setiap huruf muncul. Pada cerita pendek Edgar Allen Poe “The Gold 

Bug”, salah satu karakter menggunakan frekuensi huruf untuk memecahkan chiper. Dia 

menjelaskan

“Sekarang dalam bahasa inggris, huruf yang paling sering muncul adalah e, 

setelah itu a o i d h n r s t u y c f g l m w b k p q x z”. 

Jadi misi pertama kita adalah melihat apakah Poe benar. 

435
Latihan 20.12 

Tulis sebuah kelas yang bernama FreqTab yang menghitung berapa kali setiap huruf 

muncul pada teks contoh. Download contoh teks cerita pendek favorit anda, dan analisa 

frekuensi masing masing huruf.

Saya menemukan bahwa lebih tepat membuat kelas FreqTab diturunkan dari HashMap.  

Lalu menulis metode increment yang mengambil huruf sebagai parameter dan 

menambah atau memperbaharui entri dalam HashMap untuk setiap huruf.

Anda dapat menggunakan keySet untuk mengambil entri pada HashMap, dan mencetak 

daftar huruf dan frekuensinya. Sayangnya, mereka tidak akan tampil secara berurutan. 

Latihan berikut menyelesaikan masalah ini.

Latihan 20.13

Tulis sebuah kelas yang bernama Pair yang mewakili pasangan huruf dan frekuensi. 

Objek pair harus berisi sebuah huruf dan frekuensi sebagai variabel instance. Pair harus 

mengimplementasikan Comparable sehingga objek Pair dengan frekuensi lebih 

tinggilah yang menang.

Sekarang urutkan pasangan huruf dan frekuensi dari HashMap dengan menjelajahi 

himpunan kunci, buat objek Pair, tambahkan Pair pada PriorityQueue, ambil Pair dari 

PriorityQueue dan cetak dengan urutan mundur berdasarkan frekuensi.

436
20.3 Pohon Huffman

Langkah berikutnya adalah membangun pohon huffman. Setiap simpul pada pohon 

berisi sebuah huruf dan frekuensinya, serta penunjuk ke simpul kiri dan kanan. Untuk 

membangun pohon Huffman, kita mulai dengan membuat himpunan pohon tunggal, 

satu dari setiap entri pada tabel frekuensi. Lalu kita membangun pohon dari bawah ke 

atas, dimulai dari huruf dengan frekuensi terendah dan secara berulang menggabungkan 

subphon sampai mendapatkan pohon tunggal yang berisi semua huruf.

Di bawah ini algoritma untuk membangun pohon Huffman secara lebih detil. 

1. Untuk setiap entri pada tabel frekuensi, buat pohon Huffman tunggal dan 

tambahkan pada PriorityQueue. Sehingga ketika kita mengambil pohon dari 

PriorityQueue, kita mendapatkan yang memiliki frekuensi terendah.

2. Ambil dua pohon dari PriorityQueue dan gabungkan dengan membuat sebuah 

simpul orang tua yang menunjuk pada pohon yang diambil tadi. Frekuensi 

simpul orang tua adalah jumlahan dari frekuensi anak anaknya.

3. Jika PriorityQueue kosong, maka algoritma selesai, jika tidak letakkan pohon 

baru pada PriorityQueue kembali ke langkah 2.

Sebagai contoh kita akan menggunakan teks di bawah untuk membentuk pohon 

Huffman.

Eastern Tennessee anteaters ensnare and eat red ants, detest ant

antennae (a tart taste) and dread Antarean anteater­eaters. Rare

Andean deer eat tender sea reeds, aster seeds and rats’ ears. Dessert?

Rats’ asses.

437
Teks di atas menghasilkan tebel frekuensi: 

e  40

a  32

t  24

s  22

n  20

r  19

d  13

Jadi setelah langkah 1, PriorityQueue akan terlihat seperti:

Pada langkah 2, kita mengambil dua pohon dengan frekuensi terendah (r dan d) dan 

menggabungkannya dengan membuat simpul orang tua dengan frekuensi 32. Nilai 

huruf untuk simpul internal kurang relevan, sehingga dihapus dari gambar. Ketika kita 

meletakkan pohon baru kembali ke PriorityQueue. Hasilnnya akan seperti di bawah:

Sekarang ulangi langkah sebelumnya, dengan menggabungkan s dan n:

Setelah iterasi berikutnya, kita memiliki kumpulan pohon seperti di bawah, Sebagai 

438
informasi kumpulan pohon biasa disebut hutan.

Setelah dua iterasi lagi, hanya akan ada tiga pohon yang tertinggal:

Ini adalah pohon Huffman untuk teks contoh. Sebenarnya, ia bukan satu satunya 

karena setiap kali kita menggabungkan dua pohon, kita memilih yang mana menjadi 

simpul kanan dan yang mana di kiri, dan ketika ada pohon yang sama pada 

PriorityQueue, kita memilih tergantung selera. Jadi akan ada banyak kemungkinan 

pohon pada contoh di atas. 

Jadi bagaimana kita mengambil sebuah kode dari pohon Huffman? Kode untuk 

setiap huruf dihitung dengan menelusuri jalan dari akar pohon sampai daun yang berisi 

huruf yang dimaksud. Misalnya jalan dari akar sampai s adalah kiri­kanan­kiri. Jika kita 

mengganti kiri dengan “.” dan kanan dengan “­” kita mendapatkan tabel kode di bawah:

e  ­.

a  ­­

439
t  ..­

s  .­.

n  .­­

r  ....

d  ...­

Perhatikan bahwa kita telah mencapai tujuan: huruf dengan frekuensi terbanyak 

memiliki kode paling pendek.

Latihan 20.14

Dengan perhitungan manual, gambarkan pohon Huffman untuk tabel frekuensi berikut:

e  93

s  71

r  57

t  53

n  49

i  44

d  43

o  37

20.4 Metode super

Salah satu cara untuk mengimplementasikan pohon Huffman adalah dengan 

menurunkannya dari kelas Pair dari latihan 20.13

public class HuffTree extends Pair implements Comparable {

    HuffTree left, right;

    public HuffTree (int freq, String letter,

                     HuffTree left, HuffTree right) {

440
        this.freq = freq;

        this.letter = letter;

        this.left = left;

        this.right = right;

    }

HuffTree mengimplementasikan Comparable sehingga kita bisa meletakkan pohon 

Huffman ke dalam PriorityQueue. Untuk mengimplementasikan Comparable, kita 

harus menyediakan metode compareTo. Kita bisa menuliskannya dari awal, tetapi akan 

lebih mudah jika menggunakan versi  compareTo dari kelas Pair.

Sayangnya, metode tersebut tidak melakukan apa tepatnya yang kita inginkan. Untuk 

Pair kita memberikan prioritas untuk frekuensi  yang lebih tinggi. Sedang pada pohon 

Huffman, kita menginginkan memberikan prioritas pada frekuensi yang lebih rendah. 

Tentu saja, kita bisa menuliskan versi baru dari compareTo tetapi itu tentunya akan 

menutupi (override) versi pada kelas di atasnya (kelas orang tua), padahal kita ingin 

bisa memanggil versi metode yang ada pada kelas orang tua.

Kata kunci super mengijinkan kita untuk memanggil metode yang telah ditutup. Ia 

disebut super karena kadang kadang kelas orang tua juga disebut superclasses.

Berikut contoh dari implementasi HuffTree:

public int compareTo (Object obj) {

    return ­super.compareTo (obj);

441
Ketika compareTo dipanggil pada HuffTree, ia akan memanggil versi compareTo pada 

kelas orang tua, dan menegatifkan hasilnya. Sehingga urutan prioritas menjadi terbalik.

Ketika kelas anak (juga disebut subclass) menutupi constructor, ia bisa memanggil 

konstruktor kelas orang tua dengan menggunakan super:

public HuffTree (int freq, String letter,

                 HuffTree left, HuffTree right) {

    super (freq, letter);

    this.left = left;

    this.right = right;

Pada contoh ini, konstruktor orang tua menginisialisasi freq dan letter, dan lalu 

konstruktor anak menginisialisasi left dan right.

Meskipun fitur ini berguna, ia juga memilliki kecenderungan untuk salah. Ada beberapa 

keterbatasan seperti misal konstruktor orang tua harus dipanggil pertama, sebelum 

variabel instance lain diinisialisasi, dan ada beberapa hal yang tidak ingin anda ketahui. 

Secara umum, mekanisme ini seperti perlengkapan p3k. Ketika anda mengalami 

masalah ia bisa membantu anda. Tetapi anda tahu apa yang lebih baik? Jangan masuk 

ke dalam masalah. Pada masalah ini, lebih mudah untuk menginisialisasi kesemua 

empat variabel instance pada konstruktor anak.

Latihan 20.15

Tulis definisi kelas HuffTree dari bagian ini dan sebuah kelas dengan metode build yang 

mengambil sebuah FreqTab dan mengembalikan sebuah HuffTree. Gunakan algoritma 

442
pada bagian 20.3.

20.5 Pemecahan Kode

Ketika kita menerima pesan yang dikodekan, kita menggunakan pohon Huffman untuk 

memecah kodenya. Di bawah ini algoritma untuk melakukan hal tersebut:

1. Mulai dari akar pohon Huffman

2. Jika simbol berikutnya adalah “.”, maka berlanjut ke anak sebelah kiri, jika tidak 

maka berlanjut ke anak sebelah kanan.

3. Jika anda berada pada simpul daun. Ambil hurufnya dan tambahkan pada hasil. 

Lalu kembali ke akar.

4. Ke langkah 2.

Perhatikan kode ..­­..­­, sebagai contoh. Mulai dari puncak pohon, kita menuju kiri­kiri­

kanan dan mendapatkan huruf t. kemudian kita mulai dari akar lagi, kanan­kiri dan 

mendapatkan huruf e, kembali ke puncak, lalu kanan­kiri dan kita mendapatkan huruf a. 

jika kodenya dibentuk dengan baik, kita seharusnya ada pada simpul daun ketika kode 

berakhir. Pada kasus ini pesannnya adalah tea.

Latihan 20.16

Gunakan contoh pohon Huffman untuk memecahkan kode berikut:

a. .­.­­.­­..­­­

b. .­...­­.­......­.

c. ...­­.­.....

d. ­.­­.­...­

Perhatikan ketika anda mulai memecahkan kode, anda tidak dapat mengetahui berapa 

443
banyak huruf pada kode atau berada di mana batas batas hurufnya.

Latihan 20.17

Tulis definisi kelas Huffman. Konstuktor memiliki parameter String yang mengandung 

contoh teks. Kelas harus bisa membuat tabel frekuensi dan pohon Huffman.

Buat metode yang bernama decode. Metode ini menggunakan parameter dalam bentuk 

titik dan garis dan menggunakan pohon Huffman untuk memecahkan kode dan 

mengembalikan hasilnya.

Catatan: Walaupun anda menggunakan contoh kalimat pada bagian 20.2, anda tidak 

akan mendapatkan pohon Huffman yang sama seperti pada bagian 20.3, jadi 

kemungkinan anda tidak akan bisa menggunakan program anda untuk memecahkan 

kode pada contoh latihan sebelumnya.

20.6 Pengkodean

Biasanya, pengkodean lebih sulit dibandingkan dengan pemecahan kode, karena untuk 

suatu huruf kita harus mencari simpul daun pada pohon yang berisi huruf tersebut dan 

dilanjutkan dengan menggambarkan lintasan dari akar sampai simpul tersebut.

Proses ini akan lebih efisien jika kita menjelajahi pohon sekali, memproses semua kode, 

dan membangun Map dari huruf ke kode (huruf sebagai kunci dan kode sebagai nilai).

Dari sekarang kita telah melihat banyak pohon penjelajahan, tetapi yang satu ini tidak 

biasa karena saat kita menjelajahi pohin, kita juga ingin menyimpan lintasan/jalan 

dimana kita berada. Awalnya ini memang kelihatan sulit, tetapi ada cara yang lebih 

alami untuk melakukan perhitungan secara rekursif. Kuncinya adalalah jika lintasan dari 

444
akar ke suatu simpul disimbolkan dengan rangkaian titik dan garis yang disebut 

lintasan, maka lintasan ke anak kiri pada simpul adalah lintasan + '­' dan lintasan ke 

anak sebelah kanan adalah lintasan + '.'.

Latihan 20.18

1. Tulis definisi kelas dari CodeTab, yang diturunkan dari HashMap.

2. Pada definisi CodeTab, tulis metode rekursif yang bernama getCodes. Metode 

ini menjelajahi pohon Huffman. Ketika ia mencapai simpul daun, ia akan 

mencetak huruf pada simpul dan kode yang menyimbolkan lintasan dari akar ke 

simpul tersebut.

3. Tulis konstruktor untuk CodeTab yang mengambil HuffTree sebagai parameter 

dan mengeksekusi getCodes untuk membangun tabel kode.

4. Pada kelas Huffman, tulis metode encode yang menjelajahi sebuah kalimat, 

mencari setiap karakter pada tabel kode dan mengembalikan kalimat yang telah 

dikodekan. Uji metode ini dengan melewatkan hasilnya pada decode dan lihat 

apakah ia mengembalikan kalimat yang asli.

20.7 Daftar Kata

hutan : kumpulan pohon

superclass : nama lain dari kelas orang tua

subclass : nama lain dari kelas anak.

super : kata kunci yang digunakan untuk memanggil metode yang ditutupi pada 

superclass.

445
Lampiran Foreach dan Generik

Generik

Generik adalah kemampuan baru pada Java 1.5 yang digunakan dalam pembentukan 

Collection (List, Set, dll). Para pengguna Java tentu mengetahui salah satu kelemahan 

penggunaan Collection sebelumnya adalah adanya keharusan untuk mengcasting Objek 

saat diambil dari Collection. Proses pengcastingan ini cukup berbahaya karena 

pengecekan apakah Casting bisa dilakukan dengan benar dilakukan saat runtime,  

sehingga berisiko menghasilkan RuntimeException. 

Untuk mengatasi hal di atas maka saat pembentukan Collection, telah diberitahu lebih 

dahulu tipe apa yang akan ada di dalam Collection inilah yang disebut generik. Generik 

dilakukan dengan menambahkan tipe data/tipe objek saat pendeklarasian Collection. 

Contoh deklarasi lama:
List l = new ArrayList();

Set s = new HashSet();

Contoh deklarasi dengan generik:
List <Integer>l = new ArrayList<Integer>();

Set<Double> s = new HashSet<Double>();

Penggunaan Generik mengakibatkan dua hal:

1. Kompiler akan mengecek apakah elemen yang ditambahkan ke dalam Collection 

valid atau tidak sehingga saat anda menambahkan elemen yang bertipe data berbeda 

dengan yang bisa diterima Collection maka akan terjadi Compile Error.

446
import java.util.*;

class Test{

        public static void main (String [] args){

                List<Integer> l = new ArrayList<Integer>();

       l.add(new Integer(1));

         }

Pada kode di atas Collection yang berupa List hanya akan menerima data yang bertipe 

Integer. Ketika anda mencoba menambahkan tipe data yang lain ke dalam List tersebut 

maka list tersebut akan error.

import java.util.*;

class Test{

        public static void main (String [] args){

                List<Integer> l = new ArrayList<Integer>();

                l.add(new Double(1));

        }

Sebagai contoh saya mencoba memasukkan data bertipe Double. Jika anda 

menggunakan Java  1.5 ke atas, kode akan mengalami error saat kompilasi, tetapi 

tidak jika anda menggunakan versi  sebelumnya. 

2. Dalam pengambilan objek dari Collection anda tidak perlu lagi melakukan 

pengcastingan karena tipe data yang ada pada Collection telah didefinisikan lebih 

dahulu.

447
import java.util.*;

class Test{

        public static void main (String [] args){

                List<Integer> l = new ArrayList<Integer>();

                l.add(new Integer(1));

                Integer i=l.get(0);

        }

Foreach

Foreach adalah syntax baru Java yang juga baru diperkenalkan semenjak Java 1.5. 

Foreach sangat berguna ketika anda ingin menjelajahi semua elemen dalam satu 

Collection  atau array. Syntax baru ini dikeluarkan karena sebelumnya untuk 

melakukan penjelajahan pada Collection  menggunakan metode Iterator yang cukup 

rumit dalam penggunaannya. 
import java.util.*;

class Test{

        public static void main (String [] args){

                List<Integer> l = new ArrayList<Integer>();

                l.add(1);

                l.add(2);

                Iterator iter=l.iterator();

                while(iter.hasNext()){

                        Object i=iter.next();

                        System.out.println(i);

                }

        }

448
Dalam penggunaan iterator seperti contoh di atas untuk menjelajahi Collection satu 

persatu diperlukan minimal 2 baris kode, yaitu mengambil objek iterator dan 

mengiterasinya menggunakan while. 

Dengan foreach hal di atas bisa disederhanakan
import java.util.*;

class Test{

        public static void main (String [] args){

                List<Integer> l = new ArrayList<Integer>();

                l.add(1);

                l.add(2);

                for(Integer i : l){

                        System.out.println(i);

                }

        }

Jika sebelumnya untuk menjelajahi Collection dibutuhkan minimal dua baris kode, 

maka dengan foreach kita hanya membutuhkan satu baris kode. Foreach juga 

sepenuhnya menggunakan kemampuan generik sehingga kita tidak perlu pengcastingan 

lebih dahulu.

Secara umum syntax foreach adalah:

for(<tipedatadalam Collection atay array> <namavariabel> : <Collection atau array yang akan 

dijelajahi>)

<statemen>

Dalam penggunaannya dalam array,  foreach tidak terlalu banyak berguna karena 

dengan menggunakan perulangan for biasa penjelajahan array bisa dilakukan dengan 

449
maksimal. Salah satu kelebihan foreach dibandingkan dengan for dalam penjelajahan 

array adalah syntax yang sederhana dan tidak perlunya menggunakan indeks saat 

mengakses elemen dalam array. 

import java.util.*;

class Test{

        public static void main (String [] args){

                int [] arr={1,4,5};

                for(int i : arr)

                        System.out.println(i);

        }

Tetapi dalam menjelajahi array foreach memiliki keterbatasan, bahwa di dalam foreach 

kita tidak bisa melakukan pemanipulasian terhadap isi array. Karena foreach tidak 

mereferensi langsung pada isi array tersebut.
import java.util.*;

class Test{

        public static void main (String [] args){

                int [] arr={1,4,5};

                for(int i :arr)

                        i=i+1;

                for(int i : arr)

                        System.out.println(i);

        }

Kode di atas sama sekali tidak akan mengubah isi array array. Sehingga saat anda 

mencetaknya yang tampil tetap array yang asli.

450
Daftar Kata 

Collection : Tipe umum Struktur data Java, struktur data List, Set, Map, dan lain lain 

diturunkan  dari kelas ini. Biasanya digunakan untuk mengacu pada keseluruhan 

struktur data pada Java.

RuntimeException : Eksepsi yang dilempar Java ketika terjadi kesalahan saat program 

Java  dijalankan

451
Jawaban Latihan

Bab 2

Latihan 2.1

class Date{

public static void main(String [] args){

String hari;

hari="Sabtu";

int tanggal;

tanggal=16;

String bulan;

bulan="September";

int tahun;

tahun=2006;

System.out.println("Format Amerika:");

System.out.println(hari+", "+bulan+" "+tanggal+", "+tahun);

System.out.println("Format Eropa:");

System.out.println(hari+" "+tanggal+" "+bulan+", "+tahun);

Latihan 2.2

class Time{

public static void main(String [] args){

452
int jam,menit,detik;

jam=6;

menit =26;

detik=20;

int detik_saat_ini;

detik_saat_ini=6*3600+26*60+20;

System.out.println("Detik saat ini sejak tengah malam adalah 

"+detik_saat_ini+" detik");

int jumlah_detik_dalam_sehari;

jumlah_detik_dalam_sehari=24*3600;

int sisa_detik=jumlah_detik_dalam_sehari­detik_saat_ini;

System.out.println("Sisa detik saat ini = "+sisa_detik+" detik");

int prosentase_sisa_detik;

prosentase_sisa_detik=sisa_detik*100/jumlah_detik_dalam_sehari;

System.out.println("Prosentase sisa detik saat ini = 

"+prosentase_sisa_detik+" %");

Bab 3

Latihan 3.1

453
Hour
11

main
Minute
59

Hour 11

printTime
Minute 59

Latihan 3.2

No, Iwug.

You wugga wug.

I wug.

Latihan 3.3

class  Latihan{

public static void zool(int a, String b, String c){

public static void main(String [] args){

zool(11,"chicken","gajah mada");

454
Latihan 3.4

class Date{

public static void printAmerican(String hari, int tanggal, String bulan, int 

tahun){

System.out.println(hari+", "+bulan+" "+tanggal+", "+tahun);

public static void printEuropean(String hari, int tanggal, String bulan, int 

tahun){

System.out.println(hari+" "+tanggal+" "+bulan+", "+tahun);

public static void main(String [] args){

String hari;

hari="Sabtu";

int tanggal;

tanggal=16;

String bulan;

bulan="September";

int tahun;

tahun=2006;

System.out.println("Format Amerika:");

printAmerican(hari,tanggal,bulan,tahun);

System.out.println("Format Eropa:");

printEuropean(hari,tanggal,bulan,tahun);

455
}

Latihan 3.5 

class Multadd{

public static void multadd(double a, double b, double c){

System.out.println(a*b+c);

public static void main(String [] args){

multadd(1.0,2.0,3.0);

//phi=180' 

//Math.log10 ada pada java versi 5(1.5)

multadd(Math.cos(180/4),0.5,Math.sin(180/4));

multadd(1,Math.log10(10),Math.log10(20));

yikes(3);

public static void yikes(double x){

multadd(x,Math.exp(­x),+(Math.sqrt(1­Math.exp(­x))));

Bab 4

Latihan 4.1

456
main

nLines n 4

nLines n 3

n 2
nLines

nLines n 1

Latihan 4.2

public static boolean isTriangle(int a, int b, int c){

if(a>(b+c))

return false;  

else if(b>(a+c))

return false;  

else if(c>(a+b))

return false;  

else

return true;

Bab 6

457
Latihan 6.1.a

Iterasi ke i n
1 10 10
2 5 10
3 6 10
4 3 10
5 4 10
6 2 10
7 1 10
8 2 10
9 1 10
b.

Loop tak berhingga 

10

Latihan 6.2.

a.public static int fooMethod (String s) {

int len = s.length ();

458
int i = 0;

int count = 0;

while (i < len) {

char c = s.charAt(i);

if (c == '(') {

count = count + 1;

} else if (c == ')') {

count = count ­ 1;

i = i + 1;

return count;

b. Metode yang jika terdapat kurung buka menambah 1 isi variabel counter dan jika 

terdapat kurung tutup akan mengurangi 1 nilai counter. Metode ini berguna untuk 

menentukan apakah suatu ekspresi yang menggunakan tanda kurung telah valid (masing 

masing memiliki kurung pasangan) atau tidak.

c. Pasangan karakter yang akan dicek sebaiknya dapat diubah ubah sesuai keperluan

class Test{

public static void main (String[] args) {

System.out.println(fooMethod("((3 + 7) * 2)",'(',')'));

459
}

public static int fooMethod (String s, char kar1, char kar2) {

int len = s.length ();

int i = 0;

int count = 0;

while (i < len) {

char c = s.charAt(i);

if (c == kar1) {

count = count + 1;

} else if (c == kar2) {

count = count ­ 1;

i = i + 1;

return count;

Latihan 6.3

public static double squareRoot (double number) {

double x0=number/2;

460
double x2=100;

double x1=90;

while(Math.abs(x2­x1)>=0.0001){

x1 = (x0 +number/x0)/2;

x2=   (x1 +number/x1)/2;

x0=x2;

return x2;

Latihan 6.4

public static double power(double x, int n){

double result=1;

for(int i=1; i<=n; i++)

result*=x;

return result;

Latihan 6.5

public static int faktorial(int x){

int result=1;

while(x!=1){

result*=x;

x­=1;

461
return result;

Latihan 6.6

a)

public class Latihan66 {

public static int faktorial(int x){

int result=1;

while(x!=1){

result*=x;

x­=1;

return result;

public static double myexp(double x,int n){

double result=1;

for(int i=1; i<=n; i++){

result+=power(x,i)/faktorial(i);

return result;

public static double power(double x, int n){

double result=1;

462
for(int i=1; i<=n; i++)

result*=x;

return result;

b.

public class Latihan66 {

public static int faktorial(int x){

int result=1;

while(x!=1){

result*=x;

x­=1;

return result;

public static double myexp(double x,int n){

double result=1;

double numerator=1;

double denominator=1;

for(int i=1; i<=n; i++){

numerator*=x;

denominator*=i;

result+=numerator/denominator;

463
}

return result;

public static double power(double x, int n){

double result=1;

for(int i=1; i<=n; i++)

result*=x;

return result;

c)

public static void check(double x){

System.out.println(x+"\t"+Math.exp(x)+"\t"+myexp(x, 100));

Latihan 6.7

public static double gauss(double x,int n){

double result=1;

double xvalue=1;

double denominator=1;

int sign=1;

for(int i=1; i<=n; i++){

sign=sign*(­1);

464
xvalue*=x;

denominator*=i;

result+=sign*(i+1)*xvalue/denominator;

return result;

Bab 7

Latihan Tambahan

 public static void printBackward(String s){

                int index = s.length()­1;

                while (index >= 0) {

                        char letter = s.charAt (index);

                        System.out.print(letter);

                        index = index ­ 1;

                }

                System.out.println();

        }

Latihan 7.2

Metode bing mencetak setiap karakter pada kalimat beserta indeksnya mulai dari huruf 

paling akhir.

Latihan 7.3

Program tidak akan mencetak bilangan secara terbalik tetapi akan mencetak 

465
penjumlahan digit pertama dan digit terakhir. Program harusnya seperti berikut:
int number = 17;
int lastDigit = number%10;
int firstDigit = number/10;
System.out.println (lastDigit +”“+firstDigit);

Latihan 7.4
Program akan mencetak mengkonversi bilangan basis 10 menjadi bilangan biner.

Latihan 7.5
class Palindrome{
public static char first(String str){
return str.charAt(0);
}

public static char last(String str){
return str.charAt(str.length()­1);
}

public static String middle(String str){
int indeks=1;
String result="";
while(indeks<str.length()­1){
result+=str.charAt(indeks);
indeks++;
}
return result;
}

public static boolean isPalindrome(String str){
if(str.length()<=1)
return true;
if(first(str)==last(str)){
String middle=middle(str);
return isPalindrome(middle);
}else{
return false;
}

466
}

 public static boolean isPalindromeIter(String str){
                if(str.length()<=1)
                        return true;
int length=str.length();
                for(int i=0; i<length/2; i++){
if(str.charAt(i)!=str.charAt(length­1­i))
return false;
}
return true;
        }
}

Latihan 7.6
public static boolean isAbcedarian(String str){
char [] charArr=str.toLowerCase().toCharArray();

for(int i=1; i<charArr.length; i++){

if(charArr[i]<=charArr[i­1])

return false;

return true;

Latihan 7.7

public static boolean isDupledrome(String str){

char [] charArr=str.toLowerCase().toCharArray();

for(int i=0; i<charArr.length; i+=2){

if(i+1>=charArr.length || charArr[i]!=charArr[i+1])

return false;

467
}

return true;

Latihan 7.8

public class Name {

public static boolean hasComma(String str){

char [] charArr=str.toCharArray();

for(int i=0; i<charArr.length; i++){

if(charArr[i]==',')

return true;

return false;

public static String convertName(String name){

if(hasComma(name))

return name;

else if(name.split(" ").length==1)

return name;

else{

String backname="";

int i=0;

for(i=name.length()­1; i>=0; i­­){

468
if(name.charAt(i)==' ')

break;

else

backname=name.charAt(i)+backname;

return backname+", "+name.substring(0,i);

public static int compareName(String name1, String name2){

name1=convertName(name1.toLowerCase());

name2=convertName(name2.toLowerCase());

for(int i=0; i<Math.min(name1.length(), name2.length()); i++){

if(name1.charAt(i)==name2.charAt(i))

continue;

else if(name1.charAt(i) > name2.charAt(i))

return 1;

else

return ­1;

if(name2.length()>name1.length())

return 1;

else if(name2.length() < name1.length())

return ­1;

469
else

return 0;

Latihan 7.9

public static char add(char c, int addition){

if(Character.isLowerCase(c)){

if(addition>26 || addition<­26 )

addition%=26;

int ascii=(char)c;

ascii+=addition;

if(ascii>122)

ascii=96+(ascii­122);

else if(ascii<97)

ascii=122+(96­ascii);

return (char)ascii;

else if(Character.isUpperCase(c)){

if(addition>26 || addition<­26 )

addition%=26;

int ascii=(char)c;

ascii+=addition;

if(ascii>90)

470
ascii=64+(ascii­90);

else if(ascii<65)

ascii=90+(64­ascii);

return (char)ascii;

return c;

Bab 8

latihan 8.1

b) 5

Latihan 8.2

Latihan 8.3

(5,8)

(5,8)

471
p1 dan p2 bukan merupakan alias,

karena masing masing objek dibuat saat pemanggilang "findCenter"

import java.math.BigInteger;

Latihan 8.4 

class Big{

public static int factorial(int n){

int result=1;

for(int i=n; i>=1; i­­){

result*=i;

return result;

public static BigInteger bigfactorial(int n){

BigInteger result=BigInteger.valueOf(1);

for(int i=n; i>=1; i­­){

result=result.multiply(BigInteger.valueOf(i));

return result;

472
public static void main(String [] args){

for(int i=1; i<=20; i++){

System.out.println("factorial "+i+" = "+Big.bigfactorial(i));

Latihan 8.5

public static BigInteger pow(int x, int n){

if(n==0)

return BigInteger.valueOf(1);

BigInteger t =pow(x,n/2);

if(n%2 == 0)

return t.multiply(t);

else

return t.multiply(t).multiply(BigInteger.valueOf(x));

Bab 9

Latihan 9.1

public class Tile{

473
int value;

char letter;

public Tile(char c, int v){

letter=c;

value=v;

public static void print(Tile t){

System.out.println("letter "+t.letter+" has value "+t.value);

public static void testTile(){

Tile t = new Tile('z',10);

Tile.print(t);

latihan 9.2

public class Date{

int date;

int month;

int year;

public Date(){}

474
public Date(int d, int m, int y){

date=d;

month=m;

year=y;

public static void main(String [] args){

Date d = new Date(11, 7, 1986);

Date d1 = new Date();

d1.date=11;

d1.month=7;

d1.year=1986;

Latihan 9.3

public class Rational{

int numerator;

int denominator;

public Rational(){

numerator=0;

denominator=0;

public Rational(int a, int b){

475
numerator=a;

denominator=b;

public static void printRational(Rational r){

System.out.println(r.numerator+"/"+r.denominator);

public void negate(){

numerator=­numerator;

public void invert(){

int temp=numerator;

numerator=denominator;

denominator=temp;

public static double toDouble(Rational r){

return (double)r.numerator/r.denominator;

public static int gcd(int a, int b){

if(b>a){

int temp=a;

a=b;

476
b=temp;

while(b>1){

int temp=b;

b=a%b;

a=temp;

if(b==1)

return 1;

else

return a;

public static Rational reduce(Rational r){

int gcd=gcd(r.numerator,r.denominator);

System.out.println("gcd ="+gcd);

Rational number = new Rational();

number.numerator=r.numerator/gcd;

number.denominator=r.denominator/gcd;

return number;

public static Rational add(Rational r1, Rational r2){

477
return new 

Rational(r1.numerator*r2.denominator+r2.numerator*r1.denominator,r2.denominator*r

1.denominator);

public static void main(String [] args){

Rational r = new Rational(36,20);

Rational.printRational(r);

r.negate();

Rational.printRational(r);

r.invert();

Rational.printRational(r);

System.out.println(Rational.toDouble(r));

r = Rational.reduce(new Rational(36,20));

Rational.printRational(r);

Bab 10

Latihan 10.1 dan 10.2

class RandomClass {

public static double randomDouble(double low, double high){

478
return low+(Math.random()*(high­1));

public static int randomInt(int low, int high){

return low+(int)(Math.random()*(high­1));

public static void main(String [] args){

System.out.println(randomDouble(0.6,7.8));

System.out.println(randomInt(7,8));

Latihan 10.3

public static int[] scoreHist(int [] scores){

int [] counts= new int[100];

for(int i=0; i<scores.length; i++){

int index=scores[i];

counts[index]++;

return counts;

latihan 10.4

public static boolean areFactors(int number, int [] factors){

for(int i=0; i<factors.length; i++){

479
if(number%factors[i]==0)

continue;

else

return false;

return true;

latihan 10.5

public static int findInRange(int [] arr, int bil, int low, int high){

if(low==high){

if( arr[low]==bil)

return low;

else

return ­1;

int mid=(low+high)/2;

int result=findInRange(arr,bil,low,mid);

if(result==­1){

int result1=findInRange(arr,bil,mid+1,high); 

return result1;

}else

return result;

480
Latihan 10.6

public static int[] arrayHist(int [] scores){

int [] counts= new int[11];

for(int i=0; i<scores.length; i++){

if(scores[i]<=0)

counts[0]++;

else if(scores[i]>=10)

counts[10]++;

else

counts[scores[i]]++;

return counts;

Latihan 10.8

a. 30

b. bob ==> 0­>2

   1­>4

   2­>6

   3­>8

   4­>10

c. menjumlahkan semua elemen array dan mengembalikan nilainya

481
Latihan 10.9

class Array {

public static int maxInRange(int [] arr, int low, int high){

if(low==high)

return arr[low];

if(low==high­1)

return Math.max(arr[low],arr[high]);

int mid=(low+high)/2;

return 

Math.max(maxInRange(arr,mid+1,high),maxInRange(arr,low,mid));

public static int max(int [] arr){

return maxInRange(arr,0,arr.length­1);

public static int findInRange(int [] arr, int bil, int low, int high){

if(low==high){

if( arr[low]==bil)

return low;

else

return ­1;

int mid=(low+high)/2;

482
int result=findInRange(arr,bil,low,mid);

if(result==­1){

int result1=findInRange(arr,bil,mid+1,high); 

return result1;

}else

return result;

public static void main(String [] args){

int [] arr={1,4,5,7};

System.out.println(findInRange(arr,71,0,3));

Latihan 10.10

class Sorter {

public static int indexOfMaxInRange(int [] arr, int low, int high){

int max=low;

for(int i=low+1; i<=high; i++)

if(arr[i]>arr[max])

max=i;

return max;

483
public static void swap(int [] arr, int index, int index1){

int swap=arr[index];

arr[index]=arr[index1];

arr[index1]=swap;

public static int[] sortArrays(int [] arr){

for(int i=0; i<arr.length­1; i++){

int index=indexOfMaxInRange(arr,i,arr.length­1);

swap(arr,i,index);

return arr;

public static void main(String [] args){

int [] arr={4,5,6,0,23,12};

arr=sortArrays(arr);

for(int i=0; i<arr.length; i++)

System.out.println(arr[i]);

latihan 10.11

//blank tiles diwakili oleh spasi(' ')

class LetterHist {

484
public static int [] letterHist(String kal){

int [] counts = new int[27];

char [] kar = kal.toCharArray();

for(int i=0; i<kar.length; i++){

if(kar[i]==' '){

counts[26]++;

continue;

kar[i]=Character.toLowerCase(kar[i]);

counts[kar[i]­97]++;

return counts;

public static void main(String [] args){

int count[]=letterHist("afathkFFUhskldh");

for(int i=0; i<count.length; i++)

System.out.println(count[i]);

latihan 10.12

class Doubloon{

public static boolean isDoubloon(String word){

int count[]=LetterHist.letterHist(word);

for(int i=0; i<count.length; i++)

485
if(count[i]==2 || count[i]==0)

continue;

else

return false;

return true;

public static void main(String [] args){

System.out.println(isDoubloon("alalsxxsx"));

latihan 10.13

class Scrabble {

public static boolean testWord(String tiles, String words){

int [] tilesCount=LetterHist.letterHist(tiles);

int [] wordCount=LetterHist.letterHist(words);

for(int i=0; i<wordCount.length; i++){

if(wordCount[i] <= tilesCount[i])

continue;

else

return false;

return true;

486
public static boolean testWordModif(String tiles, String words){

int [] tilesCount=LetterHist.letterHist(tiles);

int [] wordCount=LetterHist.letterHist(words);

int falseCount=0;

for(int i=0; i<wordCount.length; i++){

if(wordCount[i] <= tilesCount[i])

continue;

else

falseCount++;

if(falseCount<=tilesCount[26])

return true;

else

return false;

public static void main(String [] args){

System.out.println(testWordModif("qijbo","jjib"));

487
Bab 11

class CardUtility{

public static Card[] buildDeck(){

Card deck[] = new Card[52];

int index=0;

for(int suit=0; suit<=3; suit++){

for(int rank=1; rank<=13; rank++){

deck[index]= new Card(suit,rank);

index++;

return deck;

public static int handScore(Card [] card){

int total=0;

for(int i=0; i<card.length; i++){

int score=card[i].getRank();

if(score>10)

score=10;

total+=score;

return total;

488
public static int StringToSuit(String str){

if(str.equals("Clubs"))

return 0;

if(str.equals("Diamonds"))

return 1;

if(str.equals("Hearts"))

return 2;

if(str.equals("Spades"))

return 3;

else

return ­99;

public static int StringToRank(String str){

int result=­99;

try{

result=Integer.parseInt(str);

if(result>=2 && result<=10)

return result;

else

return ­99;

}catch(NumberFormatException e){

str=str.toLowerCase();

if(str.equals("ace"))

489
return 1;

if(str.equals("jack"))

return 11;

if(str.equals("queen"))

return 12;

if(str.equals("king"))

return 13;

else

return ­99;

public static Card parseCard(String str){

String [] token = str.split(" of ");

int rank=StringToRank(token[0]);

int suit=StringToSuit(token[1]);

System.out.println(suit+" "+rank);

if(rank==­99 || suit==­99)

return null;

else

return new Card(suit,rank);

public static int [] suitHist(Card [] card){

int [] hist = new int[4];

490
for(int i=0; i<card.length; i++)

hist[card[i].getSuit()]++;

return hist;

public static boolean isFlush(Card [] card) {

int [] hist=suitHist(card);

for(int i=0; i<hist.length; i++){

if(hist[i]>=5)

return true;

else

continue;

return false;

public static void main(String [] args){

parseCard("1 of Diamonds");

class Card{

int suit;

int rank;

public Card(){

491
suit=0;

rank=0;

public Card(int s, int r){

suit=s;

rank=r;

public int getSuit(){

return suit;

public int getRank(){

return rank;

Bab 12

latihan 12.1

class Search {

public static int findBisect(Deck d, Card c, int low, int high){

System.out.println(low+" "+high);

if(high<low)

return ­1;

492
int mid=(high+low)/2;

int comp=d.cards[mid].compareCard(c);

if(comp==0)

return mid;

else if(comp>0){

Deck sub=Deck.subDeck(d,low,mid­1);

return findBisect(sub,c,low,mid­1);

}else{

Deck sub=Deck.subDeck(d,mid+1,high);

return findBisect(sub,c,mid+1,high);

latihan 12.5

public class Poker{

public Deck[] getHands(){

Deck d= new  Deck();

Deck.shuffleDeck(d);

Deck[] arr = new Deck[4];

arr[0]=Deck.subdeck(d,0,4);

arr[1]=Deck.subdeck(d,5,9);

arr[2]=Deck.subdeck(d,10,14);

arr[3]=Deck.subdeck(d,15,19);

493
return arr;

public static boolean isFlush(Deck d){

return CardUtility.isFlush(d.cards);

public static boolean isThreeKind(Deck d){

Card[] cards=d.cards;

int [] counter = new int[13];

for(int i=0; i<cards.length; i++){

counter[cards[i].getRank()]++;

for(int i=0; i<counter.length; i++){

if(counter[i]==3)

return true;

else

continue;

return false;

public static boolean isFourKind(Deck d){

Card[] cards=d.cards;

494
int [] counter = new int[13];

for(int i=0; i<cards.length; i++){

counter[cards[i].getRank()]++;

for(int i=0; i<counter.length; i++){

if(counter[i]==4)

return true;

else

continue;

return false;

public static boolean isPair(Deck d){

Card[] cards=d.cards;

int [] counter = new int[13];

for(int i=0; i<cards.length; i++){

counter[cards[i].getRank()]++;

for(int i=0; i<counter.length; i++){

if(counter[i]==2)

return true;

else

495
continue;

return false;

public static boolean isTwoPair(Deck d){

Card[] cards=d.cards;

int [] counter = new int[13];

for(int i=0; i<cards.length; i++){

counter[cards[i].getRank()]++;

int pair=0;

for(int i=0; i<counter.length; i++){

if(pair==2)

return true;

if(counter[i]==2)

pair++;

else

continue;

return false;

496
public static boolean isStraight(Deck d){

Card[] cards=d.cards;

Card [] temp = new Card[cards.length];

for(int i=0; i<cards.length; i++)

temp[i]=cards[i];

for(int i=0; i<temp.length; i++){

int index=getLowestCard(temp,i,temp.length­1);

Deck.swapCards(temp,i,index);

if(i>=1){

if(temp[i].getRank()!=temp[i­1].getRank()+1)

return false;

return true;

public static boolean isFullHouse(Deck d){

Card[] cards=d.cards;

int [] counter = new int[13];

for(int i=0; i<cards.length; i++){

counter[cards[i].getRank()]++;

//return true if three & two = true

boolean three=false;

boolean two=false;

for(int i=0; i<counter.length; i++){

497
if(three && two)

return true;

if(counter[i]==3 )

three=true;

else if(counter[i]==2)

two=true;

else

continue;

return false;

private static int getLowestCard(Card[] c, int low, int high){

int min=low;

for(int i=low+1; i<=high; i++){

if(c[i].getRank()<c[min].getRank())

min=i;

return min;

498
latihan 12.2 s/d 12.7 kecuali 12.5

class Deck{

Card[] cards;

public Deck(int n){

cards = new Card[n];

public Deck(){

cards = new Card[52];

int index=0;

for(int suit=0; suit<=3; suit++){

for(int rank=1; rank<=13; rank++){

cards[index]=new Card(suit,rank);

index++;

public static Deck subdeck(Deck deck, int low, int high){

Deck sub = new Deck(high­low+1);

for(int i=0; i<sub.cards.length; i++)

sub.cards[i]=deck.cards[low+i];

return sub;

499
public static void swapCards(Card [] c, int i, int j){

Card temp=c[i];

c[i]=c[j];

c[j]=temp;

public static void shuffleDeck(Card[] c){

for(int i=0; i<c.length; i++){

int random=i+(int)(Math.random()*(c.length­1));

if(random<=51 && random >=0) 

                        swapCards(c,i,random);

public static void shuffleDeck(Deck d){

for(int i=0; i<d.cards.length; i++){

int random=i+(int)(Math.random()*(d.cards.length­1));

if(random<=51 && random >=0) 

                         swapCards(d.cards,i,random);

public static int findLowestCard(Card [] c, int low, int high){

//if(low<0 || high >=c.length)

// return ­99;

500
int min=low;

for(int i=low+1; i<=high; i++){

if(c[min].compareCard(c[i])==1)

min=i;

return min;

public static void sort(Card[]  c){

for(int i=0; i<c.length; i++){

int swap=findLowestCard(c,i,c.length­1);

if(swap!=­99)

swapCards(c,i,swap);

public static void incrementalShuffle(Deck d, Card c){

int random=0+(int)(Math.random()*(d.cards.length­1));

d.cards[random]=c;

public static Deck merge(Deck d1, Deck d2){

Deck result = new Deck(d1.cards.length+d2.cards.length);

int i=0;

int j=0;

501
for(int k=0; k<result.cards.length; k++){

//d1 empty

if(i==d1.cards.length){

result.cards[k]=d2.cards[j];

j++;

//d2 empty

}else if(j==d2.cards.length){

result.cards[k]=d1.cards[i];

i++;

}else if(d1.cards[i].compareCard(d2.cards[j])==­1){

result.cards[k]=d1.cards[i];

i++;

}else{

result.cards[k]=d2.cards[j];

j++;

return result;

502
public static Deck mergeSort1(Deck deck){

int mid=(deck.cards.length­1)/2;

Deck sub1=subdeck(deck,0,mid);

Deck sub2=subdeck(deck,mid+1,deck.cards.length­1);

sort(sub1.cards);

sort(sub2.cards);

Deck d = merge(sub1,sub2);

return d;

public static Deck mergeSort2(Deck deck){

if(deck.cards.length<=1)

return deck;

int mid=(deck.cards.length­1)/2;

Deck sub1=subdeck(deck,0,mid);

Deck sub2=subdeck(deck,mid+1,deck.cards.length­1);

sub1=mergeSort2(sub1);

sub2=mergeSort2(sub2);

Deck d = merge(sub1,sub2);

return d;

503
public static void main(String [] args){

Deck d = new Deck(5);

Card [] c = new Card[5];

c[0]= new Card(3,5);

c[1]= new Card(0,5);

c[2]= new Card(0,4);

c[3]= new Card(4,4);

c[4]= new Card(1,5);

d.cards=c;

Deck d1 = mergeSort2(d);

for(int i=0; i<d1.cards.length; i++){

System.out.println(d1.cards[i].getSuit()+" 

"+d1.cards[i].getRank());

Bab 13

latihan 13.2

public double abs(){

return Math.sqrt(real*real+imag*imag);

504
latihan 13.3

public static boolean equals(Complex a, Complex b){

return (a.real==b.real && a.imag==b.imag);

latihan 13.4

class Complex{

double real;

double imag;

public Complex(){

real=0;

imag=0;

public Complex(double r, double i){

real=r;

imag=i;

public void printComplex(){

System.out.println(real+"+"+imag+"i");

public void conjugate(){

505
imag=­imag;

public double abs(){

return Math.sqrt(real*real+imag*imag);

public static Complex normalize(Complex num){

double d = num.abs();

double real=num.real/d;

double imag=num.imag/d;

Complex c = new Complex(real,imag);

return c;

public void add(Complex x){

real=real+x.real;

imag=imag+x.imag;

public static void main(String [] args){

Complex x  = new Complex();

x.real=1;

x.imag=2;

506
Complex y = new Complex(3,4);

System.out.println(y.abs());

x.conjugate();

x.printComplex();

y.printComplex();

x.add(y);

x.printComplex();

Bab 14 

latihan 14.1

public class IntList {

    int length;

    Node head;

    public IntList () {

length = 0;

head = null;

    }

    public static Node removeSecond (Node list) {

        Node first = list;

507
        Node second = list.next;

        // make the first node refer to the third

        first.next = second.next;

        // separate the second node from the rest of the list

        second.next = null;

        return second;

    }

    public Node removeFirst(){

    if(head!=null){

    Node headLama=head;

    head=head.next;

    headLama.next=null;

    length­­;

    return headLama;

   }

   return null; 

      }

    public void set(int index,int cargo){

    

if(index>=1 && index<=length){

int i=1;

Node list=head;

508
while(i<index){

list=list.next;

i++;

list.cargo=cargo;

}     

    }

    public void add(int index, int cargo){

    if(index>=1 && index<=length){

    Node newNode = new Node();

    newNode.cargo=cargo;

    int i=1;

    Node list=head;

    while(i<index){

    list=list.next;

    i++;

    }

    newNode.next=list.next;

    list.next=newNode;

    length++;

    }

    }

    public void addLast(int cargo){

     Node newNode = new Node();

509
     newNode.cargo=cargo;

     int i=1;

             Node list=head;

     while(list.next!=null){                

list=list.next;                                 

     }

     newNode.next=list.next;

     list.next=newNode;

     length++;

    }

public void reverse(){

Node list=head;

Node temp=list.next;

list.next=null;

Node prev=list;

while(temp!=null){

list=temp;

temp=list.next;

list.next=prev;

prev=list;

head=list;

510
public void append(IntList list){

Node node = list.head;

while(node!=null){

addLast(node.cargo);

node=node.next;

public boolean checkLength(){

if(head==null)

return false;

Node node=head;

int panjang=0;

while(node!=null && node.next!=node){

panjang++;

node=node.next;

System.out.println(panjang);

System.out.println(length);

if(panjang==length)

return true;

else

return false;

511
    // print: print the list

    public void print () {

Node node;

System.out.print ("(");

// start at the beginning of the list

node = head;

// traverse the list, printing each element

while (node != null) {

    System.out.print (node.cargo);

    node = node.next;

    if (node != null) {

System.out.print (", ");

    }

System.out.println (")");

    }

    public void printBackward () {

System.out.print ("(");

if (head != null) {

512
    Node tail = head.next;

    Node.printBackward (tail);

    System.out.print (head);

System.out.println (")");

    }

    public static void main (String[] args) {

// note: the following is a really bad way to build a list.

// warning signs of badness: allocating two different kinds

// of objects, accessing the instance variables of another class,

// using the constant 3 to set the length

// create an empty list

IntList list = new IntList ();

// create three new nodes, unlinked

Node node1 = new Node ();

node1.cargo = 1;

Node node2 = new Node ();

node2.cargo = 2;

Node node3 = new Node ();

node3.cargo = 3;

513
// next up the nodes

node1.next = node2;

node2.next = node3;

node3.next = null;

list.head = node1;

list.length = 3;

list.print();

Node removed=list.removeFirst();

System.out.println("Node yang dihapus");

Node.printList(removed);

list.print();

System.out.println("ubah cargo indeks 2 jadi 6");

list.set(2,6);

list.print();

System.out.println("tambah node dengan kargo 5 di belakang node indeks ke 

1");

list.add(1,5);

list.print();

System.out.println("tambah node 7 di belakang list");

list.addLast(7);

514
list.print();

System.out.println("Reserve");

list.reverse();

list.print();

IntList list2 = new IntList ();

// create three new nodes, unlinked

Node node4 = new Node ();

node4.cargo = 4;

Node node5 = new Node ();

node5.cargo = 5;

Node node6 = new Node ();

node6.cargo = 6;

// next up the nodes

node4.next = node5;

node5.next = node6;

node6.next = null;

list2.head = node4;

list2.length = 3;

515
System.out.println("append list 4 5 6");

list.append(list2);

list.print();

System.out.println("Check length ="+list.checkLength());

    }

class Node {

    int cargo;

    Node next;

    // default constructor

    public Node () {

cargo = 0;

next = null;

    }

    // other constructor

    public Node (int cargo, Node next) {

this.cargo = cargo;

this.next = next;

    }

    public String toString () {

return cargo + "";

516
    }

    public static void printBackward (Node list) {

        if (list == null) return;

        Node head = list;

        Node tail = list.next;

        printBackward (tail);

        System.out.print (head + ", ");

    } 

    public static void printList (Node list) { 

         Node node = list;

 while (node != null) {

         System.out.print (node);

           node = node.next;

     }

    System.out.println ();

    } 

// This program is part of "How to think like a computer scientist,"

// by Allen B. Downey, which is available from thinkAPjava.com

// This program is licensed under the GNU Free Software License,

517
// the terms of which are available from www.gnu.org

latihan 14.2

class PembandingAngka{

public static void main(String [] args){

IntList list = new IntList();

Node node1 = new Node ();

node1.cargo = 3;

Node node2 = new Node ();

node2.cargo = 2;

Node node3 = new Node ();

node3.cargo = 1;

// next up the nodes

node1.next = node2;

node2.next = node3;

node3.next = null;

list.head = node1;

list.length = 3;

IntList list2 = new IntList();

Node node4 = new Node ();

518
node4.cargo = 2;

Node node5 = new Node ();

node5.cargo = 6;

Node node6 = new Node ();

node6.cargo = 1;

// next up the nodes

node4.next = node5;

node5.next = node6;

node6.next = null;

list2.head = node4;

list2.length = 3;

System.out.println("hasil = "+compare(list,list2));

public static int compare(IntList list1, IntList list2){

if(list1.length>list2.length)

return 1;

else if(list1.length<list2.length)

return ­1;

else{

519
Node node1=list1.head;

Node node2=list2.head;

int result=0;

while(node1!=null){

if(node1.cargo > node2.cargo)

result=1;

else if(node1.cargo < node2.cargo)

result=­1;

else if(node1.cargo == node2.cargo)

result=result;

node1=node1.next;

node2=node2.next;

return result;

Bab 15

15.1

import java.util.*;

class Latihan15_1{

public static void reverse(int [] arr){

520
Stack stack = new Stack();

for(int i=0; i<arr.length; i++){

stack.push(Integer.valueOf(arr[i]));

int indeks=0;

while(!stack.isEmpty()){

Integer i=(Integer)stack.pop();

arr[indeks]=i.intValue();

indeks++;

public static void main(String [] args){

int arr[]={3,4,5,6};

Latihan15_1.reverse(arr);

for(int i=0; i<arr.length; i++){

System.out.print(arr[i]+" ");

Latihan 15.2

public class LinkedList {

    int length;

    Node head;

521
    public LinkedList () {

length = 0;

head = null;

    }

    public static Node removeSecond (Node list) {

        Node first = list;

        Node second = list.next;

        // make the first node refer to the third

        first.next = second.next;

        // separate the second node from the rest of the list

        second.next = null;

        return second;

    }

    // print: print the list

    public void print () {

Node node;

System.out.print ("(");

// start at the beginning of the list

node = head;

522
// traverse the list, printing each element

while (node != null) {

    System.out.print (node.cargo);

    node = node.next;

    if (node != null) {

System.out.print (", ");

    }

System.out.println (")");

    }

    public void printBackward () {

System.out.print ("(");

if (head != null) {

    Node tail = head.next;

    Node.printBackward (tail);

    System.out.print (head);

System.out.println (")");

    }

public Node removeFirst(){

    if(head!=null){

523
    Node headLama=head;

    head=head.next;

    headLama.next=null;

    length­­;

    return headLama;

   }

   return null; 

      }

public void addFirst(Object cargo){

Node newNode = new Node();

newNode.cargo=cargo;

if(head==null){

head=newNode;

newNode.next=null;

length++;

     }

else{

newNode.next=head;

head=newNode;

length++;

524
public void add(int index, Object cargo){

    Node newNode = new Node();

    newNode.cargo=cargo;

    if(head==null){

head=newNode;

newNode.next=null;

length++;

    }

    else if(index>=1 && index<=length){

    int i=1;

    Node list=head;

    while(i<index){

    list=list.next;

    i++;

    }

    newNode.next=list.next;

    list.next=newNode;

    length++;

    }

    }

public static LinkedList split(String sentence){

String [] word=sentence.split(" ");

Node [] node = new Node[word.length];

for(int i=0; i<word.length; i++){

525
node[i] = new Node();

node[i].cargo=word[i];

LinkedList list = new LinkedList();

list.head=node[0];

for(int i=1; i<node.length; i++)

node[i­1].next=node[i];

node[node.length­1]=null;

list.length=word.length;

return list;

public static String join(LinkedList list){

Node node = list.head;

String result="";

while(node!=null){

result+=node.cargo+" ";

node=node.next;

return result;

public String toString(){

return LinkedList.join(this);

526
    public static void main (String[] args) {

// note: the following is a really bad way to build a list.

// warning signs of badness: allocating two different kinds

// of objects, accessing the instance variables of another class,

// using the constant 3 to set the length

// create an empty list

LinkedList list = new LinkedList ();

// create three new nodes, unlinked

Node node1 = new Node ();

node1.cargo = new Integer(1);

Node node2 = new Node ();

node2.cargo = new Integer(2);

Node node3 = new Node ();

node3.cargo = new Integer(3);

// next up the nodes

node1.next = node2;

node2.next = node3;

node3.next = null;

527
list.head = node1;

list.length = 3;

list.print ();

list.printBackward ();

LinkedList linkedList=LinkedList.split("aaa akbfkjfb lij ndnd");

linkedList.print();

System.out.println(LinkedList.join(linkedList));

System.out.println("Test toString method");

System.out.println(linkedList.toString());

    }

class Node {

    Object cargo;

    Node next;

    // default constructor

    public Node () {

cargo = new Integer(0);

next = null;

    }

    // other constructor

    public Node (Object cargo, Node next) {

528
this.cargo = cargo;

this.next = next;

    }

    public String toString () {

return cargo + "";

    }

    public static void printBackward (Node list) {

        if (list == null) return;

        Node head = list;

        Node tail = list.next;

        printBackward (tail);

        System.out.print (head + ", ");

    }    

Latihan 15.3

class NewStack {

private LinkedList list;

public NewStack(){

list = new LinkedList();

list.head=null;

529
list.length=0;

public boolean isEmpty(){

return list.head==null;

public void push(Object o){

list.addFirst(o);

public Object pop(){

Node node = list.removeFirst();

return node.cargo;

public static void main(String [] args){

NewStack stack = new NewStack();

stack.push(Integer.valueOf(1));

stack.push(Integer.valueOf(2));

stack.push(Integer.valueOf(3));

while(!stack.isEmpty()){

Object o = stack.pop();

System.out.println(o);

530
}

latihan 15.4

import java.util.*;

import java.io.*;

class Balance {

private Stack parenthesStack;

private Stack bracketStack;

private Stack squigStack;

public Balance(){

parenthesStack = new Stack();

bracketStack = new Stack();

squigStack = new Stack();

public boolean read(String filename){

BufferedReader reader=null;

try{

reader = new BufferedReader(new FileReader(filename));

while(true){

String s = reader.readLine();

531
if(s==null)

break;

char [] kar = s.toCharArray();

for(int i=0; i<kar.length; i++){

if(kar[i]=='(')

parenthesStack.push(new Character('('));

else if(kar[i]==')'){

if(parenthesStack.isEmpty())

return false;

else

parenthesStack.pop();

else if(kar[i]=='[')

bracketStack.push(new Character('['));

else if(kar[i]==']'){

if(bracketStack.isEmpty())

return false;

else

bracketStack.pop();

else if(kar[i]=='{'){

squigStack.push(new Character('{'));

else if(kar[i]=='}'){

if(squigStack.isEmpty())

532
return false;

else

squigStack.pop();

}syst

if(squigStack.isEmpty() && bracketStack.isEmpty() && 

parenthesStack.isEmpty())

return true;

else

return false;

}catch(Exception e){

e.printStackTrace();

return false;

}finally{

try{

reader.close();

}catch(IOException ioe){

ioe.printStackTrace();

public static void main(String [] args){

533
System.out.println(new Balance().read("balance"));

latihan 15.5 dan 15.6

import java.util.*;

import java.io.*;

class EvalPostfix{

public static double evalPostFix(String postfix){

StringTokenizer token = new StringTokenizer(postfix);

Stack stack = new Stack();

while(token.hasMoreTokens()){

String operand=token.nextToken();

System.out.println(operand);

try{

Double angka=Double.valueOf(operand);

stack.push(angka);

}catch (NumberFormatException e){

double angka1=((Double)stack.pop()).doubleValue();

double angka2=((Double)stack.pop()).doubleValue();

if(operand.equals("+"))

stack.push(Double.valueOf(angka1+angka2));

else if(operand.equals("­"))

stack.push(Double.valueOf(angka1­angka2));

534
else if(operand.equals("*"))

stack.push(Double.valueOf(angka1*angka2));

else if(operand.equals("/"))

stack.push(Double.valueOf(angka1/angka2));

return ((Double)stack.pop()).doubleValue();

public static String inputLoop() throws IOException{

BufferedReader reader = new BufferedReader(new 

InputStreamReader(System.in));

String result="";

while(true){

System.out.print("=>");

String s = reader.readLine();

if(s==null)

break;

else if(isOperator(s) || isOperand(s)){

System.out.println(s);

result+=s+" ";

else if(s.equals("quit"))

break;

return result;

535
}

public static boolean isOperator(String operand){

if(operand.equals("+"))

return true;

else if(operand.equals("­"))

return true;

else if(operand.equals("*"))

return true;

else if(operand.equals("/"))

return true;

else

return false;

public static boolean isOperand(String s){

try{

Integer.parseInt(s);

return true;

}catch (NumberFormatException e){

return false;

536
public static void main(String [] args){

String s="";

try{

s = inputLoop();

}catch(IOException e){

e.printStackTrace();

System.out.println(s);

System.out.println(evalPostFix(s));

Bab 16

latihan 16.1

class Queue16_1 {

public Object[] array;

public int first,next;

public Queue16_1(){

array = new Object[128];

first=0;

next=0;

537
public boolean isEmpty(){

return first==next;

public void add(Object item){

array[next]=item;

next++;

public Object remove(){

if(isEmpty())

return null;

else{

Object result=array[first];

first++;

return result;

latihan 16.2

class Queue16_2 {

public Object[] array;

public int first,next;

public Queue16_2(){

538
array = new Object[3];

first=0;

next=0;

public boolean isEmpty(){

return first==next;

public void add(Object item){

array[next]=item;

if(isFull())

resize_array();

next=(next+1)%array.length;

private boolean isFull(){

return ((next+1)%array.length==first);

private void resize_array(){

Object [] temp=array;

array = new Object[2*temp.length];

for(int i=0; i<temp.length; i++){

array[i]=temp[i];

539
}

public Object remove(){

if(isEmpty())

return null;

else{

Object result=array[first];

first++;

return result;

public static void main(String [] args){

Queue16_2 queue = new Queue16_2();

queue.add("a");

queue.add("b");

queue.add("b");

queue.remove();

queue.add("a");

queue.add("c");

latihan 16.4

import java.util.*;

540
class SortedList extends LinkedList{

public SortedList(){

super();

public void add(Comparable o){

Node node=super.head;

int indeks=1;

while(node!=null){

if(o.compareTo(node)!=­1)

break;

indeks++;

node=node.next;

Node n = (Node)o;

//jika indeks satu maka gunakan method addFirst

if(indeks==1)

super.addFirst(n.cargo);

else

super.add(indeks­1,n.cargo);

public Node removeLast(){

return super.removeLast();

541
public static void main(String [] args){

SortedList list = new SortedList();

list.add(new Node(6));

list.add(new Node(4));

list.add(new Node(5));

list.print();

latihan 16.5

public Object maximum(){

Node node=head;

Node max=head;

while (node != null) {

    if(max.compareTo(node) == ­1)

max=node;

    node = node.next;

       }

return max;

latihan 16.6

//descending priority

class PriorityQueue extends SortedList{

542
public boolean isEmpty(){

return super.isEmpty();

public void add(int a){

Node n = new Node(a);

super.add(n);

public int remove(){

Node node=super.removeLast();

return ((Integer)node.cargo).intValue();

public static void main(String [] args){

PriorityQueue queue = new PriorityQueue();

queue.add(6);

queue.add(4);

queue.add(7);

while(!queue.isEmpty()){

System.out.println(queue.remove());

543
}

latihan 16.7

import java.util.PriorityQueue; 

import java.util.Date;

class Event{

private PriorityQueue queue;

public boolean isEmpty(){

return queue.size()==0;

public Event(){

queue = new PriorityQueue();

public void add(Date d){

queue.add(d);

public Date nextTime(){

if(queue.isEmpty())

return null;

else{

return (Date)queue.peek();

544
}

public Date nextEvent(){

if(queue.isEmpty())

return null;

else{

return (Date)queue.poll();

public static void main(String [] args){

Event event = new Event();

event.add(new Date(2006,10,6));

event.add(new Date(2006,11,6));

event.add(new Date(2006,10,7));

while(!event.isEmpty()){

System.out.println(event.nextTime().toString());

System.out.println(event.nextEvent().toString());

545
Bab 17

latihan 17.1

public static void visitPreorder(Tree tree){

if(tree==null)

return;

tree.node.visit();

visitPreorder(tree.left);

visitPreorder(tree.right);

latihan 17.2

import java.util.*;

class PreIterator implements Iterator{

private Iterator iter;

public PreIterator(Tree t){

iter=buildVector(t).iterator();

public void remove(){

iter.remove();

546
public boolean hasNext(){

return iter.hasNext(); 

public Object next(){

return iter.next();

private Vector buildVector(Tree t){

Vector v = new Vector();

v.add(t.getNode().getCargo());

if(t.left!=null)

v.addAll(buildVector(t.left));

if(t.right!=null)

v.addAll(buildVector(t.right));

return v;

import java.util.*;

class Tree{

public Node node;

public Tree left;

547
public Tree right;

public Tree(Node node, Tree left, Tree right){

this.node=node;

this.left=left;

this.right=right;

public Node getNode(){

return node;

public static void visitPreorder(Tree tree){

if(tree==null)

return;

tree.node.visit();

visitPreorder(tree.left);

visitPreorder(tree.right);

public PreIterator preorderIterator(){

return new PreIterator(this);

public static int longestPath(Tree tree){

548
if(tree==null)

return 0;

return 1+Math.max(longestPath(tree.left),longestPath(tree.right));

public static void main(String [] args){

Tree t1 = new Tree(new Node(2),null,null);

Tree t2 = new Tree(new Node(3),null,null);

Tree t = new Tree(new Node(1),t1,t2);

Tree t3 = new Tree(new Node(4),null,null);

Tree root = new Tree(new Node(5),t,t3);

visitPreorder(root);

PreIterator iter=root.preorderIterator();

System.out.println();

while(iter.hasNext()){

System.out.println(iter.next());

System.out.println("panjang tree "+longestPath(root));

549
class Node implements Visitable,Comparable{

private Object cargo;

public Node(Object o){

cargo=o;

public void visit(){

System.out.print(cargo+" ");

public Object getCargo(){

return cargo;

public int compareTo(Object obj){

Node node=(Node)obj;

int a=((Integer)this.cargo).intValue();

int b=((Integer)node.cargo).intValue();

if(a>b)

return 1;

if(a<b)

return ­1;

return 0;

550
interface Visitable{

public void visit();

latihan 17.3

a.9

b.2 3 * 1 +

c.3

latihan 17.4

public static int longestPath(Tree tree){

if(tree==null)

return 0;

return 1+Math.max(longestPath(tree.left),longestPath(tree.right));

latihan 17.5

import java.util.*;

class ComparableTree{

Comparable node;

public Tree left;

public Tree right;

public ComparableTree(Comparable node, Tree left, Tree right){

551
this.node=node;

this.left=left;

this.right=right;

public static Node findMax(Tree tree){

Node max=tree.node;

if(tree.left!=null){

Node left=findMax(tree.left);

if(max.compareTo(left)==­1)

max=left;

if(tree.right!=null){

Node right=findMax(tree.right);

if(max.compareTo(right)==­1)

max=right;

return max;

public static void main(String [] args){

Tree t1 = new Tree(new Node(2),null,null);

Tree t2 = new Tree(new Node(78),null,null);

552
Tree t = new Tree(new Node(1),t1,t2);

Tree t3 = new Tree(new Node(4),null,null);

Tree root = new Tree(new Node(5),t,t3);

System.out.println("max= "+findMax(root).getCargo());

latihan 17.6

import java.util.*;

class SearchTree {

Comparable node;

public SearchTree left;

public SearchTree right;

public SearchTree(Comparable node, SearchTree left, SearchTree right){

this.node=node;

this.left=left;

this.right=right;

public boolean contains(Object o){

return contains(o,this);

553
}

public Comparable getNode(){

return node;

public static boolean contains(Object o, SearchTree t){

Node n =(Node)o;

if(n.compareTo(t.getNode())==0)

return true;

if(n.compareTo(t.getNode())==­1){

if(t.left==null)

return false;

return contains(o,t.left);

else{

if(t.right==null)

return false;

return contains(o,t.right);

public static void main(String [] args){

SearchTree t1 = new SearchTree(new Node(2),null,null);

SearchTree t2 = new SearchTree(new Node(4),null,null);

SearchTree t = new SearchTree(new Node(3),t1,t2);

554
SearchTree t3 = new SearchTree(new Node(6),null,null);

SearchTree root = new SearchTree(new Node(5),t,t3);

System.out.println(root.contains(new Node(5)));

latihan 17.8­17.9

import java.util.*;

class TreeSetModify extends TreeSet {

public static TreeSet union(Set set1, Set set2){

Iterator iter1 = set1.iterator();

Iterator iter2 = set2.iterator();

TreeSet newset = new TreeSet();

while(iter1.hasNext()){

newset.add(iter1.next());

while(iter2.hasNext()){

newset.add(iter2.next());

return newset;

555
public static TreeSet intersection(Set set1, Set set2){

Iterator iter1 = set1.iterator();

TreeSet newset = new TreeSet();

while(iter1.hasNext()){

Object o =(Object)iter1.next();

if(set2.contains(o))

newset.add(o);

return newset;

Bab 18

latihan 18.1 18.2 dan 18.7

import java.util.*;

class Heap {

int [] array;

int size;

public Heap(){

556
array = new int[128];

size=0;

public void print(){

for(int i=0; i<array.length; i++){

if(array[i]!=0)

System.out.println(array[i]);

public Object getCargo(int i){

return array[i];

public void setCargo(int i, int o){

array[i]=o;

public int getLeft(int i){

return 2*i;

public int getRight(int i){

return 2*i+1;

557
public int getParent(int i){

if(i % 2 == 1)

return i/2;

else 

return (i­1)/2;

public void add(int o){

array[size]=o;

int indeks=size;

int parent=getParent(size);

while(indeks!=0){

if(array[parent]<array[indeks]){

int temp=array[parent];

array[parent]=array[indeks];

array[indeks]=temp;

indeks=parent;

parent=getParent(indeks);

else

break;

size++;

558
public void remove(int indeks){

int right=getRight(indeks);

int left=getLeft(indeks);

//indeks is tree's leaf

if(array[right]==0)

array[indeks]=array[right];

array[right]=array[size­1];

if(array[indeks]<array[left]){

int temp=array[indeks];

array[indeks]=array[left];

array[left]=temp;

reheap(left);

reheap(right);

private void reheap(int indeks){

if(array[indeks]==0)

return;

int right=getRight(indeks);

int left=getLeft(indeks);

if(array[indeks]<array[left]){

int temp=array[indeks];

559
array[indeks]=array[left];

array[left]=temp;

reheap(left);

if(array[indeks]<array[right]){

int temp=array[indeks];

array[indeks]=array[right];

array[right]=temp;

reheap(right);

public static boolean isComplete(Tree tree){

if(tree.left==null && tree.right==null)

return true;

int leftHeight=Tree.longestPath(tree.left);

int rightHeight=Tree.longestPath(tree.right);

if(leftHeight==1 && rightHeight==1)

return true;

if(leftHeight==rightHeight || leftHeight==rightHeight+1){

if(isComplete(tree.left)){

if(isComplete(tree.right)){

return true;

560
}

return false;

public static boolean isHeapProperty(Tree tree){

if(tree.left==null || tree.right==null)

return true;

Node cargo=tree.getNode();

Node left=tree.left.getNode();

Node right=tree.right.getNode();

if(cargo.compareTo(left)!=­1 && cargo.compareTo(right)!=­1)

if(isHeapProperty(tree.left))

if(isHeapProperty(tree.right))

return true;

return false;

public static void main(String [] args){

Heap heap = new Heap();

heap.add(79);

heap.add(60);

heap.add(65);

561
heap.add(56);

heap.add(57);

heap.add(18);

heap.add(20);

heap.add(14);

heap.add(28);

heap.add(20);

heap.print();

heap.add(68);

heap.print();

heap.remove(68);

import java.util.*;

class Tree{

public Node node;

public Tree left;

public Tree right;

public Tree(Node node, Tree left, Tree right){

this.node=node;

this.left=left;

this.right=right;

562
}

public Node getNode(){

return node;

public static void visitPreorder(Tree tree){

if(tree==null)

return;

tree.node.visit();

visitPreorder(tree.left);

visitPreorder(tree.right);

public static int longestPath(Tree tree){

if(tree==null)

return 0;

return 1+Math.max(longestPath(tree.left),longestPath(tree.right));

public static void main(String [] args){

Tree t1 = new Tree(new Node(2),null,null);

563
Tree t2 = new Tree(new Node(3),null,null);

Tree t = new Tree(new Node(1),t1,t2);

Tree t3 = new Tree(new Node(4),null,null);

Tree root = new Tree(new Node(5),t,t3);

visitPreorder(root);

System.out.println("panjang tree "+longestPath(root));

class Node implements Visitable,Comparable{

private Object cargo;

public Node(Object o){

cargo=o;

public void visit(){

System.out.print(cargo+" ");

public Object getCargo(){

return cargo;

564
public int compareTo(Object obj){

Node node=(Node)obj;

int a=((Integer)this.cargo).intValue();

int b=((Integer)node.cargo).intValue();

if(a>b)

return 1;

if(a<b)

return ­1;

return 0;

interface Visitable{

public void visit();

latihan 18.3

      79

60         65

     56          57        18     20

14  28     20  

79 68 65 56 60 18 20 14 28 20 57 

565
latihan 18.5

n div 2

latihan 18.6

n+1

Bab 19

Latihan 19.1

import java.util.*;

public class MyMap {

Vector entries;

public MyMap () {

entries = new Vector ();

public Object get (Object key) {

Iterator it = entries.iterator ();

while (it.hasNext ()) {

Entry entry = (Entry) it.next ();

if (key.equals (entry.key)) {

566
return entry.value;

return null;

public Object put (Object key, Object value) {

Object result = get (key);

if (result == null) {

Entry entry = new Entry (key, value);

entries.add (entry);

} else {

update (key, value);

return result;

private void update (Object key, Object value) {

Iterator it = entries.iterator ();

while (it.hasNext ()) {

Entry entry = (Entry) it.next ();

if (key.equals (entry.key)) {

entry.value = value;

break;

567
}

public Set keySet(){

Iterator it = entries.iterator ();

  Set s = new TreeSet();

while (it.hasNext ()) {

Entry entry = (Entry) it.next ();

s.add(entry.key);

return s;

public boolean containsKey(Object key){

if(get(key)==null)

return false;

else

return true;

class Entry {

     Object key, value;

568
     public Entry (Object key, Object value) {

         this.key = key;

         this.value = value;

     public String toString () {

         return "{ " + key + ", " + value + " }";

Penggunaan TreeSet pada metode keySet cukup mudah. Prinsipnya adalah anda tinggal 

mengambil semua kunci yang ada pada Vector dan memasukkannya satu persatu ke 

dalam TreeSet. Untuk melakukan hal ini Vector memiliki metode iterator yang bisa 

digunakan untuk menjelajahi semua elemen pada Vector.

Latihan 19.2

a 123456

b 111213141516

c 1234566

Latihan 19.3

21

Latihan 19.5

import java.util.*;

569
class BirthDay{

private int day;

private int month;

public BirthDay(int d, int m){

day=d;

month=m;

public int getDay(){

return day;

public int getMonth(){

return month;

public boolean equals(BirthDay b){

if(this.day==b.getDay() && this.month==b.getMonth()){

return true;

return false;

570
public static boolean hasDuplicate(BirthDay [] arr){

List list = new ArrayList();

for(int i=0; i<arr.length; i++){

String str=arr[i].getDay()+""+arr[i].getMonth();

if(list.contains(str))

return true;

else

list.add(arr[i]);

return false;

public static BirthDay[] randomBirthdays(int n){

BirthDay [] bdays = new BirthDay[n];

for(int i=0; i<n; i++){

int day=1+(int)(Math.random()*30);

int month=1+(int)(Math.random()*12);

bdays[i] = new BirthDay(day,month);

return bdays;

public static void main(String [] args){

for(int i=1; i<100; i++){

BirthDay[] bday = randomBirthdays(10);

571
System.out.println(hasDuplicate(bday));

Latihan 19.6

import java.util.*;

class Invertible{

public static boolean invertible(HashMap map){

Set set=map.keySet();

Iterator iter=set.iterator();

List list = new ArrayList();

while(iter.hasNext()){

Object o=map.get(iter.next());

if(list.contains(o))

return false;

else

list.add(o);

return true;

Latihan 19.7

572
import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.PriorityQueue;

import java.util.Set;

import java.util.StringTokenizer;

public class Excercise197 {

private BufferedReader reader;

private Map map = new HashMap();

private int numOfWord;

public Excercise197(String filename){

try{

reader = new BufferedReader(new InputStreamReader(new 

FileInputStream(filename)));

}catch(Exception e){

e.printStackTrace();

573
}

while(true){

try{

String content=reader.readLine();

if(content==null)

break;

StringTokenizer st = new StringTokenizer(content);

while(st.hasMoreTokens()){

numOfWord++;

String str=st.nextToken();

if(str.length()==1)

continue;

if(map.containsKey(str)){

int 

counter=((Integer)map.get(str)).intValue();

map.put(str, Integer.valueOf(counter+1));

}else

map.put(str, Integer.valueOf(1));

}catch(Exception e){

e.printStackTrace();

try{

reader.close();

}catch(IOException ioe){

574
ioe.printStackTrace();

public int getNumOfDifferentWord(){

return map.size();

public int getNumOfWord(){

return numOfWord;

public int getNumOfWord(String s){

Object o=map.get(s);

if(o==null)

return 0;

return ((Integer)o).intValue();

public String[] get20MostCommonWord(){

Set s=map.keySet();

Iterator iter=s.iterator();

PriorityQueue queue = new PriorityQueue();

575
while(iter.hasNext()){

String key=(String)iter.next();

Pair p = new Pair(key,((Integer)map.get(key)).intValue());

queue.add(p);

String [] arr = new String[20];

for(int i=0; i<20; i++){

arr[i]=((Pair)queue.poll()).getWord();

return arr;

/**

 * @param args

 */

public static void main(String[] args) {

// TODO Auto­generated method stub

Excercise197 e = new Excercise197("../../thinkapjava.txt");

//jawaban a

System.out.println(e.getNumOfWord());

//jawaban b

System.out.println(e.getNumOfDifferentWord());

//jawaban c

System.out.println(e.getNumOfWord("encapsulation"));

//jawaban d

576
String [] arr=e.get20MostCommonWord();

for(int i=0; i<arr.length; i++)

System.out.println(arr[i]);

class Pair implements Comparable{

String word;

int frequency;

public Pair(String w, int freq){

word=w;

frequency=freq;

public int getFrequency(){

return frequency;

public String getWord(){

return word;

public int compareTo(Object o){

577
Pair p=(Pair)o;

if(this.getFrequency() > p.getFrequency())

return ­1;

else if(this.getFrequency() < p.getFrequency())

return 1;

else

return 0;

Latihan 19.8

import java.util.*;

public class LinkedList {

    int length;

    Node head;

    public LinkedList () {

     length = 0;

     head = null;

    }

//metode yang mengecek apakah suatu list mengandung loop

public boolean containLoop(){

Node node=head;

578
Map map = new HashMap();

while(node != null){

if(map.containsKey(node))

return true;

else

map.put(node, new Integer(1));

node=node.next;

return false;

public static void main(String [] args){

LinkedList list = new LinkedList ();

// create three new nodes, unlinked

Node node1 = new Node ();

node1.cargo = new Integer(1);

Node node2 = new Node ();

node2.cargo = new Integer(5);

Node node3 = new Node ();

node3.cargo = new Integer(3);

579
// next up the nodes

node1.next = node2;

node2.next = node3;

node3.next = node1;

list.head = node1;

list.length = 3;

System.out.println(list.containLoop());

    

class Node {

    Object cargo;

    Node next;

    // default constructor

    public Node () {

cargo = new Integer(0);

next = null;

    }

580
Latihan 19.9

import java.util.*;

class NewMap{

Vector entries;

public NewMap(){

entries = new Vector();

public Object get(Object key){

Iterator it = entries.iterator();

while(it.hasNext()){

java.util.LinkedList entry =(java.util.LinkedList)it.next();

if(key.equals(entry.getFirst())){

return entry.getLast();

return null;

public Object put(Object key, Object value){

Object result=get(key);

581
if(result==null){

List l = new java.util.LinkedList();

l.add(key);

l.add(value);

entries.add(l);

}else{

update(key,value);

return result;

private void update(Object key, Object value){

Iterator it = entries.iterator();

while(it.hasNext()){

java.util.LinkedList entry =(java.util.LinkedList)it.next();

if(key.equals(entry.getFirst())){

entry.set(1, value);

break;

public Set keySet(){

Iterator it = entries.iterator();

TreeSet set = new TreeSet();

582
while(it.hasNext()){

java.util.LinkedList entry =(java.util.LinkedList)it.next();

set.add(entry.getFirst());

return set;

public static void main(String [] args){

NewMap map = new NewMap();

map.put("aa","dsdd");

map.put("saa","sdfdd");

map.put("saa","test");

Set set=map.keySet();

Iterator it = set.iterator();

while(it.hasNext()){

String key=(String)it.next();

System.out.println(key);

System.out.println(map.get(key));

Pada implementasi di atas digunakan Vector yang berisi LinkedList. Dimana isi dari 

Map disimpan dalam LinkedList. LinkedList yang digunakan adalah LinkedList bawaan 

dari Java yang pada paket java.util. Elemen pertama LinkedList adalah kunci entri 

583
sedang Elemen terakhir LinkedList adalah nilai yang disimpan dalam Map.

Latihan 19.10

import java.util.*;

class NewSet 

HashMap map ;

public NewSet(){

map = new HashMap();

public void clear(){

map = new HashMap();

public boolean remove(Object o){

if(map.remove(o) != null)

return true;

else

return false;

public boolean removeAll(Collection c){

Iterator it = c.iterator();

584
while(it.hasNext()){

if(remove(it.next()))

continue;

else

return false;

return true;

public void add(Object o){

map.put(o,null);

Latihan 19.11

Untuk melakukan pengujian saya menyediakan kelas BenchMark yang mengambil 

argumen banyak data (n) yang akan di test dan mencetak waktu yang digunakan oleh 

HashMap dan TreeMap dalam melakukan operasi add dan contains.

Untuk menggunakan kelas anda harus memberi argumen saat anda mengeksekusi kelas 

pada konsole atau commandprompt

Contoh penggunaan:

[fuad@fuad bab19]$ java Bencmark 200

TES METODE ADD

585
waktu hash map 1

waktu tree map 2

TES METODE CONTAINS

waktu hash map 1

waktu tree map 1

Eksekusi di atas akan mengetes HashMap dan TreeMap dengan data sebanyak 200. 

waktu yang dihasilkan adalah waktu eksekusi masing masing metode baik add maupun 

contains.

import java.util.*;

public class Bencmark {

HashMap hashMap = new HashMap();

TreeMap treeMap = new TreeMap();

public void add(int n){

System.out.println("TES METODE ADD"); 

long time=System.currentTimeMillis();

for(int i=1; i<=n; i++)

hashMap.put(new Integer(i),"test");

long time1=System.currentTimeMillis();

System.out.println("waktu hash map "+(time1­time)); 

time=System.currentTimeMillis();

586
for(int i=1; i<=n; i++)

treeMap.put(new Integer(i),"test");

time1=System.currentTimeMillis();

System.out.println("waktu tree map "+(time1­time)); 

public void testContains(){

System.out.println(); 

System.out.println(); 

System.out.println("TES METODE CONTAINS"); 

Iterator keys = hashMap.keySet().iterator();

long time=System.currentTimeMillis();

while(keys.hasNext()){

hashMap.containsKey(keys.next());

long time1=System.currentTimeMillis();

System.out.println("waktu hash map "+(time1­time));

keys = treeMap.keySet().iterator();

time=System.currentTimeMillis();

while(keys.hasNext()){

treeMap.containsKey(keys.next());

time1=System.currentTimeMillis();

System.out.println("waktu tree map "+(time1­time));  

587
}

public static void main(String [] args){

int n = Integer.parseInt(args[0]);

Bencmark b = new Bencmark();

b.add(n);

b.testContains();

BAB 20

Latihan  20.12

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

public class FreqTab extends HashMap {

588
BufferedReader reader;

Map map = new HashMap();

public FreqTab(String filename){

try{

reader = new BufferedReader(new InputStreamReader(new 

FileInputStream(filename)));

}catch(Exception e){

e.printStackTrace();

private void buildFrequencyTable(){

String content="";

while(true){

try{

content=reader.readLine();

if(content==null)

break;

char [] arr=content.toCharArray();

for(int i=0; i<arr.length; i++){

if(Character.isLetter(arr[i])){

increment(arr[i]);

589
}catch(Exception e){

e.printStackTrace();

try{

reader.close();

}catch(IOException ioe){

ioe.printStackTrace();

private void increment(char c){

Character key = Character.valueOf(Character.toLowerCase(c));

Object o=map.get(key);

if(o==null)

map.put(key,new Integer(1));

else{

int oldValue=((Integer)o).intValue();

map.put(key,new Integer(++oldValue));

public void print(){

590
Iterator iter=map.keySet().iterator();

while(iter.hasNext()){

Object key=iter.next();

System.out.println(key+" "+map.get(key));

public static void main(String [] args){

FreqTab ft = new FreqTab("FreqTab.java");

ft.buildFrequencyTable();

ft.print();

Kelas di atas mengambil parameter nama file pada konstruktor nya, membaca dan 

menghitung frekuensi kemunculan tiap tiap huruf. Sebagai contoh saya membaca file 

kode sumber kelas ini lagi.

Anda bisa mengubahnya dengan teks lain yang anda inginkan.

Latihan 20.13

import java.util.*;

public class pair implements Comparable{

int frequency;

591
char karakter;

public pair(char c, int a){

karakter=c;

frequency=a;

public pair(){

public int getFrequency(){

return frequency;

public char getKarakter(){

return karakter;

public int compareTo(Object o){

pair p=(pair)o;

if(this.getFrequency() > p.getFrequency())

return ­1;

else if(this.getFrequency() < p.getFrequency())

return 1;

else

592
return 0;

Definisi FreqTab yang menggunakan pair

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStreamReader;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.PriorityQueue;

public class FreqTab extends HashMap {

BufferedReader reader;

Map map = new HashMap();

public FreqTab(String filename){

try{

reader = new BufferedReader(new InputStreamReader(new 

FileInputStream(filename)));

}catch(Exception e){

e.printStackTrace();

593
}

public FreqTab(){

public void buildFrequencyTable(String teks){

char [] arr=teks.toCharArray();

for(int i=0; i<arr.length; i++){

if(Character.isLetter(arr[i])){

increment(arr[i]);

private void buildFrequencyTable(){

String content="";

while(true){

try{

content=reader.readLine();

if(content==null)

break;

char [] arr=content.toCharArray();

for(int i=0; i<arr.length; i++){

if(Character.isLetter(arr[i])){

594
increment(arr[i]);

}catch(Exception e){

e.printStackTrace();

try{

reader.close();

}catch(IOException ioe){

ioe.printStackTrace();

private void increment(char c){

Character key = Character.valueOf(Character.toLowerCase(c));

Object o=map.get(key);

if(o==null)

map.put(key,new Integer(1));

else{

int oldValue=((Integer)o).intValue();

map.put(key,new Integer(++oldValue));

595
}

public void print(){

Iterator iter=map.keySet().iterator();

PriorityQueue queue = new PriorityQueue();

while(iter.hasNext()){

Character key=(Character)iter.next();

pair p = new 

pair(key.charValue(),((Integer)map.get(key)).intValue());

queue.add(p);

while(!queue.isEmpty()){

Object o = queue.remove();

pair pairobj = (pair)o;

System.out.println(pairobj.getKarakter()+"  

"+pairobj.getFrequency());

public static void main(String [] args){

FreqTab ft = new FreqTab("FreqTab.java");

ft.buildFrequencyTable();

ft.print();

596
}

Latihan 20.14

447

261
186

151

110 93 80

e s r t n i d o
93 71 57 53 49 44 43 37

latihan 20.15

import java.io.*;

import java.util.*;

public class HuffTree extends pair {

HuffTree left,right;

public HuffTree(char c, int a,HuffTree left, HuffTree right){

super(c,a);

597
this.left=left;

this.right=right; 

public int compareTo(Object o){

return ­super.compareTo(o);

public HuffTree getLeft(){

return left;

public HuffTree getRight(){

return right;

public static void print(HuffTree tree){

System.out.println(tree.getFrequency());

if(tree.left!=null)

print(tree.left);

if(tree.right!=null)

print(tree.right);

public static HuffTree build(FreqTab ft){

598
Map map=ft.getMap();

Iterator iter=map.keySet().iterator();

PriorityQueue queue = new PriorityQueue();

while(iter.hasNext()){

Character key=(Character)iter.next();

HuffTree ht = new 

HuffTree(key.charValue(),((Integer)map.get(key)).intValue(),null,null);

queue.add(ht);

while(!queue.isEmpty()){

Object o = queue.remove();

HuffTree ht= (HuffTree)o;

o = queue.remove();

HuffTree ht1= (HuffTree)o;

HuffTree join = new HuffTree('  

',ht.getFrequency()+ht1.getFrequency(),ht,ht1);

if(queue.isEmpty()){

return join;

}else{

queue.add(join);

return null;

599
}

public static void main(String [] args){

FreqTab ft = new FreqTab("FreqTab.java");

ft.buildFrequencyTable();

HuffTree tree = HuffTree.build(ft);

HuffTree.print(tree);

Latihan 20.16

a. santa

b. steere

c. deer

d. east

Latihan 20.17

public class HuffMan {

private HuffTree tree;

public HuffMan(String text){

FreqTab ft = new FreqTab();

ft.buildFrequencyTable(text);

tree= HuffTree.build(ft);

600
public String decode(String teks){

char [] arr= teks.toCharArray();

HuffTree tree= this.tree;

String result="";

for(int i=0;i<arr.length; i++){

if(arr[i]=='.'){

tree=tree.left;

else if(arr[i]=='­'){

tree=tree.right;

if(tree.left==null && tree.right==null){

result+=tree.karakter;

tree=this.tree;

return result;

Latihan 20.18

import java.util.*;

class CodeTab extends HashMap{

601
private HuffTree root;

public CodeTab(HuffTree r){

root=r;

public void getCodes(){

traverseTree(root,"");

private void traverseTree(HuffTree t, String lastpath){

if(t.left == null && t.right== null){

put(Character.valueOf(t.getKarakter()),lastpath);

return;

traverseTree(t.getLeft(),lastpath+".");

traverseTree(t.getRight(),lastpath+"­");

}  

public class HuffMan {

private HuffTree tree;

public HuffMan(String text){

FreqTab ft = new FreqTab();

602
ft.buildFrequencyTable(text);

tree= HuffTree.build(ft);

public String decode(String teks){

char [] arr= teks.toCharArray();

HuffTree tree= this.tree;

String result="";

for(int i=0;i<arr.length; i++){

if(arr[i]=='.'){

tree=tree.left;

else if(arr[i]=='­'){

tree=tree.right;

if(tree.left==null && tree.right==null){

result+=tree.karakter;

tree=this.tree;

return result;

public String encode(String s){

char[] charArr=s.toCharArray();

603
CodeTab ct= new CodeTab(tree);

ct.getCodes();

String code="";

for(int i=0; i<charArr.length; i++){

Object codePart=ct.get(Character.valueOf(charArr[i]));

if(codePart!=null)

code+=(String)codePart;

return code;

public static void main(String [] args){

String teks="";

for(int i=1; i<=40; i++)

teks+="e";

for(int i=1; i<=32; i++)

teks+="a";

for(int i=1; i<=24; i++)

teks+="t";

for(int i=1; i<=22; i++)

teks+="s";

for(int i=1; i<=20; i++)

teks+="n";

for(int i=1; i<=19; i++)

teks+="r";

604
for(int i=1; i<=13; i++)

teks+="d";

HuffMan hm = new HuffMan(teks);

String code=hm.encode("desta");

System.out.println(code);

System.out.println(hm.decode(code));

605
History 

1994, Tulisan Original Oleg Allen Downey

2007, Penerjemahan dan Penambahan lampiran “For each dan Generik” oleh Wim 

Permana, Muhammad Fuad Dwi Rizki, dan Agus Juliardi

GNU Free Documentation License

Version 1.2, November 2002 

Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.


51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

0. PREAMBLE 

The purpose of this License is to make a manual, textbook, or other functional and 

useful document "free" in the sense of freedom: to assure everyone the effective 

freedom to copy and redistribute it, with or without modifying it, either commercially or 

noncommercially. Secondarily, this License preserves for the author and publisher a 

way to get credit for their work, while not being considered responsible for 

modifications made by others. 

This License is a kind of "copyleft", which means that derivative works of the document 

must themselves be free in the same sense. It complements the GNU General Public 

License, which is a copyleft license designed for free software. 

We have designed this License in order to use it for manuals for free software, because 

606
free software needs free documentation: a free program should come with manuals 

providing the same freedoms that the software does. But this License is not limited to 

software manuals; it can be used for any textual work, regardless of subject matter or 

whether it is published as a printed book. We recommend this License principally for 

works whose purpose is instruction or reference. 

1. APPLICABILITY AND DEFINITIONS 

This License applies to any manual or other work, in any medium, that contains a notice 

placed by the copyright holder saying it can be distributed under the terms of this 

License. Such a notice grants a world­wide, royalty­free license, unlimited in duration, 

to use that work under the conditions stated herein. The "Document", below, refers to 

any such manual or work. Any member of the public is a licensee, and is addressed as 

"you". You accept the license if you copy, modify or distribute the work in a way 

requiring permission under copyright law. 

A "Modified Version" of the Document means any work containing the Document or a 

portion of it, either copied verbatim, or with modifications and/or translated into 

another language. 

A "Secondary Section" is a named appendix or a front­matter section of the Document 

that deals exclusively with the relationship of the publishers or authors of the Document 

to the Document's overall subject (or to related matters) and contains nothing that could 

fall directly within that overall subject. (Thus, if the Document is in part a textbook of 

mathematics, a Secondary Section may not explain any mathematics.) The relationship 

could be a matter of historical connection with the subject or with related matters, or of 

legal, commercial, philosophical, ethical or political position regarding them. 

The "Invariant Sections" are certain Secondary Sections whose titles are designated, 

607

You might also like