Anda di halaman 1dari 456

Mulai Belajar java dari mana? ...

Rabu, 13/05/2009 - 18:33 — AryaJimbaran


Ini adalah pertanyaan yang paling sering ditanyakan
Saya sendiri belajar Java secara otodidak. Tidak melalui bangku
kuliah (saya kuliah Teknik Industri), tidak juga ikut kursus atau
pelatihan. Pada waktu itu -sekitar tahun 2002- milis jug-indonesia dan jlinux
belum seramai sekarang. Sehingga untuk konsultasi dan tanya-jawab agak
sulit. Perlu diperhatikan juga bahwa pada masa itu blog belum ngetren.
Jarang ada blog yang membahas pemrograman Java dalam bahasa Indonesia.
Singkat kata, resource di internet tidak sebanyak saat ini (awal 2006).
Sebelum mulai belajar Java, kemampuan teknis saya adalah sebagai berikut:
Bisa menggunakan Linux, tapi sebatas user, bukan administrator ahli.Mengerti tentang basic
networking (IP Address, Subnet, cara kerja DNS, dan sedikit tentang routing)Mengerti sedikit
tentang relational database. SELECT, INSERT, UPDATE sih bisa. Bisa PHP sedikit-sedikit.
Cuma bisa HelloWorld, dan simpan isian
form HTML ke dalam database. Tapi untuk aplikasi skala besar belum
pernah buat.
Dengan modal pas-pasan seperti itu, saya berhasil diterima bekerja
di sebuah kursus pendidikan franchise dari India. Waktu itu mereka baru
membuka cabang di Surabaya, dan saya masuk sebelum grand-launching
dilakukan.
Karena masih baru, siswa peserta kursus juga masih sedikit.Seingat
saya, sehari cuma ada satu kelas selama 4 jam sehari. 4 jam sisanya, 20
perangkat komputer terbaru terhubung dengan jaringan termasuk satu
asisten lab (tidak lain dan tidak bukan adalah saya) praktis menjadi
pengangguran. Internet di sana dial-up, tapi ada beberapa buku
pelajaran dan referensi di perpustakaan mini.
Waktu luang banyak, komputer banyak, buku banyak, internet agak
lemot. Ya sudah, akhirnya saya ngoprek saja sendirian. Instruktur di
sana, walaupun native speaker India, nampaknya kurang kompeten,
sehingga kalo tanya ke dia, yang ada malah tambah bingung.
Minggu-minggu pertama saya habiskan membuat website dengan PHP.
Berusaha bikin Content Management System kecil-kecilan. Tapi karena
belum pengalaman, yang ada malah berantakan. Pengguna bukannya menjadi
mudah malah menjadi sulit, karena untuk posting artikel harus mengerti
HTML dan PHP :D. Padahal niatnya mau memudahkan. Yah, mau bagaimana
lagi … ada masanya ketika kita masih muda dan bodoh :P
Bosan dengan PHP, saya mulai lihat-lihat buku di perpustakaan. Ada
VB, Java, Windows 2000 Server, Oracle, dan sebagainya. Entah karena
background saya yang pengguna Linux, saya kurang tertarik belajar VB.
Selain itu, instruktur di sana (menganggap dirinya) master VB. Jadi
saya tidak mau kompetitif dengan belajar VB juga. Oracle terlalu sulit
buat saya (waktu itu). Instalasi saja sulitnya setengah mati.
Installernya terlalu banyak tanya ini-itu yang saya gak ngerti apa
jawabannya. Windows 2000 Server juga kelihatan kurang menarik. Jadilah
akhirnya saya pilih belajar Java saja.
Saya coba belajar dari buku yang ada. Referensinya waktu itu Core
Java vol 1 dan 2 karangan Cay Horstmann. Belakangan saya tau kalo buku
itu sangat bagus dan lengkap. Ada beberapa konsep rumit seperti anonymous inner class yang
dijelaskan dengan sangat baik di sana. Tapi untuk pemula, Core Java itu relatif sulit dimengerti.
Sekitar sebulan saya berputar-putar mencari cara belajar dan
referensi yang bagus. Karena kualitas dan kecocokan referensi dengan
cara belajar kita akan sangat berpengaruh terhadap kecepatan belajar.
Setelah browsing ke website Sun, saya berhasil menemukan tutorial Java dan dokumentasi Java.
Ini merupakan referensi yang benar-benar cocok buat saya. Dengan
bermodalkan dua bahan tersebut, akhirnya dua bulan berikutnya menjadi
terang-benderang.
Satu demi satu konsep Java saya pelajari:
Sintaks dan Semantic (for loop, statement, if-else, dsb)Konsep OOPImplementasi Class dan
Object di JavaPackageI/OCollectionSwingThreadJDBCdsb
Sampai akhirnya saya lumayan bisa membuat aplikasi desktop sederhana yang mengakses
database.
Pada bulan keempat, saya masuk ke kantornya instruktur dan menemukan
buku baru. Modul pelatihan Java Servlet. Wah, ada mainan baru. Segera
saja saya coba semua contoh kodenya. Lumayan dari buku tersebut saya
bisa memahami web.xml, servlet, dan application server. Waktu itu Tomcat belum terkenal
seperti sekarang. Saya pakai Java Web Server untuk mendeploy servlet.
Sekitar enam bulan kemudian, saya sudah cukup mengerti apa itu EJB
(waktu itu masih versi 1.x) dan bisa mendeploy EJB kecil-kecilan.
Kemudian saya ditugaskan menjadi dosen di Stikom, sebagai bagian
dari paket kerjasama kursus tempat saya bekerja dengan Stikom. Di sana
lebih banyak teman diskusi dan buku.
Dari titik ini, perjalanan belajar Java menjadi lebih mudah. Karena
selain perpustakaan cukup lengkap, milis java juga sudah lumayan aktif.
Sehingga saya dapat mainan baru seperti Hibernate dan Ant.
Sudah cukup panjang ceritanya. Pesan moral dari cerita ini adalah:
Dengan waktu luang dan referensi yang tepat, belajar Java secara otodidak sangat mungkin
dilakukan Download tutorial dan dokumentasi Java yang dikeluarkan Sun. Banyak berlatih (saya
berlatih 6-8 jam sehari, setelah jam kantor saya masih stay untuk belajar)Untuk dapat melakukan
poin #1 dan #2, kemampuan bahasa Inggris (read-only sudah cukup) wajib dimiliki.
Sedikit saran dari saya, cobalah berkontribusi di milis. Baik
bertanya maupun menjawab. “Bagaimana kalo saya menjawab tapi jawabannya
salah? Nanti diketawain … ”
 Bab I - Pendahuluan [1]
 Bab II - Instalasi [2]
 Bab III - Memulai Java [3]
 Bab IV - Memulai Java Lebih Lanjut - Struktur Kontrol [4]
 Bab V - Subrutin [5]
 Bab VI - Pemrograman Berorientasi Objek [6]
 Bab VII - Kebenaran dan Ketangguhan Program [7]
 Bab VIII - Pengenalan Struktur Data dan Algoritma [8]
 Bab IX - Pemrograman Generik dan Kelas Koleksi [9]
 Bab X - Pengenalan Input/Output (I/O)
Bahasa pemrograman Java adalah bahasa pemrograman berorientasi objek yang mirip dengan bahasa
C++ dan Smalltalk. Java bersifat netral, tidak bergantung pada suatu platform, dan mengikuti prinsip
WORA (Write Once and Run Anywhere). Tidak seperti C atau C++, Anda dapat menulis program dalam
bahasa Java, cukup sekali mengkompilasi dan dapat dijalankan pada berbagai sistem operasi, seperti
Windows, Linux, Solaris, MacOS. Sebaliknya bahasa C++ bergantung pada suatu platform, karena
mengharuskan kita mengkompilasi program tersebut pada setiap sistem operasi yang dituju

Sejarah Java
Java dipelopori oleh James Gosling, Patrick Naughton, Chris Warth, Ed Frank, dan Mike
Sheridan dari Sun Microsystems, Inc pada tahun 1991. Mereka membutuhkan kurang lebih 18
bulan untuk membuat versi pertamanya. Bahasa ini pada awalnya disebut “Oak” tapi kemudian
diubah menjadi “Java” pada tahun 1995 karena nama Oak telah dijadikan hak cipta dan
digunakan sebagai bahasa pemrograman lainnya. Antara pembuatan Oak pada musim gugur
1992 hingga diumumkan ke publik pada musim semi 1995, banyak orang yang terlibat dalam
desain dan evolusi bahasa ini. Bill Joy, Arthur van Hoff, Jonathan Payne, Frank Yellin, dan Tim
Lindholm merupakan kontributor kunci yang mematangkan prototipe aslinya.
Java Modern
Java telah digunakan dalam banyak hal dan telah membuktikan keberadaannya pada abad ke 21.
Saat ini, Java digunakan bermacam jenis aplikasi seperti aplikasi embedded, aplikasi keuangan,
desktop, simulasi pesawat, pemrosesan citra, game, aplikasi perusahaan terdistribusi yang
disebut J2EE dan masih banyak lagi.
Java Virtual Machine (JVM)
Java Virtual Machine merupakan aplikasi sederhana yang ditulis dalam bahasa C untuk
mengeksi program yang ditulis dalam bahasa Java. Pada saat kompilasi (perubahan dari bahasa
tingkat tinggi ke bahasa lebih rendah), program tersebut diubah menjadi KODE BYTE.
Kemudian pada saat eksekusi, JVM membaca kode byte tersebu dan mengubahnya menjadi
bahasa mesin yang dimengerti oleh sistem operasi tempat program tersebut dijalankan.
Karena JVM sangat bergantung pada platformnya (bahasa mesin merupakan bahasa level rendah
yang hanya dimengerti oleh suatu mesin tertentu, misalnya Intel, tapi tidak dapat dimengerti oleh
mesin lain, seperti Macintosh), byte code ini dapat dibuat untuk terbebas dari kungkungan
platform tertentu. Code byte yang dihasilkan dalam proses kompilasi bahasa Java akan selalu
sama untuk setiap sistem operasi atau jenis mesinnya, tetapi JVM akan mengubah kode byte
tersebut menjadi bahasa mesin tujuannya.
Just In Time Compiler (JIT)
Meskipun Java didesain untuk diinterpretasi, secara teknis tidak ada yang menghalangi Java
untuk dikompilasi menjadi bahasa mesin seperti bahasa-bahasa pemrograman lainnya. Sun
menyediakan kompiler Just In Time Compiler (JIT) untuk mengkompilasi kode byte itu menjadi
bahasa mesinnya pada saat yang bersamaan dengan eksekusinya. Walaupun demikian,
pendekatan JIT ini menghasilkan kemampuan yang lebih dibandingkan dengan interpretasi biasa
Kelebihan Java

Bahasa pemrograman lain yang telah ada sebelum Java lahir sudah merupakan bahasa yang baik
dan mudah dipelajasi oleh programmer profesional. Akan tetapi para programmer ini
menginginkan sesuatu yang baru yang memiliki banyak hal yang menyelesaikan masalah
mereka. Utamanya adalah keamanan kode mereka. Hal ini melahirkan pikiran yang revolusioner
untuk menemukan bahasa pemrograman lain yang disebut Java. Tidak hanya keamanan tapi juga
beberapa hal yang sering disebut sebagai Java-Buzzwords. Kata-kata ini menjelaskan berbagai
fitur tambahan dan beberapa hal yang membuat Java demikian sukses dan diterima oleh dunia
perangkat lunak. Berikut ini adalah penjelasan serta keuntungan dari kata-kata tersebut.
Sederhana dan Berorientasi Objek
Seperti diuraikan sebelumnya, Java lahir dari suatu pemikiran mendalam akan bahasa
pemrograman yang ada pada saat itu, seperti C dan C++. Hal ini akan memudahkan programmer
profesional untuk dapat mengerti lebih jelas tentang Java, fungsionalitas, dan lain sebagainya
apabila ia memiliki pengetahuan dasar tentang C++ dan konsep pemrograman berorientasi objek.
Tujuannya agar konsep dasar dari teknologi Java dapat dimengerti dengan mudah, dan
programmer dapat segera menghasilkan sesuatu sedini mungkin. Tidak hanya ini, penemu Java
memastikan bahwa Java juga bermula dari bahasa pemrograman dasar yang sudah ada pada saat
itu. Kemudian mereka membuang berbagai fitur yang rumit dan membingungkan.
Bahasa pemrograman Java didesain sejak awal untuk menjadi bahasa yang berorientasi objek.
Setelah kira-kira 30 tahun, akhirnya teknologi objek menjadi kenyataan dan diterima oleh
sebagian besar komunitas pemrograman. Konsep berorientasi objek memungkinkan pembuatan
software yang kompleks, berbasis network, sehingga dapat disimpulkan bahwa teknologi Java
menghasilkan platform pembuatan perangkat lunak yang baik dan efisien serta berorientasi
objek.
Keuntungan yang Anda dapat dari Java

 Mulai dengan cepat: Java merupakan bahasa pemrograman berorientasi objek, mudah
dipelajari, terutama untuk programmer yang sudah menguasai C atau C++
 Tulis lebih sedikit program: Jumlah kelas, jumlah metode, dll, menunjukkan bahwa program
yang ditulis dalam bahasa pemrograman Java memiliki jumlah 4 kali lipat lebih kecil dari
program sama yang ditulis dalam bahasa C++
 Tulis program lebih baik: Bahasa pemrograman Java menganjurkan praktek membuat program
yang baik, dan automatic garbage collection membantu Anda untuk menghindari kebocoran
memori. Orientasi objeknya, arsitektur komponen JavaBeans, dan jangkauannya yanga luas, API
yang mudah diperluas, memungkinkan Anda menggunakan kode yang ada.
 Membuat program dengan lebih cepat: Bahasa pemrograman Java lebih mudah dari C++,
pemrograman akan menjadi 2 kali lipat lebih cepat, dengan jumlah baris yang jauh lebih sedikit.
 Menghindari kebergantungan pada platform tertentu: Anda dapat menjalankan program Anda
pada banyak platform dengan TIDAK menggunakan library yang ditulis spesifik untuk platform
tertentu.
 Tulis sekali, jalankan di mana saja: Karena aplikasi yang ditulis dalam bahasa Java dikompilasi ke
dalam kode byte yang bebas platform, aplikasi yang ditulis dapat jalan secara konsisten pada
platform apa saja.
 Distribusikan software Anda dengan mudah: Dengan Java Web Start, pengguna program Anda
akan dapat menggunakan aplikasi Anda dengan mudah. Sistem pengecekan versi otomatis pada
saat program dimulai menjamin pengguna Anda selalu menjalankan versi terkini. Apabila versi
baru tersedia, Java Web Start akan melakukan instalasi secara otomatis.

Bab II - Instalasi

Software yang digunakan :

 Eclipse 3.4 Ganymede digunakan dalam situs ini sebagai IDE (integrated development
environment)
 atau Java 6 SDK
 Eclipse IDE
 Instalasi Subversive, Plugin SVN untuk Eclipse

Eclipse IDE

Eclipse merupakan komunitas open source yang bertujuan menghasilkan platform pemrograman
terbuka. Eclipse terdiri dari framework yang dapat dikembangkan lebih lanjut, peralatan bantu
untuk membuat dan memanage software sejak awal hingga diluncurkan. Platform Eclipse
didukung oleh ekosistem besar yang terdiri dari vendor tekonologi, start-up inovatif, universitas,
riset institusi serta individu.
Banyak orang mengenal Eclipse sebagai IDE (integrated development environment) untuk
bahasa Java, tapi Eclipse lebih dari sekedar IDE untuk Java.
Komunitas Eclipse memiliki lebih dari 60 proyek open source. Proyek-proyek ini secara konsep
terbagi menjadi 7 categori :

1. Enterprise Development
2. Embedded and Device Development
3. Rich Client Platform
4. Rich Internet Applications
5. Application Frameworks
6. Application Lifecycle Management (ALM)
7. Service Oriented Architecture (SOA)

Secara umum Eclipse digunakan untuk membangun software inovatif berstandar industri, dan
alat bantu beserta frameworknya membantu pekerjaan menjadi lebih mudah.
Lisensi
Eclipse menggunakan EPL (Eclipse Public License), yaitu lisensi yang memungkinkan
organisasi untuk menjadikan Eclipse sebagai produk komersialnya, dan pada saat yang sama
meminta orang yang melakukan perubahan untuk mengkontribusikan hasilnya kembali kepada
komunitas.
Instalasi

 Anda membutuhkan Java 5 JRE untuk menjalankan Eclipse.


 Download Eclipse IDE for Java Developers untuk menggunakan kode pada situs Belajar Java ini.
 Gunakan utility pada sistem operasi anda untuk
membuka kompresi file tersebut ke dalam hard disk
anda.
 Catatan untuk Windows: Apabila Anda menggunakan
utilitas kompresi file yang berasal dari Windows XP atau
Windows Vista itu sendiri, kadang kala utilitas tersebut
tidak berhasil membuka file dengan nama yang panjang.
Jika Anda mengalami masalah dekompresi Eclipse pada
Windows, letakkan hasil dekompresi pada root
directory (misalnya C:\eclipse) atau gunakan software
dekompresi lain yang gratis seperti 7-Zip

Menjalankan Eclipse untuk pertama kali

Menjalankan Eclipse untuk pertama kali

 Cari file bernama eclipse.exe (pada Windows) atau eclipse (pada Ubuntu) kemudian double-click
 Pada saat Eclipse pertama kali dijalankan, Eclipse akan menanyakan workspace, yaitu folder
tempat proyek dan data diletakkan. Anda bisa menempatkan di mana saja asalkan jangan di
dalam folder Eclipse itu sendiri.
 Click Browse dan pilih folder yang ada inginkan. Tik "Use this as default and do not ask again"
 Halaman pembuka akan muncul. Klik "Workspace", tombol paling kanan berbentuk anak panah
untuk masuk ke dalam workspace Anda.

Program Java pertama Anda

 Klik "File -> New -> Java Project"


 Isi nama proyek (misalnya SelamatDatang), kemudian klik "Finish"
 Setelah Eclipse membuat proyek untuk Anda, di bagian kiri workspace Anda akan melihat
struktur direktori proyek Anda yang dimulai dengan nama proyek, folder src, dan folder JRE
System Library
 Klik kanan pada folder src, kemudian "New -> Package"
 Isi nama package (misalnya selamatdatang), kemudian klik "Finish"
 Klik kanan lagi pada folder selamatdatang, kemudian "New -> Class"
 Isi nama class (misalnya SelamatDatang)
 Karena class ini adalah class utama yang akan langsung dijalankan oleh JRE (Java Runtime
Environment), click "public static void main(String[] args)" pada bagian "Which method stubs
would you like to create?"

 Klik "Finish"
 Eclipse akan membuat program kosong yang berisi package dan class sesuai dengan nama yang
Anda masukkan pada tahap sebelumnya
 Sekarang ketik program berikut di bawah "// TODO"
System.out.println("Selamat Datang!");

 Kemudian simpan hasilnya

Menjalankan program Java pertama Anda

 Untuk menjalankan program Anda, klik "Run -> Run"


 Di bagian bawah pada tab yang berjudul "Console" hasil program Anda ditampilkan
 Program ini akan menampilkan tulisan Selamat Datang! seperti pada gambar berikut ini

Sisipan

Sisipan Ukuran

selamatdatang-class.gif 68.33 KB

Komentar
Instalasi Eclipse

Saya mau tanya,kalau eclipse diinstal diwindows7 kompatibel nggak ya? trims

menjalankan eclipse pertama kali

kak saya mau tanya... saya sudah instal eclipse java helios,caranya buka eclipse.exe klik 2
kali(sebelumnya saya pakai windows vista)tp kok gak bisa ya? dan ada kotak warning "The
eclipse executable launcher was unable to locate its companion shared library" knp ya?mohon
bantuannya.terima kasih.
coba letakkan eclipse di

coba letakkan eclipse di direktori utama, misalnya c:\eclipse atau d:\eclipse, jangan di dalam
desktop atau di dalam my documents. juga pastikan JRE terinstall. caranya pergi ke link ini
http://www.java.com/en/download/installed.jsp kemudian click "verify java". Jika tidak,
download JRE dari link "downloads" di halaman web yang sama dengan link di atas.

run java

Ka saya dah punya java jdk update 18. dan eclipse sebagai editor. tapi pada saat saya menulis
contoh program diatas, muncul kode eror berikut: Exception in thread "main" java.lang.Error:
Unresolved compilation problem: String literal is not properly closed by a double-quote at
belajar.belajar.main(belajar.java:18) padahal saya sudah yakin programnya sama seperti contoh
diatas mohon penjelasannya ya kak.

Coba import projectnya

Coba import projectnya langsung ke Eclipse, sepertinya kodenya beda, karena kode di atas hanya
sampai baris 14, sedangkan errornya ada di baris 18.

cara import projectnya

Dear,....
Coba import projectnya langsung ke Eclipse, sepertinya kodenya beda, karena kode di atas hanya
sampai baris 14, sedangkan errornya ada di baris 18.
Cara import projectnya gimana mas?
Thank's

Tanya tentang Package

Salam semuanya. 
Saya mau bertanya, sebenarnya apa tujuan dibuatnya suatu package pada step 4-5 di atas?
Apakah ini hal yang wajib atau optional?

Untuk coba-coba mungkin

Untuk coba-coba mungkin optional, tapi untuk buat program serius, package ini penting supaya
tidak bertabrakan dengan kelas lain yang dibuat oleh orang lain atau bahkan program kita
sendiri.
Anggap package ini seperti "direktori" atau "folder" dalam suatu program. Ketika Anda mulai
membuat program yang terdiri beberapa modul, misalnya satu modul untuk menangani I/O, satu
modul lagi untuk konektivitas ke database, satu modul lagi untuk display. Akan sangat mudah
untuk membagi program Anda ke dalam beberapa package daripada kesemuanya disimpan
dalam package default.
Instalasi Subversive, Plugin SVN untuk Eclipse

Untuk menggunakan contoh kode pada situs ini, Anda juga bisa menggunakan Subversion untuk
mengambil file langsung dari gudang SVN. Untuk menginstall Plugin Subversive, dengan
melakukan langkah-langkah berikut ini :
1. Klik "Help -> Software Updates -> Available Software"
2. Klik tombol "Add Site", kemudian masukkan alamatnya sebagai berikut :
http://subclipse.tigris.org/update_1.4.x

3. Setelah mengambil data plugin yang tersedia, pilih beberapa plugin seperti pada gambar
berikut, lalu klik "Install" :

4. Window baru akan muncul, klik "Finish", jangan lupa untuk mengaccept license
agreementnya.

Menguji Koneksi SVN

Setelah Anda berhasil melakukan instalasi plug-in Subversive, langkah-langkah berikut ini akan
membimbing Anda untuk menguji koneksi ke gudang (repository) kode pada SVN server.

1. Klik "New -> Project -> SVN -> Checkout Project from SVN"

2. Klik "Create a new repository location"


3. Masukkan http://belajarjava.googlecode.com/svn/trunk

4. Pilih folder selamatdatang dan klik Finish

5. Project baru akan tersedia di sebelah kiri workspace Anda. Klik "Run -> Run" dan pilh "Java
Application" untuk menjalankan program ini.

6. Selamat, Anda telah mempersiapkan software yang diperlukan.

Bab III - Memulai Java

Program komputer adalah rangkaian instruksi yang diberikan agar komputer dapat bekerja. Suatu
pekerjaan yang mungkin sederhana bagi manusia tidak dapat dimengerti oleh komputer. Manusia
harus memberikan petunjuk kepada komputer bagaimana melakukan suatutugas dalam bentuk
bahasa pemrograman. Bahasa pemrograman berbeda dengan bahasa manusia, karena komputer
membutuhkan aturan yang lebih baku apa yang boleh dan apa yang tidak boleh dalam suatu
bahasa pemrograman. Aturan ini disebut sintaks bahasa.

Sintaks bahasa pemrograman ditentukan berdasarkan apa yang bisa dilakukan oleh komputer,
misalnya loop (perulangan), cabang (branch), atau fungsi. Hanya program dengan sintaks yang
benar yang dapat dikompilasi atau diinterpretasi yang pada akhirnya bisa dijalankan di komputer.
Kompiler akan memberikan pesan kesalahan apabila ada kesalahan dalam sintaks sehingga kita
memperbaikinya.

Untuk menjadi programmer yang sukses, kita harus mengerti secara detail sintaks dari bahasa
pemrograman yang kita akan gunakan. Tetapi, sintaks hanya sebagian cerita. Kita ingin program
yang kita buat berjalan sesuai dengan yang kita inginkan. Artinya program tersebut harus benar
secara logika. Program yang benar secara logika disebut memiliki semantik yang benar.
Di situs ini kita akan mempelajari tentang sintaks dan semantik dari dari setiap bahasa
pemrograman Java. Sintaks mudah dihafal, tetapi semantik lebih seperti perasaan. Untuk itu,
coba download dan jalankan contoh-contoh program sehingga kita dapat memahami bagaimana
setiap program bekerja.

Melihat lebih dekat “SelamatDatang”

Applikasi SelamatDatang memiliki 4 komponen, yaitu :

 definisi paket (package)


 komentar
 definisi kelas (class)
 metode main

package selamatdatang;
 
public class SelamatDatang {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Selamat Datang!");
}
 
}

Mari kita bahas satu per satu.

Definisi paket (package)

package selamatdatang;

Package dalam Java merupakan kumpulan dari berbagai kode yang terangkum dalam satu paket.
Untuk memudahkan penulisan dan pembagian logika suatu program, satu paket terbagi menjadi
beberapa berkas (file) di mana setiap file memiliki fungsi atau tugas yang sangat khusus,
misalnya satu file berfungsi untuk mendeklarasikan konstanta dan kelas, sementara file yang lain
berisi implementasi kelas dan prosedurnya.

Pada contoh aplikasi SelamatDatang di atas, paket ini hanya berisi satu buah file yang isinya
terdiri dari satu kelas dan satu metode.

Definisi paket tidak selalu diperlukan, tetapi hal ini merupakan kebiasaan baik untuk melatih kita
berfikir secara logis dan sistematis.

Komentar
/**
* @param args
*/
// TODO Auto-generated method stub

Komentar tidak akan diproses oleh kompiler tetapi berguna bagi programmer lain. Bahasa Java
memiliki 3 jenis komentar :

 /* text */ — Compiler akan mengabaikan kata kata antara /* dan */

 /** documentation */ — Ini merupakan komentar yang dipergunakan khusus untuk


dokumentasi. Kompiler akan mengabaikan komentar dari /* hingga */. Alat bantu javadoc akan
memproses komentar dokumentasi untuk membuat dokumentasi secara otomatis dari sumber
program.

 // text — Kompiler akan mengabaikan segala sesuatu dari // hingga akhir baris

Definisi Kelas

public class SelamatDatang {


...
}

Kelas merupakan bagian integral dari bahasa Java karena Java merupakan bahasa berorientasi
objek. Setiap aplikasi harus terdiri dari satu kelas. Di sini kita definisikan kelas SelamatDatang
sebagai kelas utama.

Metode main

Dalam bahasa pemrograman Java, setiap aplikasi harus memiliki satu buah metode main yang
bentuknya seperti berikut :

public static void main(String[] args) {


...
}

Metode main mirip dengan fungsi main pada bahasa C/C++ di mana fungsi ini merupakan pintu
gerbang dimulanya suatu program. Metoda main dapat dipanggil dengan menyertakan variabel,
baik hanya satu variabel, banyak variabel atau bahkan tidak ada sama sekali.

Yang terakhir adalah perintah berikut untuk menampilkan Selamat Datang pada komputer Anda.

System.out.println("Selamat Datang!");

Perintah tersebut menggunakan pustaka inti Java, yaitu kelas Sistem.


Variabel dan Tipe Data
Posted Min, 02/08/2009 - 01:10 by belajarprogram

Versi ramah cetak

Nama merupakan hal penting dalam teknik pemrograman. Dalam suatu program, nama
digunakan untuk menyebut sesuatu. Untuk menggunakan "sesuatu" tersebut, programmer harus
mengerti bagaimana aturan pemberian nama dan aturan untuk menggunakan nama tersebut
dalam programnya. Atau dengan kata lain, programmer harus mengerti sintaks dan semantik dari
nama.

Menurut aturan sintaks Java, nama merupakan rangkaian dari 1 atau lebih karakter. Harus
dimulai dengan huruf dan harus terdiri dari huruf, angka atau karakter garis bawah '_'. Berikut ini
adalah contoh nama yang diperbolehkan:

N n rate x15 quite_a_long_name HelloWorld

Hurus kecil dan huruf besar dianggap berbeda, sehingga HelloWorld, helloworld, HELLOWORLD,
dan heLLOwoRLD adalah nama yang berbeda-beda. Beberapa kata tertentu merupakan nama yang
memiliki kegunaan tertentu oleh Java, dan tidak dapat dipergunakan oleh programmer. Kata-kata
ini disebut reserved words (kata-kata cadangan) misalnya: class, public, static, if, else,
while, dan lain-lain.

Hal lain yang penting adalah compound names atau nama campuran, yaitu yang merupakan
nama biasa yang dihubungkan dengan titik, misalnya System.out.println. Idenya adalah
"sesuatu" pada Java dapat terdiri dari "sesuatu" yang lain. Nama System.out.println artinya
System menampung out dan out menampung println. Kita sebut "sesuatu" sebagai identifier
(pengenal) tidak peduli apakah ia berupa nama tunggal atau campuran.

Program melakukan manipulasi data yang disimpan dalam memori. Dalam bahasa mesin, data
hanya bisa diambil dengan menyebut alamatnya di memori. Dalam bahasa pemrograman tingkat
tinggi seperti Java, nama bisa digunakan untk mengganti alamat data tersebut di memori. Tugas
komputer adalah untuk melacak di mana data tersebut di simpan, sedangkan programmer
menggunakan nama untuk memerintahkan komputer mengambil data tersebut dari memori.
Nama yang digunakan seperti ini disebut variable.

Variabel sebenarnya berarti lebih kompleks. Variabel bukan isi dari data, tapi lokasi di memori
yang menyimpan data tersebut. Variabel bisa diibaratkan sebagai kotak penyimpanan data,
bukan isi kotaknya. Karena data di dalam kotak bisa berubah, variabel hanya dapat dipercaya
pada satu saat saja, walaupun tempatnya selalu sama.

Dalam bahasa Java, satu-satunya cara untuk memasukkan data ke dalam variabel adalah dengan
menggunakan assignment statement, atau pernyataan pemberian nilai. Pernyataan ini berbentuk:
variable = ekspresi;

di mana ekspresi menyatakan apapun yang berhubungan dengan nilai suatu data. Ketika
komputer menjalankan instruksi ini, komputer akan menghitung dan menyimpan hasilnya ke
dalam variabel. Contoh:

kecepatan = 40;

Variable dalam pernyataan di atas adalah kecepatan dan ekspresinya adalah angka 40.
Komputer menghitung pernyataan ini dan menyimpan 40 ke dalam variabel kecepatan, dan
mengganti apapun yang telah disimpan sebelumnya.

Sekarang misalnya kita ingin melakukan perhitungan yang lebih kompleks:

jarak = kecepatan * waktu

Di sini, * merupakan operasi perkalian. Komputer mengambil data yang disimpan dalam variabel
kecepatan dan waktu, melakukan perkalian, dan menyimpan hasilnya dalam jarak.

Variabel dalam bahasa Java didesign untuk menyimpan hanya 1 jenis tipe data. Kompiler akan
menampilkan kesalahan sintax apabila variabel ini dicoba untuk diberi tipe data jenis lain. Oleh
karena itu Java disebut bahasa pemrograman bertipe kuat atau strongly typed language.

Ada 8 tipe data primitif dalam bahasa Java.

Jenis
Deskripsi Ukuran Minimum Maksimum
Data

Hanya bisa berisi benar


boolean 1-bit    
atau salah

char Karakter Unicode 16-bit    

byte Bilangan bulat 8-bit -127 128

short Bilangan bulat 16-bit -32768 32767

int Bilangan bulat 32-bit -2147483648 2147483647

long Bilangan bulat 64-bit -9223372036854775808 9223372036854775807

float Bilangan riil 32-bit 1.40129846432481707e-45 3.40282346638528860e+38

4.94065645841246544e-
double Bilangan riil 64-bit 1.79769313486231570e+308
324
Suatu variabel baru dapat digunakan apabila telah dideklarasikan. Pernyataan deklarasi variabel
digunakan untuk mendeklarasikan satu atau lebih variabel dan memberinya nama. Ketika
komputer mengeksekusi deklarasi variabel, komputer akan menyediakan ruangan di memori
kemudian menyimpan alamat ini sesuai dengan nama variabel yang diberikan. Deklarasi variable
berbentuk seperti :

nama_tipe nama_variabel;

nama_variabel dapat berupa sebuah nama variabel atau beberapa nama sekaligus yang dipisah
dengan koma. Gaya pemrograman yang baik yaitu dengan mendeklarasikan satu variabel dalam
satu pernyataan, kecuali variabel tersebut berhubungan erat satu sama lain. Misalnya:

float num;
String nama;
String nama;
boolean bol;
int x,y;

Atau pendeklarasian variabel bisa juga dilakukan sekaligus dengan pemberian nilainya, seperti
pada contoh berikut:

int num = 1000;


char ch = 'e';
float angka = -1.504;
boolean bol = true;

Jenis-jenis Variabel

Java memiliki beberapa jenis variabel yang dapat dikelompokkan sebagai berikut :

 Instance Variables (tidak statis). Dalam bahasa pemrograman berorientasi objek, objek
menyimpan variabel yang tidak dideklarasikan dengan kata kunci static dalam kategori non-
statis, atau dapat berubah-ubah. Suatu kelas dapat dijelmakan ke dalam beberapa objek. Nilai
yang terkandung dalam variabel tak-statis ini berbeda untuk setiap objeknya.
 Class Variables (statis). Variabel ini merupakan bagian integral dari suatu kelas, dan tidak ada
satu objek pun yang dapat menyatakan kepemilikan atas variabel ini. Variabel yang
dideklarasikan sebagai statis digunakan bersama oleh semua objek. Variabel ini lebih bersifat
global yang nilainya sama untuk setiap objek pada kelas yang bersangkutan.
 Local Variables. Variabel ini didefinisikan di dalam suatu metoda (method) atau dalam suatu
prosedur. Variabel ini bersifat lokal karena hanya dapat diakses oleh metoda atau prosedur
tersebut.
 Parameter. Paramater atau argumen adalah variabel yang digunakan pada saat suatu metoda
atau prosedur dipanggil. Parameter berguna untuk memberikan nilai awal untuk diteruskan
(pass) ke dalam suatu prosedur atau metoda.

 
 

Literal

Pada bagian ini akan dijelaskan tentang literal, yaitu rangkaian kata atau huruf yang menyatakan
suatu nilai. Misalnya

int angka = 10;

Pada pernyataan di atas, yang dinamakan literal adalah 10, karena 10 berarti bilangan bulat atau
integer. Pada bahasa pemrograman java, terdapat beberapa jenis literal yang melambangkan
bilangan bulat, riil, kalimat, atau boolean.

Literal Bilangan Bulat

Bilangan bulat dapat dilambangkan dalam beberapa bentuk. Bilangan bulat biasa dilambangkan
dengan deretan angka yang dimulai dengan angka yang bukan nol.

int angka = -10;

Bilangan oktal adalah bilangan bulat berbasis 8, yang berarti hanya dapat terdiri dari angka-
angka 0 hingga 7. Bilangan oktal ditulis seperti bilangan bulat biasa dimulai dengan 0.

// 22 basis delapan atau 18 dalam desimal


int angka = 022;

Bilangan heksadesimal adalah bilangan berbasis 16. Bilangan heksadesimal dilambangkan


dengan 0 hingga 9 dan a hingga f dan dimulai dengan 0x.

// 2a heksadesimal atau 42 dalam desimal


int angka = 0x2a;

Long integer. Seperti dijelaskan pada bab terdahulu long integer membutuhkan memori sebesar
64bit, yang artinya kita dapat menyimpan bilangan bulat hingga 2 ^ 64. Untuk merepresentasikan
long integer, tambahkan huruf L pada akhir bilangan.

int angka = 22L;

Literal Karakter

Kita dapat melambangkan suatu karakter dengan tanda petik tunggal misalnya ‘a’ atau ‘3′ atau
‘=’. Suatu karakter dapat juga dilambangkan dengan kode ASCII nya. Caranya dengan
memulainya dengan \u00 (garis miring terbalik) kemudian diikuti dengan kode ASCII nya dalam
bentuk heksadesimal.

// huruf 'A' dalam ASCII


char huruf = '\u0041';
Selain itu ada beberapa karakter lain selain alfabet yang dapat dilambangkan dengan escape
sequence. Berikut ini beberapa contohnya.

\n = tombol enter atau baris baru.

\r = carriage return.

\t = tombol tab.

\b = tombol backspace.

\\ = karakter \

\’ = karakter ‘

\” = karakter ”

Literal Boolean

Nilai true dan false pada java merupakan literal boolean. Suatu variabel bertipe boolean hanya
dapat memiliki nilai true atau false.

boolean ok = true;

Ingat bahwa boolean true atau false TIDAK menggunakan tanda petik tunggal seperti ekspresi
pada karakter.

Literal Bilangan Riil

Bilangan riil, misalnya -0.00127 atau 415.842, pada java dapat disimpan baik sebagai float atau
double. Bilangan real dapat direpresentasikan dalam bentuk desimal biasa, pecahan, atau
eksponen (dilambangkan dengan e atau E).

Ukuran
Tipe Rentang Presisi (jumlah digit)
bytes bit

float 4 32 +/- 3.4 x 1038 6-7

double 8 64 +/- 1.8 x 10308 15

Imbuhan akhir d atau D dan f atau F dapat pula ditambahkan untuk menentukan tipenya secara
eksplisit. Berikut beberapa contohnya.

double d = 3.27E+32;
float f = 4f;
float pi = 3.14159;

Literal String

String merupakan untaian huruf dan angka yang tersusun menjadi satu kalimat. Dalam bahasa
java, string bukan merupakan tipe primitif, tetapi merupakan kelas. String pada java tidak
disimpan dalam bentuk array seperti pada C. Java menyediakan beberapa metoda untuk
melakukan penggabungan, modifikasi, atau perbandingan. String ditulis di antara dua tanda petik
ganda seperti contoh berikut.

String salam = "Selamat Datang";

String juga dapat mengandung karakter spesial seperti dibahas pada literal karakter. Misalnya

String hallo = "Selamat Datang \"Bapak Presiden\"";


System.out.println("Hallo Bambang\nSelamat pagi,\nSemoga hari anda cerah\n";

Berikut ini adalah beberapa contoh lainnya.

// Contoh string kosong


String teks = "";
 
// Contoh string berisi "
teks = "\"";
 
// String dapat juga dipisah menjadi beberapa baris
teks = "ini baris pertama " +
"dan ini lanjutannya."

Literal Null

Literal terakhir pada bahasa java adalah literal null. Null merupakan kondisi di mana suatu objek
tidak diberi alokasi memori. Pada saat suatu objek dideklarasikan, komputer akan
mengalokasikan memori untuk objek tersebut. Apabila objek tersebut telah selesai dipergunakan,
kita dapat melepas lokasi memori yang digunakan oleh objek tersebut sehingga memori itu dapat
digunakan oleh objek lain. Berikut ini adalah contohnya

obj = null;

Literal null berfungsi memberi tahu garbage collector (pemulung memori) bahwa objek tersebut
tidak lagi terpakai. Kemudian memori akan dilepaskan agar dapat digunakan oleh objek lain.

Contoh Program Variabel dan Tipe Data

Berikut ini adalah listing program penghitungan bunga bank. Kode program dapat anda unduh
dalam bentuk zip file atau melalui SVN di alamat berikut :
http://belajarjava.googlecode.com/svn/trunk/BungaBank
Lihat cara mengimpor contoh-contoh program ke dalam Eclipse di Bab II - Instalasi.

package bungabank;
 
public class BungaBank {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
 
/* Deklarasi variable */
double pokok; // nilai investasi
double sukubunga; // suku bunga bank
double bunga; // nilai bunga
 
/* Perhitungan */
pokok = 20000;
sukubunga = 0.10; // sama dengan 10%
bunga = pokok * sukubunga;
 
pokok = pokok + bunga;
 
/* Cetak hasil keluaran */
System.out.print("Bunga yang dihasilkan adalah Rp. ");
System.out.println(bunga);
System.out.print("Nilai investasi setelah 1 tahun adalah Rp.
");
System.out.println(pokok);
 
}
}

Berikut adalah hasil keluarannya :

String, Objek dan Subrutin


Posted Min, 02/08/2009 - 05:29 by belajarprogram

Versi ramah cetak


Bagian sebelumnya memperkenalkan 8 jenis tipe data primitif dan tipe data String. Perbedaan
mendasar antara tipe primitif dan String adalah : nilai dari tipe String berupa objek. Objek
akan dibahas pada bagian lain mengenai kelas (class). Di bagian ini kita akan belajar bagaimana
String digunakan dan juga mempelajari konsep pemrograman penting yang lain, yaitu subrutin.

Subrutin adalah kumpulan instruksi program yang digabungkan sehingga memiliki fungsi
tertentu. Dalam bahasa Java, setiap subrutin termasuk di dalam bagian suatu kelas atau objek.
Java menyediakan kelas standar yang siap digunakan. Nilai tipe String adalah objek yang
memiliki kumpulan subrutin yang dapat digunakan untuk memanipulasi String tersetbut. Kita
bisa memanggil subrutin tersebut tanpa harus mengerti bagaimana subrutin tersebut bekerja.
Sebenarnya ini adalah tujuan subrutin, yaitu sekumpulan perintah yang memiliki fungsi tertentu
tanpa harus mengetahui secara detail apa yang terjadi di dalam.

Kelas terdiri dari variabel dan subrutin yang disimpan di dalamnya. Variabel dan subrutin ini
disebut static member (anggota statis). Contohnya adalah pada program SelamatDatang, kelas
SelamatDatang memiliki anggota main() yang merupakan anggota statis kelas itu. Anggota
yang berupa static member diberi imbuhan static, seperti pada main().

Fungsi kelas yang lain adalah untuk mendeskripsikan suatu objek. Kelas di sini berfungsi seperti
tipe data. Nilai yang disimpan dalam tipe data itu adalah objek. Misalnya String sebenarnya
merupakan nama kelas yang disediakan bahasa Java. String juga berupa tipe data dan kalimat
seperti "Selamat Datang!" adalah isi dari tipe data String.

Kegunaan kelas baik sebagai gabungan subrutin ataupun sebagai objek sering membingungkan.
Misalnya kelas String juga menyimpan beberapa subrutin statik selain juga sebagai tipe data.
Contoh kelas standar lainnya adalah Math yang berisi kumpulan subrutin statik untuk melakukan
berbagai perhitungan matematis.

Kelas sebagai tipe data


Posted Rab, 02/11/2009 - 02:09 by belajarprogram

Versi ramah cetak

Kelas sebagai tipe data

Mari mulai dengan melihat kembali subrutin System.out.print. Subrutin ini digunakan untuk
menampilkan pesan kepada user. Misalnya System.out.print("Selamat datang!")
menampilkan pesan Selamat datang!

System merupakan salah satu kelas standar Java. Salah satu anggotanya bernama out. Karena
variable ini berada di dalam kelas System, kita harus memanggilnya dengan nama lengkapnya
yaitu System.out. Variabel System.out merupakan suatu objek, dan objek itu memiliki
subrutin yang bernama print. Pengenal campuran System.out.print mengacu pada subrutin
print di dalam objek out dalam kelas System.
(Untuk melihat dari sisi lain, sebetulnya System.out merupakan objek dari kelas PrintStream.
PrintStream adalah salah satu kelas standar Java. Objek dengan tipe PrintStream adalah objek
tempat informasi bisa dicetak. Setiap objek yang bertipe PrintStream memiliki subrutin
bernama print yang bertugas untuk mencetak sesuatu ke medium tersebut. Dalam hal ini
System.out adalah tujuan tempat print dilakukan. Objek lain yang bertipe PrintStream bisa
mengirim informasi ke tujuan lain, misalnya file atau network atau ke komputer lain.

Ini adalah esensi dari pemrograman berorientasi objek, di mana beberapa hal yang memiliki
kesamaan - dalam hal PrintStream sama-sama sebagai tempat tujuan print - dapat digunakan
dengan cara yang sama, yaitu memanggil subrutin print.)

Karena nama variabel, nama kelas, dan nama subrutin berbentuk hampir sama, ada baiknya
untuk membedakannya sehingga di kemudian hari program dapat dibaca dengan jelas. Kelas
standar Java menggunakan nama yang selalu dimulai dengan huruf besar, sedangkan nama
variabel dimulai dengan huruf kecil. Ini bukan sintaks Java, tetapi lebih seperti konvensi. Setiap
orang bebas menggunakan konvensinya masing-masing, tetapi apabila pemrograman dilakukan
secara bersama-sama, seperti pada open source programming, konvensi yang sama akan sangat
memudahkan orang lain membaca dan menguji program yang kita buat. Nama subrutin juga
dimulai dengan huruf kecil, sama dengan nama variabel. Tetapi subrutin harus diikuti dengan
tanda buka kurung sehingga masih mudah dibedakan dengan nama variabel.

Kelas sebagai kumpulan subrutin dan variabel statik


Posted Rab, 02/11/2009 - 02:13 by belajarprogram

Versi ramah cetak

Kelas sebagai kumpulan subrutin dan variabel statik

Selain sebagai tipe data, kelas System juga memiliki subrutin statik yang bernama exit.
Memanggil System.exit akan menghentikan jalannya program, dan digunakan apabila karena
suatu hal (misalnya program telah selesai atau adanya error) program harus dihentikan. Subrutin
exit menerima parameter bilangan bulat, misalnya System.exit(0) atau System.exit(1),
untuk memberitahu kepada sistem operasi alasan kenapa program dihentikan. Status 0 berarti
program berhenti normal tanpa adanya error, sedangkan status lain berarti ada sesuatu yang salah
yang terjadi di tengah eksekusi program tersebut.

Setiap subrutin melakukan fungsi tertentu. Beberapa di antaranya melakukan perhitungan lalu
melaporkan hasil perhitungannya. Ada juga yang berfungsi untuk mengambil data dari tempat
tertentu dan melaporkan data yang didapat. Subrutin jenis ini disebut function (fungsi). Fungsi
adalah subrutin yang mengembalikan (return) suatu nilai. Nilai yang dikembalikan akan
digunakan lebih lanjut dalam program.

Sebagai contoh adalah fungsi untuk menghitung akar kuadrat dari suatu bilangan. Java memiliki
fungsi seperti itu yang disebut Math.sqrt. Fungsi ini merupakan anggota statik dari kelas yang
bernama Math. Jika x adalah suatu bilangan, makan Math.sqrt(x) menghitung akar kuadrat dari
x dan mengembalikan hasil perhitungannya. Karena Math.sqrt(x) mengembalikan suatu
bilangan, kita tidak bisa memanggil fungsi ini seperti

Math.sqrt(x); // Tidak masuk akal!

Kita tentunya ingin menggunakan hasilnya untuk instruksi selanjutnya, misalnya menuliskan
hasilnya di layar seperti

System.out.print( Math.sqrt(x) ); // Menampilkan akar kuadrat x di layar.

atau menyimpan hasilnya pada variabel lain, seperti

panjangDiagonal = Math.sqrt(x);

Kelas Math
Posted Rab, 02/11/2009 - 02:18 by belajarprogram

Versi ramah cetak

Kelas Math memiliki banyak fungsi statik. Beberapa yang penting di antaranya:

 Math.abs(x), menghitung nilai mutlak (absolut) dari x. Nilai mutlak bilangan negatif adalah
bilangan positif, dan bilangan positif tetap bilangan positif.
 Fungsi trigonometri Math.sin(x), Math.cos(x), and Math.tan(x). (Untuk semua fungsi
trigonometri, sudut memiliki satuan radian, bukan derajat)
 Fungsi trigonometri inverse, yang mencari sudut dari suatu nilai trigonometric, kebalikan dari
fungsi trigonometri, seperti arcus sin, arcus cos, dan arcus tangen. Math.asin(x),
Math.acos(x), and Math.atan(x).
 Math.exp(x), menghitung pangkat dari bilangan natural e, atau e x. Dan logaritma natural loge
x atau ln x bisa dihitung dengan menggunakan fungsi Math.log(x).
 Math.pow(x,y) menghitung xy atau x pangkat y
 Math.floor(x) menghitung pembulatan ke bawah dari suatu bilangan riil, misalnya 3.84 akan
dibulatkan ke bawah menjadi 3.0
 Math.random() memilih bilangan acak di antara 0.0 dan 1.0. Komputer memiliki algoritma
perhitungan tertentu yang hasilnya bilangan acak (meskipun bulan bilangan yang betul-betul
acak, tetapi cukup untuk kebanyakan fungsi)

Paremeter (nilai di dalam kurung) fungsi-fungsi di atas bisa bertipe numerik apa saja (misalnya
double, int, dll), tetapi keluarannya bertipe double, kecuali abs(x) yang tipe keluarannya sama
dengan tipe parameternya.

Math.random() tidak memiliki parameter, tetapi tanda kurungnya harus tetap ditulis untuk
membedakan fungsi dan variabel. Contoh fungsi lain yang tidak memiliki parameter adalah
System.currentTimeMillis() yang berguna untuk mengambil waktu saat ini dalam satuan
milidetik, dihitung sejak 1 Januri 1970 waktu GMT. Satu milidetik sama dengan 1 per 1000
detik. Keluarannya bertipe long.
Untuk menghitung waktu yang diperlukan untuk menjalankan suatu perintah, jalankan fungsi
System.currentTimeMillis() sebelum dan sesudah suatu instruksi dijalankan. Perbedaannya
adalah waktu yang diperlukan untuk menjalankan suatu instruksi.

Contoh Kelas Math


Posted Rab, 02/11/2009 - 23:56 by belajarprogram

Versi ramah cetak

Berikut ini adalah listing program untuk melakukan beberapa perhitungan matematika,
menampilkan hasilnya di layar, dan melaporkan waktu yang diperlukan untuk melakukan
perhitungan tersebut.

Kode program dapat anda unduh dalam bentuk zip file atau melalui SVN di alamat berikut :
http://belajarjava.googlecode.com/svn/trunk/WaktuKomputasi

Lihat cara mengimpor contoh-contoh program ke dalam Eclipse di Bab II - Instalasi.

package waktukomputasi;
 
public class WaktuKomputasi {
 
/**
* Program ini akan melakukan beberapa perhitungan matematika,
* menampilkan hasilnya di layar, dan melaporkan waktu yang diperlukan
* untuk melakukan perhitungan tersebut
*
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
long waktuMulai;
long waktuSelesai;
 
waktuMulai = System.currentTimeMillis();
 
double panjang, lebar, sisiMiring; // sisi segitiga siku-
siku
panjang = 18.0;
lebar = 27;
 
sisiMiring = Math.sqrt(panjang*panjang + lebar*lebar);
System.out.print("Segitiga siku-siku dengan panjang 18 dan
lebar 27 memiliki sisi miring ");
System.out.println(sisiMiring);
 
System.out.println("\nSecara matematis, sin(x)*sin(x) + "
+ "cos(x)*cos(x) - 1 = 0");
System.out.println("Mari kita cek untuk x = 1 :");
System.out.print("sin(1)*sin(1) + cos(1)*cos(1) - 1 = ");
System.out.println( Math.sin(1)*Math.sin(1)
+ Math.cos(1)*Math.cos(1) - 1 );
System.out.println("(Mungkin akan ada kesalahan desimal dalam
"
+ "perhitungan bilangan real!)");
 
System.out.print("\nIni adalah bilangan acak : ");
System.out.println(Math.random());
 
waktuSelesai = System.currentTimeMillis();
System.out.print("\nTotal waktu perhitungan : ");
System.out.print((waktuSelesai - waktuMulai)/1000.0);
System.out.println(" detik");
 
}
}

Berikut adalah hasil keluarannya :

Kelas String
Posted Kam, 02/12/2009 - 23:44 by belajarprogram
Versi ramah cetak

Nilai suatu String adalah objek. Objek ini berisi rangkaian huruf yang membentuk string. Objek
tersebut juga berisi subrutin. Misalnya length adalah fungsi yang menghitung panjang suatu
string, atau jumlah karakter dalam suatu string. Misalnya string str yang dideklarasikan sebagai
berikut :

String str;
str = "Hari ini cerah sekali!"

Untuk menghitung jumlah karakter dalam string str, panggil fungsi str.length() yang
keluarannya bertipe int. Fungsi ini tidak membutuhkan parameter. Fungsi length merupakan
anggota kelas String dan dapat digunakan oleh semua data yang bertipe String. Dan juga bisa
digunakan oleh literal string, misalnya program berikut menghitung jumlah karakter dalam string
"Indonesia Raya" :

System.out.print("Jumlah karakter dalam \"Indonesia Raya\" adalah ");


System.out.print("Indonesia Raya".length());
System.out.println(" karakter");

Kelas String memiliki beberapa fungsi di antaranya :

 s1.equals(s2) adalah fungsi yang mengembalikan nilai boolean ( true atau false). Fungsi
ini akan menghasilkan true jika s2 sama dengan s1, dan salah jika tidak. Kesamaan yang diuji
adalah kesamaan persis baik kapitalnya maupun urutan huruf-hurufnya.
 s1.equalsIgnoreCase(s2) juga menghasilkan nilai boolean yang menguji apakah string s2
sama dengan s1 dengan tidak membandingkan kapitalnya. "Kucing".equalsIgnoreCase("kucing")
menghasilkan true.
 s1.length(). Seperti diulas sebelumnya, fungsi ini menghitung jumlah karakter dalam string
s1.
 s1.charAt(N). N adalah integer (bilangan bulat). Fungsi ini mengembalikan karakter ke-N dari
string s1. Karakter pertama dihitung sebagai posisi ke-0. s1.charAt(0) berarti mengambil
karakter pertama, sedangkan s1.charAt(1) berarti mengambil karakter ke-2, dan seterusnya.
Karakter terakhir memiliki indeks s1.length() - 1. Fungsi ini akan mengeluarkan pesan
kesalahan apabila N bernilai negatif atau lebih besar dari s1.length() - 1.
 s1.substring(N,M), di mana N dan M bilangan bulat. Fungsi ini mengambil potongan string
antara karakter ke-N hingga karakter M-1. Catatan bahwa karakter ke-M tidak ikut diambil.
Misalnya, "jalan layang".substring(1,4) menghasilkan "ala".
 s1.indexOf(s2) mengembalikan nilai integer. Fungsi ini mencari string s2 di dalam string s1,
dan apabila ditemukan mengembalikan posisi awal s2 di dalam s1. Jika tidak ditemukan, fungsi
ini akan mengembalikan -1. Fungsi ini bisa juga digunakan untuk mencari string s2 dalam s1
setelah posisi ke-N dalam string s1. Misalnya, "kelapa muda".indexOf("a") menghasilkan
3, sedangkan "kelapa muda".indexOf("a",6) menghasilkan 10.
 s1.compareTo(s2) membandingkan s2 dan s1. Jika s1 dan s2 sama, hasilnya 0. Jika s1 kurang
dari s2, hasilnya bilangan negatif , dan jika s1 lebih besar dari s2, hasilnya bilangan positif.
"Kurang dari" atau "lebih dari" mengacu pada urutannya dalam abjad jika keduanya huruf kecil
atau keduanya huruf besar. Jika kapitalnya berbeda, perbandingannya bergantung pada nilai
ASCII-nya.
 s1.toUpperCase() adalah fungsi untuk mengubah seluruh huruf dalam s1 menjadi huruf
besar.
 s1.toLowerCase() berfungsi untuk mengubah huruf dalam s1 menjadi hurug kecil.
 s1.trim() adalah berfungsi menghapus karakter yang tak bisa dicetak, misalnya spasi, baris
baru, enter, yang ada sebelum atau sesudah suatu kalimat. Misalnya "  selamat pagi bu 
".trim() menghasilkan "selamat pagi bu".

Untuk s1.toUpperCase(), s1.toLowerCase(), s1.trim() nilai s1 tidak berubah. Fungsi ini


melakukan perhitungan kemudian mengembalikan string baru hasil perhitungan tersebut.

Kita bisa juga menggunakan tanda + menyambung 2 string. Misalnya "mata" + "hari" menjadi
"matahari". Nilai yang dapat disambungkan bukan hanya string dan string, tetapi juga string dan
angka, misalnya "jalan" + 2 menjadi "jalan2".

Contoh Kelas String


Posted Jum, 02/13/2009 - 01:06 by belajarprogram

Versi ramah cetak

Berikut ini adalah listing program untuk melakukan beberapa contoh menggunakan kelas
String, menampilkan hasilnya di layar, dan melaporkan waktu yang diperlukan untuk
melakukan perhitungan tersebut.

Kode program dapat anda unduh dalam bentuk zip file atau melalui SVN di alamat berikut :
http://belajarjava.googlecode.com/svn/trunk/ContohString

Lihat cara mengimpor contoh-contoh program ke dalam Eclipse di Bab II - Instalasi.

package contohstring;
 
public class ContohString {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
 
// demo String.length() dan operator + untuk menghubungkan
karakter
String str;
str = "Hari ini cerah sekali!";
System.out.println("Panjang string \"" + str + "\" adalah " +
str.length());
 
System.out.print("Jumlah karakter dalam \"Indonesia Raya\"
adalah ");
System.out.print("Indonesia Raya".length());
System.out.println(" karakter");
 
// demo equals dan compareTo
System.out.println("\"jambu\" = \"Jambu\"? " +
"jambu".equals("Jambu"));
System.out.println("ignore case \"jambu\" = \"Jambu\"? " +
"jambu".equalsIgnoreCase("Jambu"));
}
}

Berikut adalah hasil keluarannya :

Operator Aritmatika
Posted Rab, 02/11/2009 - 02:29 by belajarprogram

Versi ramah cetak

+ Operator penjumlahan (juga sebagai penyambung string)


- Operator pengurangan

* Operator perkalian

/ Operator pembagian

% Operator sisa pembagian

Operator aritmatika digunakan untuk melakukan operasi matematika, seperti penambahan,


pengurangan, pembagian, dan modulo (atau sisa pembagian). Contoh penggunaan :

Simbol Nama operator Contoh penggunaan

+ Operator penjumlahan n = n + 1;

- Operator pengurangan n = n - 1;

* Operator perkalian n = n * 1;

/ Operator pembagian n = n / 1;

% Operator sisa pembagian n = n % 1;

+ Operator penyambung string n = "saya "+"tidur";

Contoh kode program yang dapat Anda unduh dalam bentuk zip file atau melalui SVN di alamat
berikut : http://belajarjava.googlecode.com/svn/trunk/OperatorAritmatika

Lihat cara mengimpor contoh-contoh program ke dalam Eclipse di Bab II - Instalasi.

package operatoraritmatika;
 
public class OperatorAritmatika {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
 
int x = 2;
int y = 5;
int z = 3;
int g = 0;
 
g = x + y;
System.out.println("Penjumlahan (x+y) : " + g);
 
g = y - x;
System.out.println("Pengurangan (y-x) : " + g);
 
g = x * y;
System.out.println("Perkalian (x*y) : " + g);
 
g = y / x;
System.out.println("Pembagian (y/x) : " + g);
 
g = z % y;
System.out.println("Sisa pembagian (z%x) : " + g);
 
g = x + (y * (z/x));
System.out.println("Hasilnya sekarang : " + g);
}
}

Keluaran Program :

Operator Tunggal
Posted Rab, 02/11/2009 - 02:33 by belajarprogram
Versi ramah cetak

+ Operator plus; menyatakan nilai positif (setiap angka tanpa tanda ini akan dianggap sebagai
positif)

- Operator minus; menyatakan nilai negatif, dapat pula digunakan untuk menegatifkan suatu
bilangan

++ Operator kenaikan; menambah suatu bilangan dengan 1

-- Operator penurunan; mengurangkan suatu bilangan dengan 1

! Operator lawan; membalik nilai suatu boolean

Operator tunggal hanya membutuhkan satu operan untuk melakukan operasinya. Operator ini
tidak dapat digunakan untuk variabel final, karena variabel final berupa konstanta yang tidak
dapat diubah-ubah. Beberapa jenis operator tunggal diberikan pada tabel di bawah ini.

Simbol Nama operator Operasi Contoh

+ Operator plus menyatakan nilai positif angka = +1;

angka = -1;
menyatakan nilai negatif, dapat pula
- Operator minus angka = -angka; //
digunakan untuk menegatifkan suatu bilangan sekarang angka bernilai
1
Operator
++ menambah suatu bilangan dengan 1 angka = ++angka;
kenaikan

Operator
-- mengurangkan suatu bilangan dengan 1 angka = --angka;
penurunan

! Operator lawan membalik nilai suatu boolean ok = !true;

Operator kenaikan dan penurunan dapat diletakkan di belakang atau di depan suatu variabel. Jika
diletakkan di depan (++x atau --x), penambahan/pengurangan dilakukan sebelumnya, sedangkan
apabila diletakkan di akhir (x++ atau x--) penambahan/pengurangan dilakukan setelahnya.
Walau bagaimanapun pada akhirnya keduanya akan menghasilkan x = x+1 atau x = x-1.

Mari kita lihat contohnya untuk membedakan lebih jelas perbedaan penempatan operator tunggal
++ dan --

Contoh kode program yang dapat Anda unduh dalam bentuk zip file atau melalui SVN di alamat
berikut : http://belajarjava.googlecode.com/svn/trunk/OperatorTunggal

Lihat cara mengimpor contoh-contoh program ke dalam Eclipse di Bab II - Instalasi.


package operatortunggal;
 
public class OperatorTunggal {
 
/**
* Contoh program menggunakan operator tunggal
*
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
 
int x = 0;
int y = 0;
y = ++x;
System.out.println("Contoh operator pada prefix (awalan)");
System.out.println("---------------------------");
System.out.println("Nilai x baru : " + x);
System.out.println("Nilai y = ++x : " + y);
 
x = 0;
y = 0;
y = x++;
System.out.println("\nContoh operator pada sufix (akhiran)");
System.out.println("---------------------------");
System.out.println("Nilai x baru :" + x);
System.out.println("Nilai y = x++ :" + y);
}
}

Jalankan program tersebut dan lihat hasilnya. Apabila operator ++ diletakkan di awal (prefix),
maka nilai "x" dan "y" akan sama, karena penambahan nilai "x" dilakukan terlebih dahulu, lalu
hasilnya diberi kepada "y".

Apabila operator ++ diletakkan di akhir (sufix), nilai "y" adalah nilai "x" terdahulu. Java akan
memberi nilai "y" dengan nilai "x" sebelum operasi ++ dilakukan. Baru kemudian nilai "x"
ditambahkan.

Berikut ini adalah screenshot keluarannya :


Operator Pembanding, Boolean dan Kondisi
Posted Rab, 02/11/2009 - 02:36 by belajarprogram

Versi ramah cetak

Operator kondisi (conditional operator) menghasilkan nilai true atau false tergantung dari
variabelnya, dalam hal ini operasinya dilakukan pada dua operand. Operator boolean adalah
operator kondisi yang kedua operandnya berupa nilai boolean (true atau false), sedangkan
Operator Pembanding membandingkan 2 nilai seperti pada operasi matematika.

Catatan : Pada objek, seperti String, operasi pembanding akan membandingkan alamat memory
tempat objek itu disimpan, bukan membandingkan isinya. Untuk membandingkan isi String,
gunakan equals(), equalsIgnoreCase(), dan compareTo() seperti dibahas pada bagian
sebelumnya.

Simbol Nama operator Contoh

== Sama dengan b = (1 == 2);


!= Tidak sama dengan b = (1 == 2);

> Lebih besar b = (1 > 2);

>= Lebih besar atau sama dengan b = (1 >= 2);

< Lebih kecil b = (1 < 2);

<= Lebih kecil atau sama dengan b = (1 <= 2);

&& Conditional AND b = true && false;

|| Conditional OR b = true || false;

! NOT b = !true;

?: Bentuk pendek dari if-then-else

Operator boolean AND

Operator kondisi AND menghasilkan "true" apabila kedua operandnya bernilai "true". Jika salah
satunya atau keduanya "false", operator ini menghasilkan "false". Berikut ini tabel kebenaran
operasi AND.

Op1 atau Exp1 Op2 atau Exp2 Hasil

true true true

true false false

false true false

false false false

Operator && akan mengevaluasi Op2 (di sebelah kanan) HANYA jika operand 1 bernilai "true".
Seperti terlihat dari tabel di atas, apabila Op1 (di sebelah kiri) bernilai "false", hasilnya akan
selalu "false" tidak tergantung pada isi dari Op2.

Operator kondisi OR

Operator kondisi OR menghasilkan "true" jika salah satu operandnya bernilai "true". Jika
keduanya "false", operator ini menghasilkan "false". Berikut ini table kebenaran oeprasi OR.
Op1 atau Exp1 Op2 atau Exp2 Hasil

true true true

true false true

false true true

false false false

Operator || akan mengevaluasi Op2 (di sebelah kanan) HANYA jika operand 1 bernilai "false".
Seperti terlihat dari tabel di atas, apabila Op1 (di sebelah kiri) bernilai "true", hasilnya akan
selalu "true" tidak tergantung pada isi dari Op2.

Operator NOT

Operator NOT ("!") melakukan operasi boolean NOT pada operand atau ekspresi tunggal.
Operator ini mengecek nilai boolean dari suatu operand atau expresi kemudian membalik
nilainya (dari true ke false atau false ke true). Berikut ini adalah tabel kebenaran operator NOT.

Op1 Hasil

true false

false true

Operator Ternary (?:) Java memiliki operator berkondisi lain yang disebut ternary "?:", yang
pada dasarnya merupakan bentuk pendek dari if-then-else. Secara umum

kondisi ? jika_benar : jika_salah

Pada dasarnya operator "?:" akan mengevaluasi "kondisi". Apabila kondisi bernilai "true",
operator akan mengembalikan "jika_benar", tetapi apabila "kondisi" bernilai "false", operator
akan mengembalika "jika_salah". Misalnya

x = (1 > 2) ? 10 : 20

Dari contoh di atas, "x" akan memiliki nilai 20, karena ekspresi (1 > 2) adalah salah (atau
"false").

Contoh kode program yang dapat Anda unduh dalam bentuk zip file atau melalui SVN di alamat
berikut : http://belajarjava.googlecode.com/svn/trunk/OperatorKondisi

package operatorkondisi;
 
public class OperatorKondisi {
 
/**
* Contoh program menggunakan operator kondisi
*
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
 
int x = 5;
int y = 10, angka = 0;
boolean bl = true;
if((x == 5) && (x < y))
System.out.println("Nilai x adalah " + x);
 
if((x == y) || (y > 1))
System.out.println("Nilai y lebih besar dari x");
angka = bl ? x : y;
 
System.out.println("Angka yang keluar adalah " + angka);
}
}

Berikut adalah hasil keluarannya :


Operator Pemberi Nilai & Type Casting
Posted Rab, 02/11/2009 - 02:27 by belajarprogram

Versi ramah cetak

Operator merupakan simbol untuk melakukan perhitungan atau suatu operasi pada satu atau lebih
dari satu hal. Setelah kita mendeklarasi dan mengisi suatu variabel, kita dapat menggunakan
operator untuk melakukan beberapa hal seperti penambahan, pengurangan dan sebagainya.

Operator Pemberi Nilai

= Operator pemberi nilai Operator penugasan dan pemberian nilai merupakan operator yang
paling umum dalam semua bahasa pemrograman. Operator ini dilambangkan dengan "=" yang
digunakan untuk memberikan nilai kepada suatu variabel di sebelah kiri operator. Jika variabel
tersebut telah memiliki nilai, nilainya akan diganti dengan variabel atau angka di sebelah kanan
operator.

Operator ini juga dapat digunakan untuk memberikan referensi kepada suatu objek.
Beberapa contoh :

String nama = "Budi";


boolean dewasa = true;
 
// buat objek baru
Shape s1 = new Shape();
 
// beri referensi s1 kepada s2
Shape s2 = s1;
 
// nilai sebelumnya diganti
dewasa = false;

Anda dapat juga memberikan nilai kepada beberapa variabel secara bersamaan. Misalnya :

x = y = z = 2;
x = (y + z);

Operator "=" dievaluasi dari kanan ke kiri. Pada ekspresi pertama, angka 2 diberikan kepada "z",
kemudian nilai yang disimpan "z" diberikan kepada "y", dan kemudian "y" ke "x" secara
bersamaan. Pada ekspresi kedua, nilai hasil evaluasi pertambahan dimasukkan ke variabel "x".

Pada dasarnya, kedua sisi tanda "=" harus memiliki tipe yang sama. Misalnya x = A, x dan A
harus memiliki tipe yang sama. Bagaimana jika tidak, misalnya

int A;
short B;
A = 17;
B = (short)A;

Pada kode di atas, B akan mengambil nilai A yang sudah dikonversi ke tipe short. Tanda (short)
dalam kurung artinya menginstruksikan Java untuk mengubah nilai A menjadi short sebelum
diberikan kepada B.

Perubahan tipe ini disebut type casting. Kita bisa mengubah tipe apa saja, tetapi karena rentang
tiap tipe berbeda, maka nilainya belum tentu sama dengan nilai aslinya. Misalnya
(short)100000 adalah -31072.

Untuk perubahan tipe dari bilangan real (float atau double) ke bilangan bulat, Java melakukan
type casting dengan memangkas desimalnya. Jadi 3.56 akan diubah menjadi 3 dalam bilangan
bulat.

Nilai char juga bisa diubah ke dalam bilangan bulat, yaitu dengan menggantinya dengan
bilangan Unicode-nya.

Selain operasi "=", Java juga memiliki operator pemberian nilai beruntun, dan dapat digunakan
oleh semua operator aritmatika, manipulasi bit, atau pergeseran bit. Misalnya pada ekspresi
berikut, nilai "x" akan dijumlahkan dengan 2, kemudian hasilnya disimpan kembali ke "x".
x += 2;

Table berikut menunjukkan semua operator pemberian nilai yang dapat Anda gunakan sehingga
kode Anda menjadi lebih efisien dan mudah dibaca.

Operator Contoh Ekspresi setara

+= x += y; x = (x + y);

-= x -= y; x = (x - y);

*= x *= y; x = (x * y);

/= x /= y; x = (x / y);

%= x %= y; x = (x % y);

&= x &= y; x = (x & y);

|= x |= y; x = (x | y);

^= x ^= y; x = (x ^ y);

< <= x < <= y; x = (x < < y);

>>= x >>= y; x = (x >> y);

>>>= x >>>= y; x = (x >>> y);

Contoh kode program yang dapat Anda unduh dalam bentuk zip file atau melalui SVN di alamat
berikut : http://belajarjava.googlecode.com/svn/trunk/OperatorPemberiNilai

package operatorpemberinilai;
 
public class OperatorPemberiNilai {
 
/**
* Contoh program menggunakan operator pemberi nilai (assignment
operator)
*
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int x = 5;
int y = 10;
 
x += y;
System.out.println("Hasil penjumlahan : " + x);
 
x -= y;
System.out.println("Hasil pengurangan : " + x);
 
x *= y;
System.out.println("Hasil perkalian : " + x);
 
x /= y;
System.out.println("Hasil pembagian : " + x);
 
x %= y;
System.out.println("Sisa pembagian : " + x);
 
x &= y;
System.out.println("Hasil operasi AND : " + x);
 
x |= y;
System.out.println("Hasil operasi OR : " + x);
 
x <<= y;
System.out.println("Hasil operasi pergeseran bit ke kiri :"+
x);
}
}

Keluaran programnya :
Intermezzo : Membaca Input dari User
Posted Min, 02/15/2009 - 02:44 by belajarprogram

Versi ramah cetak

Java bukan bahasa pemrograman untuk Console (seperti DOS atau Linux), sehingga untuk
mengambil input dari user diperlukan sedikit trik yang tidak sesederhana readln pada bahasa
pemrograman lain.

Di sini saya akan menjelaskan untuk membuat program yang bisa mengambil input dari konsol
teks. Di bagian lain, setelah kita belajar pemrograman berorientasi objek, kita akan
menggunakan GUI untuk mendapatkan interaksi dari user.

Membaca String yang diketik oleh user di konsol

Kita membutuhkan kelas yang beberapa kelas, yaitu BufferedReader, InputStreamReader,


dan System.in (lawan dari System.out yang kita gunakan untuk menampilkan pesan di layar).
Dua kelas pertama terdapat dalam package yang dinamakan java.io. Untuk itu, kita harus
menambah satu baris perintah

import java.io.*

yang berarti mengimport semua kelas dalam paket java.io (tanda * berarti semua).

Kemudian kita harus juga membuat suatu objek dari kelas BufferedReader. Kelas
BufferedReader adalah kelas abstrak yang menangani baca tulis ke suatu media.

Kelas ini membutuhkan kelas lain sebagai pekerjanya, yaitu InputStreamReader. Dan
InputStreamReader membutuhkan media tempat baca tulis dilakukan, yaitu System.in.

Semua ini bisa dituliskan dalam satu perintah yaitu :

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

Di sini variabel br merupakan objek yang merupakan jelmaan dari kelas BufferedReader.

Untuk memerintahkan Java mengambil input dari user, kita gunakan fungsi readline() yang
terdapat pada kelas BufferedReader, dalam hal ini terealisasi pada objek br.

nama = br.readLine();

Karena kita berhubungan langsung dengan sistem IO (input-output) komputer yang harus
diasumsikan tidak pasti (misalnya ada masalah pada sistem keyboard, atau komputer sedang
bekerja berat sehingga input dari user tidak bisa diambil), kita harus menempatkan fungsi
readLine() pada klausa

try {
...
} catch (IOException ioe) {
...
}

Perintah di dalam try { ... } adalah perintah yang kita ingin jalankan pada situasi yang
"mungkin" tidak berhasil.

Parameter pada catch, yaitu IOException ioe adalah jenis kesalahan yang ingin kita tangkap.
Dalam hal ini kita ingin menangkap adanya kesalahan IO, yaitu kesalahan yang bertipe
IOException.

Perintah di dalam catch { ... } adalah perintah yang akan dilakukan apabila kesalahan
ditangkap. Jika tidak ada kesalahan IO yang ditemukan, maka bagian ini akan dilewatkan (tidak
dijalankan).

Mari kita lihat program akhir untuk mengambil input dari user.
package ambilinputkonsol;
 
import java.io.*;
 
public class AmbilInputKonsol {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
 
System.out.print("Masukkan nama Anda : ");
 
// buat objek baru untuk mengambil input
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
 
// tempat di mana input dari user akan diletakkan
String nama = null;
 
try {
nama = br.readLine();
} catch(IOException ioe) {
System.out.println("Kesalahan IO pada saat menanyakan
nama Anda");
System.exit(1);
}
 
System.out.println("Terima kasih, " + nama);
}
}

Program tersebut dapat Anda unduh dalam bentuk zip file atau melalui SVN di
http://belajarjava.googlecode.com/svn/trunk/AmbilInputKonsol

Untuk menguji program tersebut, jalankan "Run -> Run" atau Ctrl-F11. Kemudian arahkan
kursor Anda ke bagian bawah di kotak yang bernama Console.
Masukkan nama Anda, kemudian hasilnya akan ditampilkan pada baris berikutnya.

Intermezzo : Mengubah String ke int dan double


Posted Min, 02/15/2009 - 17:32 by belajarprogram

Versi ramah cetak

Kita dapat mengubah tipe data String, misalnya hasil input dari konsol atau dari hasil bacaan file,
ke tipe data bilangan untuk pengolahan lebih lanjut.
Sebagai contoh, kita akan membuat program untuk menghitung nilai investasi setelah n tahun.
Input yang diminta dari user adalah :

 Nama
 Investasi awal (Rp)
 Bunga (%)
 Periode (tahun)

Dengan menggunakan teknik yang sama pada contoh sebelumnya, kita bisa mengambil input
tersebut menggunakan kelas BufferedReader seperti berikut.

nama = br.readLine();
strawal = br.readLine();
strbunga = br.readLine();
strperiode = br.readLine();

Tetapi karena keluaran dari readLine() bertipe String, kita harus mengubahnya menjadi bentuk
bilangan agar dapat diproses lebih lanjut.

Untuk mengubah String menjadi int, kita dapat menggunakan kelas Java Integer yang di
dalamnya memiliki fungsi parseInt(str). Fungsi ini dapat dipanggil dengan:

periode = Integer.parseInt(strperiode);

Sedangkan untuk mengubah String menjadi double, kita menggunakan kelas Java Double yang
di dalamnya memiliki fungsi parseDouble(str). Fungsi ini dapat dipanggil dengan:

awal = Double.parseDouble(strawal);
bunga = Double.parseDouble(strbunga);

Setelah semua variabel didapat dan diubah, kita baru bisa untuk memulai perhitungan. Untuk
menghitung bunga bank setelah n tahun, kita bisa menggunakan rumus berikut :

akhir = awal * (1 + bunga)periode

Dalam Java, rumus tersebut bisa dituliskan dengan ekspresi berikut

akhir = awal * Math.pow(1 + bunga,periode);

Berikut ini adalah listing program lengkap yang dapat diunduh dalam bentuk zip file atau melalui
SVN di alamat http://belajarjava.googlecode.com/svn/trunk/HitungInvestasiNPeriode

package hitunginvestasinperiode;
 
import java.io.*;
 
public class HitungInvestasiNPeriode {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
 
// buat objek baru untuk mengambil input
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
 
// tempat di mana input dari user akan diletakkan
String nama = null;
String strawal = null;
String strbunga = null;
String strperiode = null;
 
try {
System.out.print("Masukkan nama Anda : ");
nama = br.readLine();
 
System.out.print("Masukkan jumlah awal investasi (Rp) :
");
strawal = br.readLine();
 
System.out.print("Masukkan bunga (mis 0.1 = 10%) : ");
strbunga = br.readLine();
 
System.out.print("Masukkan periode (tahun) : ");
strperiode = br.readLine();
 
} catch(IOException ioe) {
System.out.println("Kesalahan IO pada saat menanyakan
nama Anda");
System.exit(1);
}
 
// deklarasi variabel tipe bilangan
double awal;
double bunga;
int periode;
double akhir;
 
// mengubah input dari Sting ke tipe data bilangan
periode = Integer.parseInt(strperiode);
awal = Double.parseDouble(strawal);
bunga = Double.parseDouble(strbunga);
 
// menghitung hasil investasi selama n periode
akhir = awal * Math.pow(1+bunga, periode);
 
// tampilkan hasil perhitungan di layar
System.out.println();
System.out.println("Terima kasih, " + nama);
System.out.print("Hasil investasi Anda setelah " + periode + "
tahun ");
System.out.println("adalah Rp. " + akhir);
}
}
Berikut ini adalah hasil keluarannya :

Bab IV - Memulai Java Lebih Lanjut - Struktur Kontrol


Posted Min, 02/15/2009 - 18:36 by belajarprogram

Versi ramah cetak

Komponen mendasar dari suatu program -- variabel, ekspresi, penyataan, dan pemanggilan
subrutin -- telah dijelaskan pada Bab sebelumnya. Mulai dari bab ini, kita akan melihat
bagaimana komponen dasar tersebut berinteraksi sehingga menjadi program yang lebih
kompleks.

Pada bab ini, kompleksitas program akan lebih dititikberatkan pada apa yang bisa dilakukan dari
dalam sebuah subrutin. Lebih khusus, akan dijelaskan lebih lanjut tentang struktur kontrol.

Struktur kontrol, yaitu perulangan (loop) dan percabangan (branch), dapat digunakan untuk
mengulangi perintah berulang-ulang atau untuk memilih dua atau lebih skenario. Java memiliki
beberapa struktur kontrol dan kita akan lihat secara lebih detail kemudian.

Bab ini juga akan membahas tentang desain suatu program. Jika kita dihadapkan pada suatu
permasalahan yang akan dipecahkan oleh program komputer, bagaimana caranya kita berfikir
untuk merancang program tersebut. Kita akan melihat sebagian jawabannya di bab ini, dan
kemudian akan kita gunakan dalam beberapa contoh yang tersedia.

 Blok, Perulangan, dan Percabangan


 Perancangan Algoritma
 Membuat kode, menguji, dan mencari kesalahan (debugging)
 while dan do ... while
 Perulangan for
 Pernyataan if
 Pernyataan switch

Blok, Perulangan, dan Percabangan


Posted Min, 02/15/2009 - 19:29 by belajarprogram
Versi ramah cetak

Kemampuan suatu program untuk melakukan tugas kompleks dilakukan dengan menggabungkan
perintah sederhana menjadi struktur kontrol. Dalam bahasa Java, ada 6 struktur tersebut, yaitu
blok, perulangan while, perulangan do ... while, perulangan for, pernyataan if, dan
pernyataan switch.

Masing-masing struktur ini sebetulnya merupakan pernyataan tunggal yang berdiri dengan
sendirinya, tetapi di dalamnya terdiri dari satu atau lebih perintah sehingga keseluruhannya
menjadi suatu struktur perintah.

Blok

Blok adalah pernyataan sederhana yang dimulai dengan { dan diakhiri dengan }. Tujuannya
untuk mengelompokkan beberapa perintah sehingga lebih dimengerti. Misalnya

{
perintah
}

Pernyataan blok biasanya terdapat dalam struktur kontrol, tetapi sebetulnya tanpa struktur
kontrol pun, blok tetap berlaku. Contoh sederhana penggunaan blok ini adalah dalam subrutin
main() yang kita lakukan pada contoh-contoh sebelumnya.

Berikut ini adalah 2 contoh penggunaan blok.

{
System.out.println("Hallo");
System.out.println("Dunia");
}
 
{ // blok ini digunakan untuk menukar isi variable x dan y
int temp;
temp = x;
x = y;
y = temp;
}

Pada blok kedua, kita mendeklarasikan variable baru temp. Dalam blok kedua ini, variabel
apapun yang dideklarasikan tidak akan dapat diakses dari luar blok ini. Variabel ini disebut
variabel lokal, karena hanya bisa diakses dari dalam blok.

Ketika komputer menjalankan program ini, komputer akan mempersiapkan memori untuk
menyimpan variabel yang dideklarasikan di dalam blok ini. Ketika blok ini selesai dijalankan,
komputer akan melepas memori yang digunakan dalam blok ini untuk digunakan oleh bagian
program lain.
Konsep "scope" atau jangkauan pada konsep pemrograman, mengacu pada bisa atau tidaknya
suatu variabel dilihat oleh bagian program lain. Jangkauan suatu variabel menyatakan di bagian
mana variabel ini valid atau dengan kata lain bisa diakses. Jangkauan variabel dalam suatu blok
terbatas hanya pada blok tersebut.

Blok sendiri sebetulnya bukan merupakan struktur kontrol. Program akan berjalan seperti biasa
dari atas kebawah seperti biasa. Secara umum struktur kontrol dibagi menjadi 2 bagian, yaitu :
perulangan dan percabangan.

Perulangan

Sebagai contoh untuk membahas tentang perulangan, kita lihat pernyataan while, yang memiliki
bentuk seperti

while (suatu_kondisi) {
perintah
}

Semantik pada pernyataan while tersebut adalah sebagai berikut. Ketika komputer sampai pada
pernyataan while, komputer akan melakukan perhitungan pada suatu_kondisi. Apabila
suatu_kondisi bernilai true, blok yang berisi perintah akan dilakukan. Setelah komputer
sampai pada bagian akhir blok, komputer akan menghitung kembali suatu_kondisi. Jika masih
bernilai true, maka blok tersebut akan dieksekusi, dan jika tidak, program akan melompat ke
bagian program berikutnya setelah blok berakhir. Atau dengan kata lain, jika suatu_kondisi
bernilai false, blok perintah tidak akan dieksekusi.

Berikut ini adalah contoh untuk menulis bilangan 1 hingga 5.

int angka = 1; // inisialisasi variabel, kita mulai dengan mengisi variabel


angka dengan 1
 
while (angka <= 5) {
System.out.println(angka); // cetak isi angka di layar
angka = angka + 1; // tambah angka dengan 1
}
 
System.out.println("Selesai...");

Variabel angka kita inisialiasi (persiapkan) dan kita isi mula-mula dengan 1. Ketika program
sampai pada pernyataan while, program akan mengevaluasi apakah angka <= 5. Pada saat
program baru dimulai, angka masih bernilai 1, sehingga pernyataan angka <= 5 bernilai true.
Dalam hal ini perintah di dalam blok akan dieksekusi, yaitu mencetak angka ke layar, kemudian
menambah angka dengan 1. Sekarang angka bernilai 2.

Setelah sampai pada akhir blok, program akan kembali pada awal pernyataan while. Sekarang
angka bernilai 2, dan karena 2 masih kurang dari atau sama dengan 5, program akan kembali
mengeksekusi perintah dalam blok. Begitu seterusnya hingga angka bernilai 6. Pada saat ini
program akan berhenti melakukan perulangan dan berhenti melakukan eksekusi perintah di
dalam blok tersebut, kemudian melakukan perintah berikutnya, yaitu menampilkan kata
"Selesai...".

Percabangan

Pernyataan if memperintahkan komputer untuk memilih salah satu aksi yang akan dilakukan,
tergantung pada suatu kondisi tertentu. Bentuknya dapat ditulis sebagai berikut

if (suatu_kondisi)
perintah_1;
else
perintah_2;

Perintah_1 dan perintah_2 juga bisa berbentuk blok, sehingga pernyataan di atas dapat ditulis
juga sebagai berikut

if (suatu_kondisi) {
perintah_1;
} else {
perintah_2;
}

Ketika komputer sampai pada pernyataan if, komputer akan menghitung apakah
suatu_kondisi bernilai true. Jika iya, maka blok perintah berikutnya akan dieksekusi, dalam hal
ini perintah_1. Jika tidak, maka blok setelah pernyataan else akan dieksekusi, yaitu
perintah_2.

Sebagai contoh, mari kita kembali pada contoh program untuk membalik nilai x dan y, dengan
syarat x harus lebih besar dari y. Dalam hal ini, setelah program ini dieksekusi, nilai x akan
selalu bernilai lebih kecil dari y, karena jika nilai x lebih besar, nilai x akan ditukar dengan nilai
y.

if (x > y) { // jika x lebih besar dari y


// blok ini digunakan untuk menukar isi variable x dan y
int temp;
temp = x;
x = y;
y = temp;
}

Contoh berikut adalah program untuk menentukan apakah suatu bilangan merupakan bilangan
genap atau bilangan ganjil. Dengan menggunakan operator %, yaitu sisa pembagian, kita dapat
menentukan apabila sisa pembagian suatu bilangan dengan 2 adalah 0, maka bilangan tersebut
merupakan bilangan genap. Jika tidak, maka bilangan tersebut adalah bilangan ganjil.

if ((x % 2) == 0) {
System.out.println(x + " adalah bilangan genap");
} else {
System.out.println(x + " adalah bilangan ganjil");
}
Kita akan bahas tentang struktur kontrol di bagian berikutnya. Semoga bagian ini yang
merupakan bagian pendahuluan tentang struktur kontrol dapat dimengerti sehingga kita bisa
mempelajari konsep yang lebih kompleks lagi.

Perancangan Algoritma
Posted Min, 02/15/2009 - 21:06 by belajarprogram

Versi ramah cetak

Komputer itu bodoh! Kenapa? Karena sebagai programmer, kita harus memberikan perintah
hingga sangat detail apa yang harus dikerjakan oleh komputer. Programmer adalah orang yang
bertugas untuk menerjemahkan suatu tugas menjadi instruksi detail yang dapat dimengerti oleh
komputer. Komputer hanya melakukan apa yang diperintahkan baris demi baris, tetapi komputer
tidak bisa berfikir bagaimana melakukan suatu tugas seefisien mungkin.

Untuk itu programmer baru harus dilengkapi dengan cara berfikir dan peralatan yang
memungkinkan mereka untuk sukses dalam menerjemahkan suatu tugas menjadi rangkaian
perintah yang bisa dimengerti oleh komputer.

Program komputer itu seperti seni yang memuat suatu ide. Seorang programmer mulai dengan
suatu tugas di kepalanya, misalnya menghitung sisi miring dari segitiga siku-siku. Kemudian dia
akan berfikir tentang apa yang harus dilakukan untuk menyelesaikan tugas tersebut dalam bahasa
manusia. Dalam hal ini misalnya, sisi miring dapat dihitung dengan mengambil akar kuadrat dari
jumlah kuadrat sisi siku-sikunya. Pemecahan masalah ini kemudian diterjemahkan ke dalam
bahasa pemrograman yang berupa perintah langkah demi langkah bagaimana komputer harus
menyelesaikan tugas tersebut.

Perintah langkah demi langkah hingga detail ini disebut algoritma. (Secara teknis, algoritma
adalah kumpulan langkah-langkah sederhana yang jelas, tidak membingungkan karena hanya ada
satu cara untuk melakukan langkah sederhana tersebut, dilakukan selama kurun waktu tertentu.
Kita tidak ingin program menghitung selamanya tanpa batas waktu.)

Program ditulis dalam bahasa pemgrograman tertentu. Tetapi algoritma ditulis secara umum atau
generic, dalam bahasa manusia, sehingga bisa diimplementasikan menggunakan bahasa
pemrograman apapun. Atau dengan kata lain, algoritma mirip seperti ide di belakang program
yang akan kita tulis. Tetapi ide tersebut harus jelas, dan memuat langkah demi langkah yang
sederhana.

Jadi darimana algoritma itu datang? Biasanya orang harus membuat algoritma itu. Dengan skill,
latihan dan pengalaman, orang akan lebih mudah membuat suatu algoritma.

Di bagian ini akan dibahas tentang bagaimana membuat suatu algoritma. Jadi bahasa Java akan
kita tinggalkan sementara. Kita akan beralih untuk berfikir secara abstrak.
Misalnya, kita memiliki suatu tugas di kepala. Salah satu cara untuk menyelesaikan tugas itu
adalah menuliskan penyelesaiannya langkah demi langkah, dan dari sana kita membuat algoritma
untuk menyelesaikan masalah itu. Kemudian dari setiap langkah tersebut, kita bisa membuat
langkah-langkah lain yang lebih detail, sampai kita bisa menerjemahkan langkah-langkah itu ke
dalam bahasa pemrograman. Metode ini disebut penghalusan bertahap (stepwise refinement),
dan sifatnya top-down atau dari atas ke bawah. Sambil kita menambah detail pada setiap
langkah, kita bisa mulai menuliskan algoritma dalam bentuk pseudocode (kode palsu) yang
bentuknya tidak harus persis atau mengikuti suatu bahasa pemrograman.

Misalnya, kita ambil contoh untuk menghitung rata-rata dari 5 bilangan. Kita bisa menuliskan
pseudocode dalam bentuk berikut :

ambil input user untuk bilangan pertama


masukkan ke variabel x
ambil input user untuk bilangan kedua
tambahkan variabel x dengan bilangan kedua
ambil input user untuk bilangan ketiga
tambahkan variabel x dengan bilangan ketiga
ambil input user untuk bilangan keempat
tambahkan variabel x dengan bilangan keempat
ambil input user untuk bilangan kelima
tambahkan variabel x dengan bilangan kelima
bagi variabel x dengan 5
tampilkan hasilnya di layar

Algoritma di atas betul, tetapi terlalu banyak perulangan. Bagaimana jika bilangan yang akan
dirata-ratakan ada 100? Kita bisa udah algoritma di atas dengan pseudocode yang lebih mudah
dimengerti, misalnya

while a kurang dari 5


ambil input user untuk bilangan ke-a
tambahkan nilai x dengan bilangan ke-a
tambah a dengan 1
bagi variabel x dengan 5
tampilkan di layar

Sekarang, ambil input user bisa dideskripsikan lebih jauh. Kita harus memberikan pertanyaan
kepada user. Dan seperti dipelajari pada bab sebelumnya, input dari user berupa String yang
harus diterjemahkan ke dalam tipe data bilangan untuk bisa dikalkulasi. Pseudocode di atas dapat
ditulis ulang sebagai berikut :

while a kurang dari 5


beri pertanyaan kepada user untuk memasukkan bilangan ke-a
ambil input user untuk bilangan ke-a
ubah input menjadi bilangan
tambahkan nilai x dengan bilangan ke-a
tambah a dengan 1
bagi variabel x dengan 5
tampilkan di layar
Dan juga dari pelajaran sebelumnya, untuk mengambil input user, kita bisa dihadapkan pada
permasalahan IO (input output). Selain itu kita juga harus menginisialisasi pembaca dan tempat
meletakkan string sementara. Untuk itu, kita harus mengubah pseudocode nya menjadi seperti ini

inisialisasi pembaca
inisialisasi tempat string sementara
while a kurang dari 5
beri pertanyaan kepada user untuk memasukkan bilangan ke-a
"coba" ambil input user untuk bilangan ke-a
jika ada masalah keluar dari program
ubah input menjadi bilangan
tambahkan nilai x dengan bilangan ke-a
tambah a dengan 1
bagi variabel x dengan 5
tampilkan di layar

Kemudian, perlu diperhatikan bahwa variabel a dan x tidak diketahui nilai awalnya oleh
komputer. Bayangkan jika nilai a dan x ditentukan oleh komputer secara acak, bukan saja hasil
rata-ratanya menjadi tak tentu, tetapi juga perulangannya menjadi tak menentu. Untuk itu kita
harus tambahkan perintah untuk menginisialisasi a dan x dengan 0, sehingga pseudocodenya
menjadi

inisialisasi x dengan 0
inisialisasi a dengan 0
inisialisasi pembaca
inisialisasi tempat string sementara
while a kurang dari 5
beri pertanyaan kepada user untuk memasukkan bilangan ke-a
"coba" ambil input user untuk bilangan ke-a
jika ada masalah keluar dari program
ubah input menjadi bilangan
tambahkan nilai x dengan bilangan ke-a
tambah a dengan 1
bagi variabel x dengan 5
tampilkan di layar

Dari sini kita bisa menerjemahkan pseudocode tersebut menjadi program Java, yaitu

double x = 0;
int a = 0;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String strbilangan = null;
 
while (a < 5) {
System.out.print("Masukkan bilangan ke-" + a + " : ");
try {
strbilangan = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
x = x + Double.parseDouble(strbilangan);
a = a + 1;
}
x = x / 5;
System.out.println("Rata-rata bilangan yang dimasukkan adalah " + x);

Jangan lupa bahwa program tersebut membutuhkan paket java.io.*, sehingga kita harus
menambah

import java.io.*

di awal kelas.

Berikut ini adalah program lengkapnya dan dapat diunduh dalam bentuk zip file atau melalui
SVN di alamat berikut http://belajarjava.googlecode.com/svn/trunk/HitungRataRata5Bil

package hitungratarata5bil;
 
import java.io.*;
 
public class HitungRataRata5Bil {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
double x = 0;
int a = 0;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String strbilangan = null;
 
while (a < 5) {
System.out.print("Masukkan bilangan ke-" + a + " : ");
try {
strbilangan = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
x = x + Double.parseDouble(strbilangan);
a = a + 1;
}
 
x = x / 5;
System.out.println("Rata-rata bilangan yang dimasukkan adalah
" + x);
}
}

Untuk menguji program tersebut, jalankan "Run -> Run" atau Ctrl-F11. Kemudian arahkan
kursor Anda ke bagian bawah dan klik di kotak yang bernama Console.
Berikut ini adalah hasil keluarannya, Anda bisa mencoba-coba dengan bilangan apapun.

Membuat kode, menguji, dan mencari kesalahan (debugging)


Posted Min, 02/15/2009 - 22:02 by belajarprogram

Versi ramah cetak


Akan sangat sederhana dan indah apabila program yang kita tulis akan berjalan 100% tanpa
kesalahan sama sekali. Kita tinggal memencet tombol run, dan semuanya berjalan sesuai
rencana.

Nyatanya tidak demikian.

Coba Anda ganti salah satu dari beberapa contoh yang sudah diberikan dengan mengganti salah
satu kurung { menjadi (. Kemudian pada Eclipse, jalankan dengan "Run -> Run". Lihat apa
yang terjadi.

Eclipse akan menampilkan pesan kesalahan, itu artinya secara sintaks, atau format penulisan
program ada memiliki kesalahan, dan Anda harus memperbaikinya sebelum program bisa
dijalankan.

Sintaks adalah salah satu cara menentukan bagaimana komputer harus bekerja. Manusia tidak
membutuhkan sintaks untuk berbicara karena manusia bisa menentukan mana subjek, predikat,
atau objek dengan mudah, bahkan untuk kalimat yang belum pernah dibaca atau didengar
sekalipun.

Bagi komputer, sintaks membantu komputer mengelola logika, mana yang merupakan variabel,
mana yang berupa subrutin, mana perulangan, mana percabangan dan lain-lain. Dalam bahasa
Java, yang merupakan bahasa dengan sintaks ketat, perbedaan sintaks sedikit saja membuat Java
tidak mengerti apa yang dimaksud dalam program.

Bagi beberapa programmer, ketidakluwesan Java mungkin menghambat, tetapi perlu diingat
bahwa kesalahan hanya datang dari manusia. Ketidakluwesan Java membantu programmer harus
menggunakan logika yang benar, dan tidak boleh salah dalam menggunakan variabel. Variabel
yang sudah ditentukan tipenya tidak dapat diubah ditengah jalan, kecuali dengan membuat
variabel baru dengan tipe yang berbeda.

Debugging

Ketika program Anda tidak menunjukkan kesalahan sintaks, bukan berarti program Anda bebas
dari kesalahan. Program harus diuji apakah ia berjalan sesuai dengan yang diharapkan. Idealya
apabila program menerima input yang tidak sesuai dengan yang diharapkan, program akan
memberikan pesan kepada penggunanya tentang kesalahan tersebut, bukan tiba-tiba keluar tanpa
pesan.

Kita mungkin harus melakukan testing secara lebih perlahan-lahan. Apabila jumlah baris dalam
program kita kecil, mungkin kesalahan tersebut dengan mudah akan kita temui. Tetapi apabila
program tersebut sangat besar, maka mencari kesalahan yang kelihatannya sederhana tidaklah
mudah.

Pencarian kesalahan ini dalam bahasa pemrograman disebut dengan "debugging", yang jika
diterjemahkan ke dalam bahasa Indonesia berarti membersihkan kutu, karena kesalahan kecil
dianggap sebagai kutu yang mengganggu jalannya program.

Eclipse menyediakan peralatan untuk melakukan debugging, yaitu dengan menekan tombol
"Run -> Debug". Dalam Eclipse, debugging yang bisa dilakukan antara lain: membuat
breakpoint (tempat berhenti program), mengeksekusi satu demi satu perintah, mengeksekusi satu
subrutin, melihat isi variabel saat ini, dan bahkan mengganti variabel pada saat program
dijalankan.

Untuk mendemonstrasikan debugging ini, mari kita gunakan program menghitung rata-rata pada
bagian terdahulu.

Membuat breakpoint

Kita bisa menjalankan program baris demi baris, tetapi sebelum kita melakukannya, kita harus
memberhentikan program tersebut di satu tempat terlebih dahulu. Tempat pemberhentian
program sementara ini disebut breakpoint. Untuk mengeset breakpoint, double klik bagian paling
kiri dari baris di mana Anda ingin program tersebut berhenti.

Misalnya pada tampilan berikut, program berhenti di baris double x=0;. Perhatikan juga bahwa
baris yang diberi breakpoint memiliki tanda bulat di sampingnya.
Untuk menghapus breakpoint, double click lagi tanda bulat di baris yang sudah diberi breakpoint
tadi.

Menjalankan program hingga breakpoint

Coba tekan tombol F11 atau "Run -> Debug". Pada saat Anda memulai debugging, Eclipse akan
memberikan pertanyaan bahwa perspective (atau tampilan Eclipse) Anda akan diubah ke
debugging perspective. Tekan Yes untuk mengubah perspective tersebut.

Berikut ini adalah perspektif dalam mode debugging.


Perhatikan bahwa di samping tanda bulat tadi, ada tanda panah (->) yang menunjukkan saat ini
komputer telah melaksanakan program hingga pada baris ini. Di samping kanan adalah daftar
variabel yang dideklarasikan dalam program ini. Karena baris yang kita pilih adalah baris
pertama setelah deklarasi pada subrutin main, maka hanya satu variabel yang tersedia, yaitu yang
berasal dari arg.

Menjalankan program langkah per langkah

Apabila Anda sudah berada dalam mode debugging, Anda bisa melakukan navigasi untuk
melakukan eksekusi sesuka Anda. Ada beberapa pilhan yang disediakan oleh Eclipse, semuanya
terdapat dalam menu Run yaitu :

 Resume melanjutkan eksekusi program yang berhenti.


 Suspend menghentikan sementara program yang sedang jalan.
 Terminate menghentikan sesi debugging saat ini.
 Step Into mengeksekusi SATU perintah atau masuk ke dalam subrutin.
 Step Over mengeksekusi SATU perintah. Jika perintah tersebut merupakan perintah panggilan
subrutin, maka subrutin tersebut akan dieksekusi tanpa masuk ke dalam subrutin yang dipanggil
tersebut.
 Step Return mengeksekusi seluruh perintah pada subrutin ini kemudian kembali kepada
pemanggilnya.
 Run to Line menjalankan program dari baris tempat berhentinya program sekarang hingga baris
yang Anda tentukan. Atau jika di antaranya terdapat breakpoint lagi, maka program akan
berhenti di breakpoint tersebut.

Mari kita coba untuk menjalankan progam satu langkah dengan menggunakan "Run ->
Step Over" atau tombol F6.

Berikut ini adalah screen shot setelah program maju satu langkah. Perhatikan bahwa
tanda panah maju satu langkah. Dan juga karena instruksi pada baris ini adalah
mendeklarasikan variabel x bertipe double, dan kemudian mengisinya dengan 0, variabel
ini akan muncul di kanan atas perspektif Debug.

Lakukan terus Step Over hingga program berakhir, dan Anda akan melihat langkah demi
langkah bagaimana program dijalankan secara bertahap. Perlu diingat, pada saat program
sampai pada instruksi untuk mengambil input Anda, klik bagian bawah (tab yang
bernama Console), dan masukkan angka sebagai input kemudian tekan Enter. Lihat
bagaimana variabel di kanan atas berubah sesuai dengan input yang Anda berikan.

Melihat dan mengubah isi variabel


Di sini saya jalankan program setiap baris hingga a = a + 1 seperti pada gambar berikut.
Kemudian, saya ingin memperpanjang perulangan, sehingga bukan melakukan 5 kali
perulangan, tetapi 6 kali, yaitu dengan mengubah nilai a menjadi -1. Ini bisa dilakukan
yaitu dengan mengklik nilai dari a, yang semula 0, kemudian diganti menjadi -1, seperti
pada screen shot berikut.

Setelah diganti coba jalankan program hingga selesai, misalnya dengan "Run ->
Resume". Jangan lupa untuk memasukkan inputnya di bagian Console. Lihat sekarang
bilangan ke-0 ditanyakan 2 kali, yang artinya user diperintahkan untuk memasukkan 6
bilangan. Tentunya hasil rata-ratanya salah, karena perhitungan rata-rata dilakukan
dengan rumus x = x/5, dalam hal ini seharusnya adalah 6.

Setelah selesai melakukan debugging, Anda mungkin ingin mengubah perspektif kembali
seperti semula. Caranya, di bagian paling kanan (lihat gambar dibawah), klik tanda >>
kemudian pilihan akan muncul. Klik perspektif Java untuk mengubahnya menjadi
tampilan semula.

while dan do ... while


Posted Sen, 02/16/2009 - 23:51 by belajarprogram

Versi ramah cetak

Pernyataan while

Pernyataan while telah diperkenalkan pada bagian sebelumnya. Perulangan while memiliki
bentuk

while (suatu_kondisi)
perintah

perintah bisa juga berupa blok yang berisi kumpulan perintah-perintah di antara { dan }.
perintah ini disebut juga dengan inti perulangan. Inti perulangan akan terus dieksekusi selama
suatu_kondisi bernilai true. suatu_kondisi ini disebut juga penguji perulangan.
Ada beberapa hal yang mungkin jadi pertanyaan. Apa yang terjadi jika suatu_kondisi sudah
bernilai false sejak pertama kali komputer sampai pada pernyataan ini? Dalam hal ini blok
perulangan tidak akan dieksekusi sama sekali. Program akan melompat ke perintah berikutnya di
luar blok perulangan.

Lalu apa yang terjadi jika suatu_kondisi bernilai false di tengah-tengah perulangan, apakah
program keluar dari perulangan saat itu juga? Dalam hal ini, tentunya tidak. Program akan
mengeksekusi semua perintah hingga akhir blok selesai. Setelah itu program akan kembali ke
pernyataan while, dan setelah mengevaluasi kembali suatu_kondisi, dan jika hasilnya salah,
baru program akan melompat ke perintah berikutnya di luar blok.

Mari kita ubah sedikit algoritma yang kita buat di bagian sebelumnya. Kali ini kita akan
membuat program yang menghitung rata-rata dengan cara menanyakan suatu bilangan kepada
user, kemudian program akan berhenti jika masih ada data yang akan diproses.

Inisialisasi jumlah dengan 0


Inisialisasi n (berapa data yang dimasukkan user) dengan 0
while (masih ada data yang akan diproses):
Minta input dari user
Tambah jumlah dengan input dari user
Tambah n dengan 1
Bagi jumlah dengan n untuk menghitung rata-rata
Cetak rata-rata ke layar

Pertanyaan berikutnya, bagaimana menentukan masih ada data yang akan diproses? Cara yang
paling mudah adalah melihat apakah nilai yang dimasukkan user bernilai 0. Nol di sini bukan
termasuk data yang akan dijumlahkan tetapi bertugas sebagai sinyal bahwa tidak ada lagi data
yang harus dimasukkan.

Lalu bagaimana kita harus menguji bahwa data yang dimasukkan bernilai 0 atau bukan? (Ingat,
kita baru menanyakan data di dalam blok perulangan. Pada saat komputer pertama kali menemui
perulangan while, komputer tidak tahu apa-apa.) Dalam hal ini, kita akan sedikit ubah algoritma
kita seperti berikut :

Inisialisasi jumlah dengan 0


Inisialisasi n (berapa data yang dimasukkan user) dengan 0
Minta input dari user
while (input tidak sama dengan 0):
Tambah jumlah dengan input dari user
Tambah n dengan 1
Minta input dari user
Bagi jumlah dengan n untuk menghitung rata-rata
Cetak rata-rata ke layar

Pada dasarnya, kita tanyakan user terlebih dahulu sebelum perulangan while. Dengan cara ini,
kita bisa mendapat nilai input untuk dievaluasi pada pernyataan while. Di dalam perulangan
while, kita tempatkan pertanyaan untuk mendapat input dari user di akhir perulangan. Artinya,
setelah kita memproses input dari user, kita akan tanyakan lagi kepada user untuk mendapatkan
kondisi untuk mengevaluasi kondisi while berikutnya.
Perhatikan juga bahwa ketika 0 dimasukkan, program tidak akan menghitung nilai 0 lagi. Di
algoritma sebelumnya, nilai 0 akan ikut dijumlahkan dan n akan bertambah 1, padahal 0 bukan
data. Nol hanya berfungsi sebagai sinyal bahwa perulangan harus selesai. Masalah ini sangat
amat umum ditemui oleh programmer, karena menghitung satu demi satu ternyata tidak mudah.
Untuk itu debugger diperlukan untuk melihat lebih detail apa yang dilakukan oleh komputer.

Kita bisa ubah algoritma di atas menjadi program Java sebagai berikut. (Seperti biasa program
ini bisa diunduh dalam bentuk zip file atau di alamat SVN berikut:
http://belajarjava.googlecode.com/svn/trunk/RataRata )

package ratarata;
 
import java.io.*;
 
public class RataRata {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
double jumlah = 0;
double bilangan = 0;
int n = 0;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String strbilangan = null;
 
System.out.print("Masukkan bilangan pertama : ");
try {
strbilangan = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
 
// mengubah input menjadi double agar bisa diproses lebih
lanjut
bilangan = Double.parseDouble(strbilangan);
 
while (bilangan != 0) {
jumlah += bilangan; // sama dengan : jumlah = jumlah
+ bilangan
n++; // sama dengan : n = n+1
 
// tanya user input
System.out.print("Masukkan bilangan berikutnya (atau 0
untuk mengakhiri) : ");
try {
strbilangan = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
 
// mengubah input menjadi double agar bisa diproses lebih
lanjut
bilangan = Double.parseDouble(strbilangan);
}
 
// hitung rata-rata
double ratarata = jumlah/n;
 
// cetak hasilnya ke layar
if (n == 0) {
System.out.println("Data kosong, rata-rata tidak bisa
dihitung");
} else {
System.out.println("Anda memasukkan " + n + " data");
System.out.println("Rata-rata bilangan yang dimasukkan
adalah " + ratarata);
}
}
}

Berikut hasil keluarannya :

Pernyataan do ... while

Kadang-kadang akan lebih mudah menulis perulangan jika penguji perulangan dilakukan di
akhir badan perulangan. Dalam hal ini badan perulangan akan dieksekusi terlebih dahulu tanpa
memperdulikan apakah suatu kondisi bernilai true atau false. Pengujian dilakukan di akhir
setelah suatu kondisi didapat dalam eksekusi perulangan pertama kali.

Pernyataan do ... while pada dasarnya merupakan pernyataan while terbalik, dengan bentuk.

do
perintah
while (suatu_kondisi);

Atau apabila perintah berbentuk blok kumpulan perintah-perintah, bisa juga ditulis dalam bentuk

do {
perintah-perintah
} while (suatu_kondisi);

Perlu diingat bahwa pernyataan do ... while diakhiri dengan tanda ; di akhir while.
Contoh sederhana adalah program bermain game, di mana game akan menanyakan apakah user
ingin bermain lagi.

do {
main game
tanya user apakah ingin main lagi
} while (user menjawab ya);

Jika suatu saat Anda harus menulis kondisi pada pernyataan while seperti ini while (jawaban
== true), Anda bisa mengganti pernyataan ini menjadi while (jawaban). Menguji apakah
jawaban sama dengan true sama artinya dengan melihat apakah jawaban berisi "true".

Demikian juga dengan while (jawaban == false), bisa diganti dengan while (!jawaban).
Seperti dijelaskan pada bab tentang operator boolean, operator ! membalik isi dari boolean,
misalnya dari true menjadi false atau sebaliknya. Dengan menuliskan while (!jawaban) berarti
sama dengan menguji apakah jawaban berisi false.

Pernyataan do ... while memberikan keleluasaan kepada Anda untuk berekspresi dengan
lebih lugas. Sebenarnya, untuk memecahkan suatu masalah dengan perulangan do ... while
juga bisa diekspresikan dengan perintah while, demikian juga sebaliknya.

do
perintah
while (suatu_kondisi);

bisa dituliskan dalam bentuk

perintah
while (suatu_kondisi)
perintah

Demikian juga dengan

while (suatu_kondisi)
perintah

bisa juga dituliskan dalam bentuk

if (suatu_kondisi) {
do {
perintah
while (suatu_kondisi);
}

tanpa merubah aliran program sama sekali.

Pernyataan break dan continue


Pernyataan while dan do ... while menguji kondisi di awal atau di akhir badan perulangan.
Pengujian bisa juga dilakukan di tengah-tengah badan perulangan, kemudian memerintahkan
program untuk keluar dari badan perulangan saat itu juga. Caranya dengan menggunakan
perintah

break<code>, sehingga program seperti


 
<code>while (suatu_kondisi)
perintah

bisa ditulis dalam bentuk

while (true)
perintah
if (!suatu_kondisi)
break;
<code>
 
Apa makna dari program di atas? <code>while (true)
artinya memerintahkan program untuk melakukan perulangan selamanya, karena true tidak akan
berubah. Di tengah-tengah program, kita uji apakah suatu_kondisi bernilai false. Jika ya, maka
perintah break akan dieksekusi yang menyebabkan program keluar dari badan perulangan ke perintah
berikutnya di luar badan perulangan.

Kadang-kadang gaya penulisan ini lebih masuk akal ketimbang gaya penulisan baku seperti
while atau do ... while, tapi tentu saja ini tergantung dari cara pikir masing-masing
programmer dan juga masalah yang akan dipecahkan.

Pernyataan while atau do ... while dapat dibuat bertingkat, misalnya membuat blok while
dalam blok while.

while (suatu_kondisi) {
perintah
while (kondisi_lain) {
perintah_lain
while (kondisi_lain_lagi) {
perintah_baru
}
}
}

Apabila perintah break diberikan, maka program akan keluar dari perulangan yang berada persis
di atasnya. Misalnya, apabila perintah break diberikan setelah perintah_lain maka program
akan keluar dari dalam perulangan while (kondisi_lain).

Perlu diingan juga apabila perintah break diberikan di dalam pernyataan if, maka program akan
keluar dari perulangan yang persis di atasnya.
Selain perintah break yang secara langsung menghentikan perulangan, perintah continue
digunakan untuk menghentikan operasi saat itu, mengabaikan perintah hingga perulangan
berakhir, kemudian kembali kepada perintah while lagi. Misalnya,

while (suatu_kondisi) {
perintah
continue;
perintah_lagi
perintah_lain_lagi
}

Perulangan akan menjalankan perintah, mengabaikan perintah_lagi dan


perintah_lain_lagi, kemudian kembali kepada pernyataan while untuk mengevaluasi apakah
suatu_kondisi bernilai true. Jika ya perulangan akan diteruskan. Tetapi karena ada perintah
continue, artinya selama perulangan tersebut berjalan, perintah_lagi dan
perintah_lain_lagi tidak akan pernah dieksekusi.

Perulangan for
Posted Jum, 02/20/2009 - 02:07 by belajarprogram

Versi ramah cetak

Kita akan membahas bentuk perulangan lain, yaitu perulangan for. Setiap bentuk perulangan
for dapat diubah menjadi bentuk perulangan while dengan fungsi yang sama tanpa mengubah
alur program. Tetapi tergantung dari permasalahan yang akan kita pecahkan, menulis program
dengan for akan membuat alur program lebih mudah dipahami.

Misalnya, kita akan menghitung 1+2+3+4+5+...+100. Kita bisa ekspresikan program tersebut
dalam bentuk

i = 1;
jumlah = 0;
while (i <= 100) {
jumlah += i;
i++;
}

Perulangan ini dapat ditulis juga dengan

jumlah = 0;
for (i = 1; i <= 100; i++)
jumlah += i

Apa point-point penting yang kita lihat dari perubahan ini? Pertama mari kita lihat bentuk
penggunaan while yang umum dilakukan

inisialisasi variabel
while (suatu_kondisi_variabel) {
perintah
update_variabel
}

Di sini perulangan while memiliki 3 komponen penting, yaitu inisialisasi, yaitu memberikan
nilai awal suatu variabel, suatu_kondisi_variabel, yaitu pengujian bahwa perulangan akan terus
dilakukan selama kondisi ini bernilai true, dan terakhir update_variabel, yaitu instruksi
mengubah nilai kondisi variabel untuk membatasi perulangan sehingga akan selesai suatu saat,
tidak berulang terus menerus.

Pada perulangan for, ketiga komponen ini dirangkai menjadi satu dalam bentuk

for (inisialisasi_variabel; kondisi_variabel; update_variabel)


perintah

atau jika perintah merupakan blok yang terdiri dari banyak perintah, dapat dituliskan juga dalam
bentuk

for (inisialisasi_variabel; kondisi_variabel; update_variabel) {


banyak_perintah
}

Di sini inisialisasi variabel bisa berupa apa saja yang berbentuk perintah, misalnya memberikan
variabel dengan nilai awal tertentu, dalam bentuk variabel = nilai_awal.

kondisi_variabel harus berbentuk pernyataan boolean seperti suatu_kondisi pada


pernyataan while. Sedangkan update_variabel juga berbentuk perintah.

inisialisasi_variabel, kondisi_variabel, atau update_variabel dapat dikosongkan dan


tidak harus selalu diisi. Bagian yang tidak diisi yang selalu digantikan dengan true, yang artinya
perulangan akan terus dieksekusi tanpa henti. Untuk menghentikannya, perintah break harus
diberikan ditengah-tengah badan perulangan.

Bentuk paling umum dari perulangan for adalah menghitung. Biasanya perulangan ini memiliki
bentuk seperti

for (variabel = nilai_minimum; variabel <= nilai_maksimum; variabel++) {


perintah
}

Perhatikan bagian terakhir adalah menaikkan nilai variabel dengan 1, yang artinya perulangan
akan dimulai dengan nilai_minimum, diakhiri dengan nilai_maksimum dengan jeda 1.

Contoh, jika kita ingin berhitung 2,5,8,11,14,17, atau dengan kata lain, mulai dari 2 hingga 17
dengan jeda 3, kita bisa mengekspresikan for dengan

for (i = 2; i <= 17; i += 3) {


System.out.println(i);
}

Untuk menghitung mundur, kita bisa menggunakan perintah seperti

for (i = 20; i >= 0; i--) {


System.out.println(i);
}

Atau jika kita ingin menghitung maju dan mundur pada saat yang bersamaan, misalnya i dari 1
hingga 10 dan j dari 10 hingga 1, kita bisa ekspresikan dengan

for (i = 1, j = 10; i <= 10; i++, j--) {


System.out.println(i + " " + j);
}

Catatan penting! Variabel yang akan digunakan, dalam contoh di atas i dan j, adalah variabel
yang harus dideklarasikan sebelumnya. Java adalah bahasa pemrograman ketat, yang artinya
semua harus didefinisikan dengan jelas sebelum digunakan. Untuk banyak kasus, deklarasi
variabel dan perulangannya bisa dilakukan serentak pada bagian inisialisasi variabel. Misalnya

for (int i = 1; i <= 10; i++) {


System.out.println(i)
}

Perhatikan ada imbuhan int di depan inisialisasi variabel i, yang merupakan deklarasi variabel i
dengan tipe data int sekaligus menginisialisasi nilainya dengan 1.

Perulangan for bertingkat

Seperti pada perulangan while, perulangan for pun dapat dilakukan bertingkat, artinya
perulangan for di dalam perulangan for.

Kita ambil contoh sederhana misalnya membuat tabel perkalian seperti

1 2 3 4 5 6 7 8 9 10 11 12
2 4 6 8 10 12 14 16 18 20 22 24
3 6 9 12 15 18 21 24 27 30 33 36
4 8 12 16 20 24 28 32 36 40 44 48
5 10 15 20 25 30 35 40 45 50 55 60
6 12 18 24 30 36 42 48 54 60 66 72
7 14 21 28 35 42 49 56 63 70 77 84
8 16 24 32 40 48 56 64 72 80 88 96
9 18 27 36 45 54 63 72 81 90 99 108
10 20 30 40 50 60 70 80 90 100 110 120
11 22 33 44 55 66 77 88 99 110 121 132
12 24 36 48 60 72 84 96 108 120 132 144

Program untuk membuat tabel perkalian tersebut bisa diekspresikan dengan algoritma
pseudocode sebagai berikut
untuk setiap baris i = 1,2,3...,12
cetak perkalian i dengan 1,2,3..12
cetak baris baru

Kalau kita jabarkan lebih lanjut, perintah kedua juga merupakan perulangan dari 1 hingga 12,
sehingga algoritma di atas bisa kita tulis sebagai

untuk setiap baris i = 1,2,3...,12


untuk setiap kolom j = 1,2,3...,12
cetak i*j
cetak baris baru

Kita bisa terjemahkan ke dalam bahasa Java sebagai

for (int i = 1; i <= 12; i++) {


for (int j = 1; j <= 12; j++) {
System.out.print(i*j + " ");
}
System.out.println("");
}

Berikut ini adalah contoh program yang bisa diunduh dalam bentuk zip file atau dari gudang
SVN di alamat http://belajarjava.googlecode.com/svn/trunk/TabelPerkalian :

package tabelperkalian;
 
public class TabelPerkalian {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
for (int i = 1; i <= 12; i++) {
for (int j = 1; j <= 12; j++) {
System.out.print(i*j + " ");
}
System.out.println("");
}
}
}
Berikut ini hasil kelurannya:

Pernyataan if
Posted Min, 02/22/2009 - 16:19 by belajarprogram

Versi ramah cetak

Pernyataan if merupakan salah satu pernyataan percabangan pada Java, dengan bentuk umum
seperti

if (suatu_kondisi)
perintah1
else
perintah2

Seperti biasa, perintah1 dan perintah2 bisa berbentuk blok yang terdiri dari beberapa
perintah. Pernyataan if merupakan bentuk percabangan 2 arah. Bagian else yang terdiri dari
kata "else" dan perintah2 tidak selalu harus ada.

Perhatikan bahwa baik perintah1 dan perintah2 bisa merupakan pernyataan if itu sendiri. Ada
beberapa hal menarik yang mungkin berguna. Ambil contoh dalam pernyataan berikut

if (x > 0)
if (y > 0)
System.out.println("perintah1");
else
System.out.println("perintah2");

Pertama-tama, komputer tidak peduli bagaimana Anda memformat paragraf dan indentasi dari
pernyataan if tersebut. Java akan menganggap else terkait dengan if terdekat, sehingga kode
di atas akan dianggap seperti

if (x > 0)
if (y > 0)
System.out.println("perintah1");
else
System.out.println("perintah2");

else di program di atas akan dianggap bagian dari pernyataan jika y > 0, padahal yang kita
maksud adalah else jika x > 0. Untuk memperbaikinya, kita tambahkan tanda kurung {} sehingga
menjadi

if (x > 0) {
if (y > 0)
System.out.println("perintah1");
}
else
System.out.println("perintah2");

Kedua pernyataan tersebut memiliki arti yang berbeda. Jika x <= 0, pada kode pertama Java
tidak mencetak apa-apa ke layar, sedangkan kode kedua java akan mencetak "perintah2".

Lebih menarik lagi, perhatikan kode berikut

if (kondisi_pertama)
perintah1
else
if (kondisi_kedua)
perintah2
else
perintah3

Lagi-lagi karena Java tidak membedakan indentasi penulisan, maka kode tersebut akan
diterjemahkan Java seperti

if (kondisi_pertama)
perintah1
else if (kondisi_kedua)
perintah2
else
perintah3

Dengan kata lain perintah tersebut lebih seperti percabangan 3 arah. Komputer akan
mengeksekusi hanya salah satu dari perintah1, perintah2, atau perintah3. Komputer akan
mengevaluasi kondisi_pertama, jika true, maka perintah1 dieksekusi sementara perintah2
dan perintah3 diabaikan. Jika false, maka kondisi_kedua akan dievaluasi. Jika true, maka
perintah2 akan dieksekusi dan perintah3 diabaikan. Jika false, maka hanya perintah3 saja
yang dieksekusi.

Berikut ini adalah contoh penggunaan percabangan 3 arah.

if (suhu < 20)


System.out.println("Dingin");
else if (suhu < 30)
System.out.println("Lumayan");
else
System.out.println("Panas");

Kita bahkan dapat membentuk pernyataan if-else ini menjadi percabangan N arah, misalnya

if (kondisi_pertama)
perintah1
else if (kondisi_kedua)
perintah2
else if (kondisi_ketiga)
perintah3
else if (kondisi_keempat)
perintah4
.
.
.
else if (kondisi_keNminus1)
perintahNmin1
else
perintahN

Contoh berikut ini adalah mengurutkan 3 bilangan dari kecil ke besar. Misalnya kita mempunyai
3 variabel a,b dan c. Bilangan yang paling kecil adalah bilangan yang lebih kecil dari kedua
bilangan yang lain. Sekarang mari kita rangkai logika untuk menentukan urutan bilangan dari
kecil ke besar. Mula-mula kita cek apakah a lebih kecil dari b dan c, yaitu dengan pernyataan

if (a < b && a <c)

Jika a betul merupakan bilangan terkecil, maka kita uji apakah b lebih kecil dari c dengan
perintah

if (b < c)

Jika a bukan bilangan terkecil, maka b atau c, salah satunya bisa merupakan bilangan terkecil.
Kita hanya perlu membandingkan apakah b lebih kecil dari c dengan

if (b < c)

Jika b lebih kecil dari c, berarti kita tahu bahwa b adalah bilangan terkecil. Tetapi kita belum
tahu apakah bilangan terkecil berikutnya adalah a atau c, sehingga kita harus menguji lagi
dengan

if (a < c)

Jika a lebih kecil dari c, maka urutannya adalah b, a, c. Jika tidak, maka urutannya adalah b, c, a.

Demikian halnya apabila jika b > c, maka kita bisa tentukan urutan bilangannya.

Keseluruhan logika ini, bisa kita tuangkan dalam bentuk :

if (a < b && a < c) {


if (b < c)
System.out.println(a + " " + b + " " + c);
else
System.out.println(a + " " + c + " " + b);
} else if (b < c) {
if (a < c)
System.out.println(b + " " + a + " " + c);
else
System.out.println(b + " " + c + " " + a);
} else {
if (a < b)
System.out.println(c + " " + a + " " + c);
else
System.out.println(c + " " + b + " " + a);
}

Logika di atas bisa juga dituangkan dengan cara lain, yaitu melihat urutannya. Pertama kita cek
apakah a < b. Jika ya, kita tahu bahwa urutannya pasti a terlebih dahulu baru b. Kemudian kita
lihat apakah c berada di sebelah kiri a atau disebelah kanan b atau di tengah-tengah.

Demikian seterusnya jika urutannya b terlebih dahulu baru a. Sehingga kodenya bisa dituliskan
dalam bentuk :

if (a < b) {
if (c < a)
System.out.println(c + " " + a + " " + b);
else if (c > b)
System.out.println(a + " " + b + " " + c);
else
System.out.println(a + " " + c + " " + b);
} else {
if (c < b)
System.out.println(c + " " + b + " " + a);
else if (c > a)
System.out.println(b + " " + a + " " + c);
else
System.out.println(b + " " + c + " " + a);
}

Pernyataan switch
Posted Min, 02/22/2009 - 18:31 by belajarprogram

Versi ramah cetak

Penyataan percabangan kedua yang dimiliki Java adalah switch. Pernyataan switch lebih jarang
digunakan, tetapi sering bermanfaat apabila kita ingin menuliskan percabangan multi arah.

Pernyataan switch memiliki bentuk sebagai berikut

switch (ekspresi) {
case nilai1:
perintah1
break;
case nilai2:
perintah2
break;
case nilai3:
perintah3
break;
default:
perintah_lain
}

Di sini pernyataan switch akan mencari nilai ekspresi yang sesuai dengan nilai-nilai yang
didaftarkan pada pernyataan case. Jika salah satu nilai ditemui, maka program akan melompat
ke cabang case tersebut dan melakukan perintah yang terdapat di sana. Jika tidak ditemui, maka
program akan melompat ke perintah yang terdapat pada pernyataan default.

Catatan ekspresi hanya bisa berbentuk nilai bilangan bulat (int, short, dan sejenisnya) atau
karakter, sehingga kita tidak bisa menggunakan switch untuk mengevaluasi ekspresi yang
berbentuk String.

Pernyataan break di atas sebetulnya tidak harus selalu ada. Tetapi, perintah break di sini
memerintahkan komputer agar segera keluar dari blok switch apabila perintah tersebut telah
selesai dilaksanakan.

Apabila perintah break tidak diberikan, maka program akan terus mengeksekusi perintah lain
meskipun sudah berada di luar nilai yang tertera dalam pernyataan casenya.

Misalnya, lihat kode berikut ini :

switch (N)
case 1:
System.out.println("Angka tersebut bernilai 1");
break;
case 2:
case 3:
case 4:
case 5:
System.out.println("Angka tersebut bernilai 2, 3, 4, atau 5");
break;
case 6:
case 7:
case 8:
System.out.println("Angka tersebut bernilai 6, 7, atau 8");
break;
default:
System.out.println("Angka tersebut tidak bernilai 1 - 8");
}

Salah satu aplikasi di mana pernyataan switch berguna adalah untuk memproses menu. Menu
memiliki beberapa pilihan dan user akan diminta untuk memilih suatu pilihan. Kita dapat
menggunakan switch untuk menginstruksikan komputer untuk melakukan tugas tertentu sesuai
dengan menu yang dipilih oleh user.

Jika Anda ingat pernyataan main() pada program Java, pernyataan main memiliki parameter
String[] args, di mana args merupakan argumen yang diberikan pada saat program dijalankan
melalui konsol. Biasanya argumen yang diberikan berupa opsi bagaimana program harus
dilaksanakan. Di sini pernyataan switch juga berguna untuk memilih bagaimana program akan
berjalan.

Jika Anda terbiasa atau pernah bergaul dengan Linux, maka tidak asing untuk menemukan
perintah pada Linux seperti "ls -l" atau "tar xfz blabla". Di sini ls atau tar adalah nama program
dan "-l" atau "xfz blabla" adalah argumen yang diberikan pada saat program dijalankan.

Pernyataan kosong
Pernyataan kosong sebenarnya merupakan blok kosong, atau sama dengan {} tanpa perintah apa-
apa di dalamnya. Dalam Java, pernyataan kosong juga berarti tanda ; sehingga apabila Anda
menulis kode seperti

if (x > 0);
perintah1

maka perintah1 akan tetap dilaksanakan walaupun x <= 0.

Perintah kosong sering merupakan sumber kesalahan dan salah satu fitur yang sulit untuk dicari
kesalahannya pada saat debugging. Misalnya perintah berikut

for (i = 1; i <= 10; i++);


System.out.println("hallo");

Anda berharap untuk mencetak kata hallo 10x di layar, pada kenyataannya hanya 1 hallo yang
dicetak. Kenapa? Karena tanda ";" setelah for menyatakan bahwa program tidak melakukan apa-
apa di dalam perulangan. Perintah System.out.println("hallo") tidak berada di dalam
perulangan for, sehingga perintah ini hanya dijalankan 1x saja.

Pernyataan-pernyataan lain
Hingga saat ini kita sudah membahas hampir semua pernyataan yang Java sediakan. Ada
beberapa yang akan kita bahas kemudian, tetapi pernyataan-pernyataan ini merupakan
pernyataan lanjutan Java, seperti return yang digunakan untuk membuat subrutin sendiri, atau
try...catch dan throw untuk mengontrol alur kesalahan apabila ditemui di tengah program
(atau dengan kata lain eksepsi atau pengecualian), dan synchronized untuk mengatur kontrol
untuk multi-threading.

Beberapa kata kunci lain akan juga dibahas pada subjek tentang pemrograman berorientasi objek
yang akan kita bahas kemudian.
Contoh Program switch case
Posted Sel, 02/24/2009 - 14:34 by belajarprogram

Versi ramah cetak

Kita akan membuat program untuk main suit. Permainan ini terdiri dari dua pemain. Dalam
permainan real, biasanya dua pemain mengadu suit dengan saling menunjukkan jari. Hanya 3 jari
yang boleh dipakai: jempol, telunjuk, dan kelingking.

Peraturannya : Jempol menang lawan Telunjuk, Telunjuk menang lawan Kelingking, dan
Kelingking menang lawan Jempol.

Dalam program ini, komputer adalah pemain pertama, sedangkan user adalah pemain kedua.
Komputer akan menggunakan perintah random() untuk menghitung salah satu dari 3 pilihan. 0
berarti Jempol, 1 berarti Telunjuk, dan 2 berarti Kelingking.

User akan diberikan pertanyaan untuk memasukkan J untuk Jempol, T untuk Telunjuk dan K
untuk Kelingking. Kemudian dengan pernyataan switch, J, T, dan K akan diubah menjadi angka
0, 1, dan 2 seperti pada komputer.

Hasil perhitungan komputer dan hasil input dari user akan dibandingkan, kemudian hasilnya
siapa yang menang akan ditampilkan di layar.

package mainsuit;
 
import java.io.*;
 
public class MainSuit {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
 
// cetak aturan main dan input dari user
System.out.println("Permainan suit");
System.out.println("==============");
System.out.println("Masukkan salah satu dari 3 kemungkinan :");
System.out.println("J untuk Jempol");
System.out.println("T untuk Telunjuk");
System.out.println("K untuk Kelingking");
System.out.println(""); // baris kosong
 
// variabel untuk mengambil input dari user
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String input = null;
 
// Kita gunakan pernyataan while hingga user betul
// memasukkan salah satu dari J, T, atau K
boolean inputvalid = false;
 
int suitKomputer = 0;
int suitUser = 0;
 
// selama input tidak valid, jalankan perulangan ini
while (!inputvalid) {
System.out.print("Masukkan suit Anda ");
try {
input = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
 
// pastikan bahwa user memasukkan sesuatu dengan mengecek
// apakah panjang input > 0
// jika tidak, maka perulangan akan dilanjutkan
if (input.length() > 0) {
switch (input.charAt(0)) {
case 'j' :
case 'J' :
suitUser = 0;
inputvalid = true; // kita ganti inputvalid agar
perulangan selesai
break;
case 't' :
case 'T' :
suitUser = 1;
inputvalid = true; // kita ganti inputvalid agar
perulangan selesai
break;
case 'k' :
case 'K' :
suitUser = 2;
inputvalid = true; // kita ganti inputvalid agar
perulangan selesai
break;
}
}
}
 
// sekarang menghitung suit komputer
// Math.random() menghasilkan nilai acak antara 0 dan 1
// jika kita kali 3, berarti menghasilkan nilai acak antara 0 dan 3
// perintah (int) untuk mengubah bilangan real menjadi bilangan bulat
// dengan cara menghilangkan semua digit di belakang koma
// misalnya 1.0232323 menjadi 1
suitKomputer = (int)(Math.random()*3);
 
// suatu saat "mungkin" nilai random bernilai 3
// karena 3 tidak ada dalam suit kita, maka kita harus ubah menjadi
// salah satu suit yang valid, yaitu 0, 1, atau 2
// dalam hal ini kita ganti jadi 2
if (suitKomputer == 3) {
suitKomputer = 2;
}
 
// menghitung siapa yang menang
switch (suitKomputer) {
// jika komputer Jempol
case 0:
// cetak suit Komputer
System.out.println("Suit komputer = Jempol");
switch (suitUser) {
// jika user Jempol
case 0:
System.out.println("Seri");
break;
// jika user Telunjuk
case 1:
System.out.println("Anda kalah");
break;
// jika user Kelingking
case 2:
System.out.println("Anda menang");
break;
}
break; // dari switch(suitKomputer)
// jika komputer Telunjuk
case 1:
// cetak suit Komputer
System.out.println("Suit komputer = Telunjuk");
switch (suitUser) {
// jika user Jempol
case 0:
System.out.println("Anda menang");
break;
// jika user Telunjuk
case 1:
System.out.println("Seri");
break;
// jika user Kelingking
case 2:
System.out.println("Anda kalah");
break;
}
break; // dari switch(suitKomputer)
// jika komputer Kelingking
case 2:
// cetak suit Komputer
System.out.println("Suit komputer = Kelingking");
switch (suitUser) {
// jika user Jempol
case 0:
System.out.println("Anda kalah");
break;
// jika user Telunjuk
case 1:
System.out.println("Anda menang");
break;
// jika user Kelingking
case 2:
System.out.println("Seri");
break;
}
break; // dari switch(suitKomputer)
}
}
}

Berikut ini adalah contoh keluaran program

Listing program di atas dapat Anda unduh melalui zip file atau pada gudang SVN di alamat
http://belajarjava.googlecode.com/svn/trunk/MainSuit

Bab V - Subrutin
Posted Min, 02/22/2009 - 19:59 by belajarprogram

Versi ramah cetak

Pemrograman kompleks

Salah satu cara yang digunakan untuk memecah permasalahan kompleks menjadi permasalahan
yang lebih kecil adalah dengan subrutin. Subrutin terdiri dari sekelompok perintah yang
melakukan suatu tugas tertentu. Subrutin memiliki nama, sehingga bisa dipanggil suatu saat di
bagian lain program. Ketika komputer mengeksekusi program, setiap kali nama subrutin tersebut
dipanggil, program akan melaksanakan semua perintah di dalam subrutin tersebut.

Subrutin boleh digunakan berulang-ulang, dari mana pun di dalam program, bahkan dari dalam
subrutin lain. Dengan cara ini kita bisa membuat subrutin sederhana yang digunakan berulang-
ulang di seluruh program. Dengan cara ini, program besar dapat dipecah menjadi bagian-bagian
kecil. yang masing-masing melakukan perintah sederhana.

Seperti dijelaskan sebelumnya, subrutin bisa berbentuk statik atau non-statik. Dalam bagian ini
hanya subrutin statik yang akan dijelaskan lebih lanjut. Subrutin non-statik adalah inti dari
pemrograman berorientasi objek, dan akan dijelaskan lebih lanjut pada bab berikutnya.

 Kotak Hitam
 Subrutin Statik dan Variabel Statik
 Parameter
 Tipe Keluaran
 Toolbox, API, dan Paket
 Tentang Deklarasi

Kotak Hitam
Posted Min, 02/22/2009 - 22:18 by belajarprogram

Versi ramah cetak

Subrutin terdiri dari beberapa instruksi yang melakukan suatu tugas tertentu, dikumpulkan dalam
satu himpunan, dan diberi nama. Kumpulan instruksi ini bisa berupa suatu "tugas" yang cukup
kompleks yang disatukan sebagai konsep. Dengan cara ini, kita tidak perlu lagi memikirkan
bagaimana komputer melakukan tugas hingga sedetail mungkin. Kita hanya perlu memanggil
nama subrutin tersebut untuk menjalankan suatu "tugas".

Subrutin sering juga disebut dengan kotak hitam (atau black box) karena kita tidak perlu (atau
tidak mau tahu) secara detail apa yang subrutin tersebut lakukan. Kita hanya ingin tahu
hubungan kotak hitam tersebut dengan dunia luar. Hubungan ini disebut antar muka (interface).
Di kotak itu mungkin ada tombol yang bisa kita tekan, ada keyboard yang bisa kita ketik, atau
mungkin ada jendela untuk memberi dan mengambil informasi dari dalamnya.

Karena kita bermaksud untuk menyembunyikan kompleksitas (dalam hal ini program yang akan
kita buat), ada beberapa prinsip penting dari suatu kotak hitam :

Antar muka harus sederhana, jelas, tak berbelit-belit, dan mudah dimengerti.

Apa contoh kotak hitam di sekitar kita? Sebetulnya banyak, misalnya TV, handphone, DVD
player, MP3 player, kulkas, AC, dan sebagainya. Kita bisa menyalakan TV, mengganti channel,
menaikkan dan menurunkan volume dengan mudah tanpa harus mengetahui bagaimana TV
bekerja. Sama halnya dengan AC, Anda cukup menekan tombol, menaikkan dan menurunkan
temperatur tanpa harus mengerti bagaimana AC bekerja.

Sekarang mari kita lihat bagian dalam dari kotak hitam. Bagaimana AC atau TV bekerja disebut
dengan implementasi. Aturan kedua dari suatu kotak hitam adalah :

Untuk menggunakan kotak hitam, kita tidak perlu mengetahui tentang implementasi.
Yang kita butuh adalah antar muka.

Sebetulnya kita bisa mengganti implementasi selama apa yang dihasilkan dan apa yang diminta
tetap sama. Atau dengan kata lain, perilakunya tidak berubah. Misalnya dulu TV menggunakan
tabung hampa, tetapi sekarang menggunakan transistor. Tetapi perubahan implementasi (dari
tabung hampa ke transistor) tidak mengubah bagaimana TV dioperasikan dan apa yang kita lihat
di TV. Seperti halnya dengan program, kita bisa mengubah implementasi suatu subrutin,
misalnya mengoptimasi subrutin tersebut agar lebih cepat, tanpa mengubah perilaku program
secara keseluruhan, dan tanpa mengubah perilaku fungsi lain yang memanggil subrutin tersebut.
Tentunya untuk membuat kotak hitam, kita perlu mengetahui detail tentang implementasinya.
Kotak hitam digunakan untuk membantu baik si pembuat kotak hitam maupun penggunanya.
Pada akhirnya, kotak hitam tersebut akan digunakan dalam bermacam-macam situasi. Orang
yang membuat kotak hitam ini tidak perlu mengerti bagaimana kotaknya akan digunakan.
Pembuatnya hanya menjamin bahwa kotak yang dibuat harus bekerja sesuai dengan yang
diharapkan. Aturan ketiga dari kotak hitam :

Pembuat (implementor) kotak hitam tidak perlu tahu bagaimana kotak hitam itu akan
digunakan.

Dengan kata lain, kotak hitam membagi dunia menjadi 2 bagian, yaitu bagian luar, untuk apa ia
digunakan, dan bagian dalam, yaitu detail bagaimana ia bekerja.

Antar muka kotak hitam tidak melulu harus berupa koneksi fisik antara kotak hitam dengan
dunia luar. Antar muka bisa juga berupa spesifikasi yang menjelaskan apa yang dilakukan kotak
hitam tersebut, dan perilakunya terhadap input yang diterimanya. Tidak cukup untuk
menyebutkan bahwa TV membutuhkan colokan kabel, tetapi harus disebutkan bahwa colokan
kabel digunakan untuk menyambung aliran listrik ke TV supaya TV bisa dinyalakan.

Dalam bahasa pemrograman, antar muka dari suatu subrutin harus terdiri dari komponen sintaks
dan semantik. Bagian sintaks dari subrutin mengandung penjelasan tentang apa yang harus
diketik untuk memanggil subrutin tersebut. Dan bagian semantik menjelaskan bagaimana secara
khusus apa yang akan dikerjakan oleh subrutin tersebut. Untuk menulis program yang benar, kita
harus mengetahui spesifikasi sintaks dari subrutin tersebut. Untuk mengerti dan bisa
menggunakan subrutin tersebut seefektif mungkin, kita harus mengetahui spesifikasi
semantiknya. Kedua bagian dari subrutin tersebut bisa disebut sebagai kontrak subrutin.

Kontrak subrutin bisa dijelaskan seperti "Ini yang harus Anda lakukan untuk menggunakan saya,
dan ini yang akan saya lakukan untuk Anda". Ketika kita menulis subrutin, komentar yang kita
tulis untuk menjelaskan subrutin itu harus memuat kontrak subrutin tersebut. Kadang kala
kontrak ini seringkali tidak dituliskan dengan benar, sehingga programmer yang
menggunakannya harus menerka apa yang akan dilakukan. Tentu saja ini tidak efisien dan
menghabiskan banyak waktu apabila kita harus menerka semua subrutin yang terdapat dalam
bahasa pemrograman.

Subrutin Statik dan Variabel Statik


Posted Min, 02/22/2009 - 22:44 by belajarprogram

Versi ramah cetak

Setiap subrutin yang dideklarasikan dalam Java harus dideklarasikan di dalam suatu Kelas
(Class). Hal ini mungkin membuat Java sedikit tidak normal, karena dalam bahasa pemrograman
lain, subrutin bisa diletakkan di mana saja termasuk di luar kelas. Salah satu dari fungsi kelas
adalah menggabungkan subrutin dan variabel bersama. Dan ini tidak mudah apabila subrutin dan
variabel berada di luar kelas, terutama apabila beberapa paket harus digabungkan menjadi satu
seperti dalam program kompleks. Akan terdapat banyak kebingungan yang mungkin diakibatkan
dari nama subrutin atau nama variabel yang sama.

Subrutin yang dideklarasikan di dalam kelas disebut dengan metode (method). Di bab kemudian
kita akan menggunakan istilah metode, tetapi bab ini kita akan menggunakan subrutin dalam
artiannya sebagai subrutin statik. Metode akan digunakan untuk subrutin non-statik yang lebih
merupakan sifat dari objek, dan bukan bagian dari kelas itu sendiri.

Definisi subrutin dalam bahasa pemrograman Java dapat dituliskan dalam bentuk

sifat tipe_keluaran nama_subrutin ( daftar parameter ) {


perintah
}

Kita sudah pernah mendefinisikan suatu subrutin, yaitu subrutin main(). Paling tidak kita sudah
kenal bagaimana subrutin didefinisikan.

perintah yang terdapat di antara { dan } disebut juga badan subrutin. Perintah ini merupakan
badan atau implementasi suatu subrutin, seperti yang dibahas sebelum pada penjelasan tentang
kotak hitam. Perintah ini merupakan instruksi yang akan dieksekusi oleh komputer pada saat
subrutin ini dipanggil.

sifat adalah sifat dari subrutin itu sendiri. Beberapa sifat yang pernah kita lihat adalah static
dan public. Ada lebih dari selusin sifat yang bisa diberikan kepada subrutin.

Jika kita akan membuat fungsi, yaitu subrutin yang menghitung suatu nilai kemudian
mengembalikan hasilnya, maka tipe_keluaran adalah tipe data dari keluaran yang dihasilkan
oleh fungsi tersebut. Kita akan membahas lebih lanjut tentang keluaran pada bagian berikutnya.
Jika subrutin kita bukan fungsi dan tidak menghasilkan nilai apa-apa, kita gunakan tipe data
spesial yang dinamakan void untuk menunjukkan bahwa tidak ada nilai keluaran yang akan
dikembalikan oleh subrutin tersebut.

Akhirnya kita sampai pada daftar parameter. Parameter adalah bagian dari antar muka suatu
subrutin. Parameter adalah informasi yang diberikan kepada suatu subrutin dari dunia luar, untuk
digunakan dalam eksekusi subrutin tersebut. Kasus sederhana misalnya televisi memiliki
subrutin gantiChannel(). Pertanyaan yang akan muncul adalah ganti channel ke mana? Dalam hal
ini parameter dapat digunakan, misalnya channel berbentuk bilangan bulat (int) dan deklarasi
subrutin gantiChannel dapat berbentuk seperti

public void gantiChannel(int channel) {


...
}

Pernyataan tersebut berarti subrutin gantiChannel() memiliki parameter channel yang bertipe int.
Akan tetapi channel belum memiliki nilai. Nilainya akan diberikan pada saat subrutin ini
dipanggil, misalnya dengan
gantiChannel(17);

Daftar parameter dari suatu subrutin bisa juga kosong, atau bisa berisi lebih dari satu parameter
dalam bentuk

tipe_data nama_parameter

Jika ada lebih dari satu parameter, maka parameter-perameter tersebut dihubungkan dengan
koma. Catatan bahwa masing-masing parameter harus terdiri dari satu tipe data dan satu nama,
misalnya double x, double y dan bukan double x, y.

Parameter akan dijelaskan lebih lanjut pada bagian berikutnya.

Berikut ini adalah beberapa contoh deklarasi subrutin yang umum dilakukan :

public static void mainGame() {


// "public" dan "static" ada sifat; "void" adalah tipe_keluaran
// "mainGame" adalah nama subrutin
// daftar parameternya kosong
... // perintah untuk memainkan game ditulis di bagian ini
}
 
int ambilNdata(int N) {
// tidak ada sifat, "int" adalah tipe_keluaran
// "ambilNdata" adalah nama subrutin
// dan parameternya adalah N yang memiliki tipe data int
... // perintah untuk mengambil N data ditulis di bagian ini
}
 
static boolean kurangDari(double x, double y) {
// "static" adalah sifat, "boolean" adalah tipe_keluaran
// "kurangDari" adalah nama subrutin
// parameternya ada 2, yaitu x yang bertipe data double
// dan y yang juga bertipe data double
.... // perintah untuk menguji apakah x lebih kecil dari y ditulis di
sini
}

Dalam contoh kedua perhatikan bahwa sifatnya tidak "static", dan subrutin ini tidak dibahas
dalam bagian ini. Subrutin pertama memiliki sifat "public" yang artinya subrutin ini dapat
dipanggil dari bagian manapun, termasuk dari luar kelas yang dimaksud.

Ada lagi sifat subrutin yaitu "private" yang berarti hanya bisa dipanggil dari dalam kelas di mana
subrutin tersebut didefinisikan. Sifat "public" dan "private" dinamakan penentu akses (access
specifier). Jika tidak disebutkan jenis aksesnya dalam suatu definisi subrutin, maka otomatis
subrutin itu memiliki sifat "package" yang artinya hanya bisa dipanggil dari paket yang sama
dari kelas di mana ia didefinisikan. Sifat lain yang berkaitan dengan penentu akses adalah
"protected" dan ini akan dibahas lebih lanjut pada bagian tentang pemrograman berorientasi
objek.
Ingatkah bahwa subrutin main() yang biasa kita gunakan dalam contoh-contoh program
memiliki bentuk seperti berikut ?

public static main(String[] args) { ... }

Sifatnya adalah "public" dan "static", namanya adalah "main" dan parameternya adalah args
yang bertipe data array dari String. Kita akan bahas tentang array pada bagian struktur data di
bab berikutnya.

Menjalankan subrutin

Ketika kita mendefinisikan subrutin, pada dasarnya kita memberitahu Java bahwa suatu subrutin
tersedia dalam suatu kelas. Subrutin tersebut tidak dijalankan sampai ia dipanggil. (Hal ini juga
berlaku untuk kelas main(), meskipun kita tinggal memanggilnya secara spesifik, tetapi sistem
operasi kita akan memanggil subrutin main() pada saat program tersebut dijalankan.) Misalnya
subrutin mainGame() di atas dapat dipanggil seperti

mainGame();

Pernyataan ini dapat dipanggil di mana pun dalam kelas yang sama, meskipun dari dalam
subrutin yang berbeda, misalnya dari dalam subrutin main(). Karena mainGame() bersifat
"public", maka subrutin ini dapat juga dipanggil dari luar kelas di mana ia dideklarasikan.
Misalnya, mainGame() dideklarasikan dalam kelas Gundu, maka mainGame dapat dipanggil dari
kelas lain seperti

Gundu.mainGame();

Penggunaan nama kelas di sini berarti memberitahu Java di mana subrutin mainGame() harus
dicari (dalam hal ini di dalam kelas Gundu). Dan ini juga membedakan bahwa yang dimainkan
adalah Gundu, bukan Catur.mainGame() atau UlarTangga.mainGame().

Lebih umum, untuk memanggil suatu subrutin dapat dilakukan dengan bentuk

nama_subrutin(parameter);

Dan untuk memanggil subrutin dari luar kelas, bisa dilakukan dalam bentuk

nama_kelas.nama_subrutin(parameter);

apabila subrutin tersebut memiliki sifat "static". Apabila subrutin tersebut tidak bersifat "statik"
maka nama_kelas harus diganti dengan nama objek jelmaan kelas tersebut. (Akan dijelaskan
lebih jauh nanti pada bab tentang pemrograman berorientasi objek).

Juga, apabila tidak ada parameter yang didefinisikan, maka parameter bisa dihilangkan, tetapi
tanda kurungnya () harus tetap ada meskipun kosong.

Variabel Statik
Suatu kelas juga bisa berisi lain hal selain subrutin, misalnya variabel. Variabel juga bisa
didefinisikan di dalam subrutin, yang disebut variabel lokal. Untuk membedakannya variabel
yang didefinisikan di dalam kelas disebut variabel anggota, karena variabel tersebut adalah
anggota kelas.

Seperti subrutin, variabel juga bisa bersifat statik atau non-statik. Di bagian ini kita hanya akan
membahas variabel statik. Variabel anggota statik dimiliki oleh kelas, dan akan selalu ada selama
kelas tersebut ada. Komputer akan menyiapkan memori tempat penyimpanan variabel statik pada
saat Java interpreter dijalankan.

Perubahan variabel statik ini akan mengubah isi memori tersebut, tidak peduli dari bagian
program mana perubahan variabel ini dilakukan. Kapanpun variabel ini dipanggil, ia akan
mengambil data dari memori di mana dia disimpan, tidak peduli bagian program mana yang
memanggilnya. Ini berarti variabel statik bisa diisi dari subrutin satu dan dimodifikasi dari
subrutin lainnya. Atau dengan kata lain, variabel statik digunakan bersama oleh seluruh bagian
kelas. Variabel lokal hanya bisa dipanggil dari dalam subrutin di mana ia dideklarasikan.

Deklarasi variabel anggota dapat dilakukan dengan cara yang sama seperti deklarasi variabel
dalam subrutin. Kecuali, mereka juga bisa diberi attribut yang berisi sifatnya, misalnya "static",
"public", atau "private". Misalnya,

static int umur;


static private double x;

Seperti halnya penentu akses pada subrutin, variabel yang bersifat "private" hanya bisa diakses
dari dalam kelas yang bersangkutan, sedangkan variabel "public" dapat diakses dari manapun.
Misalnya, kelas System, memiliki variabel out, sehingga bisa kita panggil dari luar dengan
System.out.

Ketika kita mendeklarasikan suatu variabel di dalam subrutin, kita harus memberi nilai awal
untuk variabel tersebut. Akan tetapi untuk variabel anggota, Java otomatis memberi nilai awal,
sehingga tidak perlu diinisialisasi terlebih dahulu. Misalnya int akan diberi nilai awal 0, karakter
diberi nilai yang berupa karakter dengan nilai Unicode 0, dan String diberi nilai awal null,
sementara boolean diberi nilai awal false.

Kita tentu saja bisa memberi nilai awal apabila nilai awal yang diberi Java tidak cocok dengan
aplikasi kita. Caranya misalnya dengan memberi nilai di awal subrutin main().

Contoh Subrutin - Mengubah Program RataRata


Posted Sen, 02/23/2009 - 23:46 by belajarprogram

Versi ramah cetak

Kita mulai dengan program RataRata yang kita bahasa pada bagian tentang while dan do ...
while.
Perhatikan bahwa di dalam program tersebut kita harus menulis berulang-ulang untuk
mendapatkan input data dari user. Sekarang kita akan pisahkan kode untuk mengambil input dari
user dalam kelas yang dinamakan KonsolInput.

Pertama-tama buat project baru di Eclipse yang dinamakan RataRata2. Caranya "File -> New ->
Java Project" kemudian masukkan RataRata2.

Kemudian buat kelas baru yang dinamakan KonsolInput. "File -> New -> Class", masukkan
package ratarata2 dan Name KonsolInput seperti gambar berikut :

Kita akan membuat subrutin statik yang dinamakan ambilDouble() yang tugasnya memberi
pertanyaan kepada user, mengambil input dari user dan mengubah input dari user menjadi
bilangan real (tipe data double).

Kita bisa definisikan subrutin ini dengan

public static double ambilDouble(String pertanyaan) { ... }

"public" dan "static" adalah sifat subrutin ini, "double" merupakan tipe data keluarannya karena
kita ingin subrutin ini mengembalikan input bertipe double sehingga siap untuk digunakan.
"ambilDouble" adalah nama subrutin ini, dan "String pertanyaan" adalah parameternya yaitu
berupa pertanyaan yang diberikan kepada user pada saat data akan diambil.

Apa yang harus dilakukan sekarang? Kita ambil perintah untuk mengambil data dari RataRata
yaitu :

double bilangan = 0;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String strbilangan = null;
 
System.out.print("Masukkan bilangan pertama : ");
try {
strbilangan = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
 
// mengubah input menjadi double agar bisa diproses lebih lanjut
bilangan = Double.parseDouble(strbilangan);

Ingat bahwa parameter "String pertanyaan" adalah pertanyaan yang akan kita ajukan kepada
user, sehingga baris

System.out.print("Masukkan bilangan pertama : ");

kita ganti dengan

System.out.print(pertanyaan);

Kita akan kembalikan "bilangan" kepada si pemanggil, sehingga di akhir subrutin kita beri
perintah

return bilangan;

yang berarti kembalikan bilangan kepada si pemanggil fungsi ini.

Jangan lupa juga untuk menambahkan import java.io.*; di awal kelas karena
BufferedReader adalah anggota dari paket ini. Sekarang subrutin ambilDouble() menjadi seperti
ini

package ratarata2;
 
import java.io.*;
 
public class KonsolInput {
 
public static double ambilDouble(String pertanyaan) {
String strbilangan = null;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
double bilangan;
 
System.out.print(pertanyaan);
try {
strbilangan = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
 
bilangan = Double.parseDouble(strbilangan);
return bilangan;
}
 
}

Kemudian kita buat kelas baru yang dinamakan RataRata2, seperti pada gambar berikut :

Dengan menggunakan subrutin yang baru kita buat, kita modifikasi program RataRata menjadi
RataRata2 sebagai berikut :

package ratarata2;
 
public class RataRata2 {
 
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
double jumlah = 0;
double bilangan = 0;
int n = 0;
 
bilangan = KonsolInput.ambilDouble("Masukkan bilangan pertama : ");
 
while (bilangan != 0) {
jumlah += bilangan; // sama dengan : jumlah = jumlah +
bilangan
n++; // sama dengan : n = n+1
 
bilangan = KonsolInput.ambilDouble("Masukkan bilangan berikutnya
(atau 0 untuk mengakhiri) : ");
}
 
// hitung rata-rata
double ratarata = jumlah/n;
 
// cetak hasilnya ke layar
if (n == 0) {
System.out.println("Data kosong, rata-rata tidak bisa dihitung");
} else {
System.out.println("Anda memasukkan " + n + " data");
System.out.println("Rata-rata bilangan yang dimasukkan adalah " +
ratarata);
}
}
}

Perhatikan beberapa perubahan di dalam program ini. Pertama, kita hapus perintah-perintah
untuk mengambil input dari user karena sudah kita implementasikan pada subrutin
ambilDouble() di kelas KonsolInput.

Di kelas RataRata2, kita panggil subrutin ambilDouble() dengan perintah

bilangan = KonsolInput.ambilDouble("Masukkan bilangan pertama : ");

dan

bilangan = KonsolInput.ambilDouble("Masukkan bilangan berikutnya (atau


0 untuk mengakhiri) : ");

di mana parameternya adalah pertanyaan yang diberikan kepada user sebelum memasukkan data.
Hasil keluarannya sama dengan pada kelas RataRata

Program di atas dapat diunduh dalam bentuk zip file atau melalui gudang SVN di alamat :
http://belajarjava.googlecode.com/svn/trunk/RataRata2

Contoh Program Subrutin dan Variabel Statik


Posted Sel, 02/24/2009 - 15:51 by belajarprogram

Versi ramah cetak

Mari kita lihat kembali dan kita akan ubah program MainSuit pada halaman ini.

Pertama-tama kita akan ubah algoritma untuk menentukan siapa yang menang. Dalam program
sebelumnya, kita gunakan pernyataan switch case, yaitu kita tuliskan semua kemungkinan dalam
permainan.

Jika Anda ingat, Jempol dilambangkan dengan 0, Telunjuk dilambangkan dengan 1, dan
Kelingking dilambangkan dengan 2. Cara lain untuk menentukan pemenangnya adalah dengan
mengurangi suitKomputer dan suitUser

delta = suitKomputer - suitUser;

Apabila delta = 0, maka permainan berakhir seri. Sekarang coba masukkan apabila komputer 0
(Jempol) dan user 1 (Telunjuk). Dalam hal ini delta bernilai -1, dan ini berarti komputer menang.
Dengan kata lain, apabila delta bernilai -1 maka komputer menang, dan apabila delta bernilai 1,
maka user menang.

Coba lagi juga komputer 0 (Jempol) dan user 2 (Kelingking). Dalam hal ini delta -2, dan ini
berarti user menang sesuai dengan aturan bahwa Kelingking menang melawan Jempol.

Dengan sifat seperti di atas, kita bisa ubah pernyataan switch case pada program sebelumnya
dengan

// menghitung siapa yang menang


int delta = suitKomputer - suitUser;
 
switch (delta) {
case 0:
seri++;
System.out.println("Hasilnya : Seri");
break;
case 1:
case -2:
userMenang++;
System.out.println("Hasilnya : Anda menang");
break;
case -1:
case 2:
komputerMenang++;
System.out.println("Hasilnya : Anda kalah");
break;
}

Kemudian, kita tambahkan lagi variabel statik yang fungsinya digunakan untuk mendata berapa
kali komputer menang, berapa kali Anda menang dan berapa kali seri.

public static int userMenang = 0;


public static int komputerMenang = 0;
public static int seri = 0;

Kemudian kita akan pindahkan sebagian kode pada subrutin main sehingga dapat dipanggil
berkali-kali tanpa harus menulis seluruh kode lagi. Kita namakan subrutin ini mainGame().

Kodenya sebagai berikut :

public static int userMenang = 0;


public static int komputerMenang = 0;
public static int seri = 0;
 
public static void mainGame() {
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
// variabel untuk mengambil input dari user
String input = null;
 
// Kita gunakan pernyataan while hingga user betul
// memasukkan salah satu dari J, T, atau K
boolean inputvalid = false;
 
int suitKomputer = 0;
int suitUser = 0;
 
// selama input tidak valid, jalankan perulangan ini
while (!inputvalid) {
System.out.print("Masukkan suit Anda ");
try {
input = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
 
// pastikan bahwa user memasukkan sesuatu dengan mengecek
// apakah panjang input > 0
// jika tidak, maka perulangan akan dilanjutkan
if (input.length() > 0) {
switch (input.charAt(0)) {
case 'j' :
case 'J' :
suitUser = 0;
inputvalid = true; // kita ganti inputvalid agar
perulangan selesai
break;
case 't' :
case 'T' :
suitUser = 1;
inputvalid = true; // kita ganti inputvalid agar
perulangan selesai
break;
case 'k' :
case 'K' :
suitUser = 2;
inputvalid = true; // kita ganti inputvalid agar
perulangan selesai
break;
}
}
}
 
// sekarang menghitung suit komputer
// Math.random() menghasilkan nilai acak antara 0 dan 1
// jika kita kali 3, berarti menghasilkan nilai acak antara 0 dan 3
// perintah (int) untuk mengubah bilangan real menjadi bilangan bulat
// dengan cara menghilangkan semua digit di belakang koma
// misalnya 1.0232323 menjadi 1
suitKomputer = (int)(Math.random()*3);
 
// suatu saat "mungkin" nilai random bernilai 3
// karena 3 tidak ada dalam suit kita, maka kita harus ubah menjadi
// salah satu suit yang valid, yaitu 0, 1, atau 2
// dalam hal ini kita ganti jadi 2
if (suitKomputer == 3) {
suitKomputer = 2;
}
 
// menghitung siapa yang menang
int delta = suitKomputer - suitUser;
 
switch (delta) {
case 0:
seri++;
System.out.println("Hasilnya : Seri");
break;
case 1:
case -2:
userMenang++;
System.out.println("Hasilnya : Anda menang");
break;
case -1:
case 2:
komputerMenang++;
System.out.println("Hasilnya : Anda kalah");
break;
}
}

Sekarang kita ubah subrutin main()-nya, sehingga komputer akan menanyakan Anda untuk main
lagi atau tidak. Jika jawabannya ya, maka permainan akan diteruskan, dan statistik menang-
kalah-seri akan ditampilkan. Jika tidak, hanya tampilkan statistiknya saja, kemudian program
akan keluar.

public static void main(String[] args) {


// TODO Auto-generated method stub
 
// cetak aturan main dan input dari user
System.out.println("Permainan suit");
System.out.println("==============");
System.out.println("Masukkan salah satu dari 3 kemungkinan :");
System.out.println("J untuk Jempol");
System.out.println("T untuk Telunjuk");
System.out.println("K untuk Kelingking");
System.out.println(""); // baris kosong
 
while (true) {
mainGame();
 
// tampilkan statistik
System.out.println("Statistik :");
System.out.println("Komputer = " + komputerMenang + " Anda = "
+ userMenang + " Seri = " + seri);
System.out.println(""); // baris kosong
 
// variabel untuk mengambil input dari user
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String input = null;
 
System.out.print("Main lagi (Y/T) ? ");
try {
input = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
 
// keluar jika jawabannya tidak
if ((input.charAt(0) == 't') || (input.charAt(0) == 'T'))
break;
}
}
Berikut ini hasil keluarannya

Dan program tersebut dapat Anda unduh dalam bentuk zip file atau melalui gudang SVN di
alamat : http://belajarjava.googlecode.com/svn/trunk/MainSuitSubrutin>

Parameter
Posted Sel, 02/24/2009 - 19:12 by belajarprogram

Versi ramah cetak

Jika subrutin adalah kotak hitam, maka parameter merupakan alat atau mekanisme untuk
memberikan informasi dari dunia luar ke dalam kotak. Parameter merupakan bagian dari antar
muka dengan suatu subrutin. Dengan menggunakan parameter, kita dapat mengatur perilaku
suatu subrutin sesuai dengan input yang diberikan.

Sebagai analogi, kita ambil contoh AC -- yaitu alat yang mengatur suhu ruangan pada temperatur
konstan. AC memiliki parameter, yaitu tombol remote yang digunakan untuk memasukkan suhu
yang diinginkan. AC akan selalu melakukan tugas yang sama, yaitu mengatur suhu ruangan.
Akan tetapi, tugas persis yang dilakukan tergantung suhu yang diterima dari remote control.
Kita ambil contoh pada kelas KonsolInput pada bagian terdahulu.

public static double ambilDouble(String pertanyaan) {


String strbilangan = null;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
double bilangan;
 
System.out.print(pertanyaan);
try {
strbilangan = br.readLine();
} catch (IOException ioe) {
System.out.println("Kesalahan IO, program berhenti");
System.exit(1);
}
 
bilangan = Double.parseDouble(strbilangan);
return bilangan;
}

Di sini subrutin ambilDouble memiliki parameter tunggal yang bertipe String dan bernama
pertanyaan. Ketika subrutin ini dipanggil, suatu nilai harus ikut disertakan, dan nilai ini
dimasukkan dalam parameter "pertanyaan". Misalnya, subrutin dapat dipanggil dengan a =
ambilDouble("hallo");. Ketika komputer menjalankan perintah ini, komputer akan
memasukkan "hallo" ke dalam parameter "pertanyaan", kemudian subrutin ambilDouble
menjalankan semua perintah di dalamnya.

Jika parameter yang diberikan berupa variabel, misalnya variabel str berisi "kabar", kemudian
subrutin ambilDouble panggil dengan perintah ambilDouble(str), maka isi dari str akan dikopi
ke dalam parameter "pertanyaan" terlebih dahulu sebelum seluruh perintah dalam subrutin
ambilDouble dilaksanakan.

Perlu dicatat bahwa istilah "parameter" digunakan dalam dua konsep berbeda tetapi berkaitan.
Yang pertama adalah "parameter" digunakan untuk mendefinisikan suatu subrutin. Parameter
yang digunakan pada definisi suatu subrutin disebut parameter formal. "Parameter" yang
digunakan untuk memanggil suatu subrutin disebut parameter aktual. Ketika suatu subrutin
dipanggil, parameter aktual akan dievaluasi, dan hasilnya akan dimasukkan ke dalam parameter
formal.

Parameter formal berbentuk seperti pengenal atau nama, dan bersifat seperti halnya variabel dan
memiliki tipe -- misalnya int, double, atau String. Parameter aktual bersifat seperti nilai atau
angka, jadi bisa berbentuk ekspresi atau perintah apapun yang menghasilkan nilai atau angka.
Sewaktu kita memanggil subrutin, kita harus memberi parameter aktual untuk setiap parameter
formal yang didefinisikan.

Misalnya, lihat contoh berikut.

static void lakukanSesuatu(int N, double d, boolean b) {


... // perintah lainnya di sini
}
Subrutin ini bisa saja dipanggil dengan instruksi berikut.

lakukanSesuatu(1, Math.random() * 3, x == 3);

Ketika komputer mengevaluasi subrutin ini, pada dasarnya sama dengan menglakukan perintah-
perintah berikut.

{
int N;
double d;
boolean b;
 
N = 1;
d = Math.random() * 3;
b = (x == 3);
... // perintah lainnya di sini
}

Untuk memanggil subrutin, yang kita perlukan adalah nama, berapa banyak parameter formal
yang dimilikinya, dan tipe dari parameter formal tersebut. Infomasi ini disebut juga tanda
subrutin. Tanda subrutin lakukanSesuatu dapat ditulis sebagai
lakukanSesuatu(int,double,boolean). Perhatikan bahwa tanda subrutin tidak memiliki nama
parameter; sebetulnya jika kita hanya ingin menggunakan subrutin tersebut, nama parameter
tidaklah penting, karena nama bukan merupakan bagian dari antar muka subrutin.

Java agak sedikit berbeda karena memungkinkan dua atau lebih subrutin yang berbeda dalam
kelas yang sama memiliki tanda subrutin yang berbeda. (Mirip seperti bahasa C++) Subrutin
yang seperti ini disebut subrutin yang dibebanlebihkan (overloaded). Misalnya,

void taruh(String s) { ... }


void taruh(int i) { ... }
void taruh(double d) { ... }
void taruh(boolean b) { ... }

Kita sudah menggunakan subrutin yang dibebanlebihkan ini misalnya pada System.out.println().
Jika kita coba ketik System.out.println pada Eclipse, Eclipse akan membantu kita untuk melihat
parameter apa saja yang dibutuhkan, termasuk juga dapat menunjukkan apakah suatu subrutin
dibebanlebihkan.
Catatan : Overload tidak berlaku pada tipe keluaran subrutin. Dua atau lebih subrutin dengan
nama sama dalam suatu kelas tetapi memiliki tipe keluaran yang berbeda tidak diperbolehkan
dalam Java. Misalnya, kalau kita coba definisikan 2 fungsi seperti berikut, maka Java akan
memberi pernyataan kesalahan sintaks.

int ambil(String s) { ... }


boolean ambil(String s) { ... }
double ambil(String s) { ... }

Terakhir, hingga saat ini kita sudah mengenal 3 jenis variabel: variabel lokal, yang didefinisikan
di dalam suatu blok, variabel statik, yang didefinisikan di dalam suatu kelas, dan parameter
formal, yang didefinisikan pada definisi subrutin di dalam suatu kelas.

Variabel lokal tidak memiliki hubungan dengan dunia luar sama sekali. Parameter digunakan
untuk berhubungan dengan dunia luar sebagai alat untuk menerima nilai atau angka dari dunia
luar. Perubahan nilai pada variabel lokal dan parameter tidak mempengaruhi variabel itu sendiri
karena sifatnya terisolasi.

Hal yang sama sekali berbeda akan terjadi apabila suatu subrutin menggunakan variabel yang
didefinisikan di luar subrutin itu. Variabel tersebut hidup secara terpisah dari subrutin, dan bisa
diakses oleh apapun di luar subrutin itu. Variabel ini disebut variabel global. Variabel ini terlihat
oleh semua subrutin dalam kelas tersebut. Perubahan yang terjadi di sini dapat mempengaruhi
cara kerja subrutin lain yang menggunakan variabel tersebut.

Hal ini kita lihat pada contoh sebelumnya tentang subrutin dan variabel statik untuk menghitung
statistik komputerMenang, userMenang, dan seri.

Tidak ada yang salah dalam menggunakan variabel global, akan tetapi kita harus terus ingat
bahwa variabel global itu harus sebagai bagian dari antar muka subrutin kita dengan keseluruhan
dunia luar. Cara ini sebetulnya jalan belakang yang tidak terdokumentasi seperti pada definisi
subrutin, yang apabila aturan-aturannya tidak dipenuhi secara disiplin mungkin akan
menyebabkan bug atau kesalahan lain di luar kontrol kita.

Paling tidak ada satu alasan untuk menggunakan variabel global, yaitu apabila kelas secara
keseluruhan dianggap sebagai kotak hitam, akan lebih masuk akal apabila subrutin bisa
mengintip sedikit keluar dan saling menukar informasi jika cara ini jauh lebih mudah
diimplementasikan dan dilihat dari dunia luar.

Tipe Keluaran
Posted Rab, 02/25/2009 - 01:06 by belajarprogram

Versi ramah cetak

Suatu subrutin yang mengembalikan nilai disebut fungsi. Suatu fungsi hanya dapat
mengembalikan nilai dengan tipe tertentu, yang disebut tipe keluaran. Fungsi biasanya
dipanggil di tempat suatu nilai atau angka ditempatkan, misalnya disebelah kanan tanda =, pada
parameter sewaktu subrutin dipanggil, atau di tengah-tengah ekspresi yang panjang. Fungsi
dengan tipe keluaran boolean juga bisa ditempatkan sebagai kondisi pada pernyataan if atau
while.

Sebetulnya boleh-boleh saja memanggil suatu fungsi sendirian tanpa diletakkan di sebelah kanan
tanda =, misalnya ambilDouble("hallo");. Dalam hal ini keluarannya akan diabaikan oleh
komputer. Tergantung program yang akan kita buat, kadang-kadang program kita memang
sengaja membuang nilai yang dikembalikan oleh fungsi karena satu dan lain hal.

Untuk membuat fungsi yang mengeluarkan suatu nilai kembali kepada pemanggilnya, kita harus
memberikan pernyataan return, dengan bentuk

return ekspresi;

Pernyataan return ini hanya boleh ditulis di dalam sebuah subrutin (termasuk subrutin main()),
dan ekspresi harus menghasilkan nilai yang memiliki tipe yang sama dengan tipe keluaran yang
didefinisikan pada deklarasi subrutin tersebut.

Ketika komputer menjalankan pernyataan return, komputer akan menghitung "ekspresi",


menghentikan eksekusi subrutin tersebut saat itu juga, dan kembali pada si pemanggil dengan
membawa nilai hasil perhitungan "ekspresi".

Misalnya, kita akan menghitung luas suatu lingkaran. Kita buat fungsi luasLingkaran dengan
parameter jarijari dan keluarannya bertipe double, sebagai berikut :

static double luasLingkaran(double jarijari) {


return 3.14 * jarijari * jarijari;
}
Anggap komputer sedang melakukan perintah "ruangkosong = 20*20 -
luasLingkaran(10);". Ketika sampai pada bagian luasLingkaran, fungsi tersebut akan
memasukkan 10 ke dalam parameter formal jarijari. Di dalam badan fungsi, ia akan menghitung
3.14 * 10.0 * 10.0 yang hasilnya 314.0. Nilai ini akan dikembalikan kepada fungsi awalnya
untuk menghitung "ruangkosong = 20*20 - luasLingkaran(10);", sehingga fungsi ini juga
bisa diganti dengan "ruangkosong = 400 - 314.0;" Hasilnya yaitu 86 dimasukkan ke dalam
variabel ruangkosong

Dalam subrutin biasa -- yaitu subrutin yang tipe keluarannya void -- kita juga bisa menggunakan
perintah return untuk langsung keluar dari subrutin tersebut, yaitu dengan perintah return;
tanpa ekspresi. Di subrutin ini perintah return boleh diberikan jika diperlukan, akan tetapi pada
fungsi perintah return wajib diberikan.

Berikut ini adalah fungsi untuk menentukan nilai akhir (A, B, C, D atau E) dari nilai ujian.

static char nilaiAlfa(double nilaiUjian) {


if (nilaiUjian >= 90)
return 'A';
else if (nilaiUjian >= 80)
return 'B';
else if (nilaiUjian >= 70)
return 'C';
else if (nilaiUjian >= 60)
return 'D';
else
return 'E';
}

Perhatikan bahwa pada setiap cabang, perintah return diberikan. Ada juga beberapa programmer
yang lebih suka dengan menggunakan variabel sementara kemudian perintah return diberi satu
kali saja di akhir fungsi, seperti contoh berikut.

static char nilaiAlfa(double nilaiUjian) {


char keluaran;
if (nilaiUjian >= 90)
keluaran = 'A';
else if (nilaiUjian >= 80)
keluaran = 'B';
else if (nilaiUjian >= 70)
keluaran = 'C';
else if (nilaiUjian >= 60)
keluaran = 'D';
else
keluaran = 'E';
return keluaran;
}

Contoh di atas memiliki tipe keluaran char. Dan sebenarnya, tipe keluaran bisa bertipe apa saja,
termasuk kelas, seperti String pada contoh berikut.

static String ulangKarakter(char c, int n) {


String keluaran = "";
 
// tambah karakter c ke dalam String keluaran sebanyak n kali
for (int i = 1; i <= n; i++)
keluaran = keluaran + c;
 
return keluaran;
}

Fungsi di atas berfungsi untuk mengulang karakter c sebanyak n kali dan mengembalikan
hasilnya. Misalnya jika fungsi di atas kita panggil dengan "ulang = ulangKarakter('A',
10);" maka ulang akan bernilai "AAAAAAAAAA" setelah fungsi ulangKarakter dijalankan.

Toolbox, API, dan Paket


Posted Sab, 02/28/2009 - 04:05 by belajarprogram

Versi ramah cetak

Dengan semakin mudah digunakannya komputer, akan semakin sulit dan kompleks tugas yang
harus dilakukan oleh programmer. Kita dengan mudah menulis program berbasis konsol dengan
menggunakan beberapa subrutin untuk menampilkan pesan dan mengambil input dari user. GUI
(graphical user interface = antarmuka pengguna berbasis grafik), seperti jendela, tombol, scroll
bar, menu, kotak input teks, dan lain-lain mungkin lebih menarik bagi user. Akan tetapi
programmer harus berhadapan dengan kemungkinan yang sangat amat banyak, dan lebih banyak
subrutin yang harus dibuat untuk bisa mengontrol setiap komponen GUI.

Seseorang yang ingin membuat program untuk Windows misalnya, harus menggunakan Toolbox
Windows, yaitu koleksi dari ribuan subrutin, misalnya untuk membuka dan menutup jendela,
untuk menggambar dan menulis teks, menambah tombol dan menerima respon dari user. Selain
GUI ada juga subrutin yang berurusan dengan membuka, membaca, dan menulis file,
berkomunikasi dengan network, dan lain-lain. Intinya di dalam toolbox terdapat segala sesuatu
yang menurut kita standar. Apple dan Linux memiliki toolbox sendiri yang berbeda dengan yang
disediakan oleh Windows.

Setiap proyek pembuatan program akan terdiri dari inovasi (sesuatu yang sangat baru) dan
menggunakan kembali sesuatu yang sudah pernah dibuat sebelumnya. Seorang programmer
diberi peralatan untuk berhasil dalam proyeknya tersebut, yang paling dasar adalah apa yang
diberikan oleh bahasa pemrograman itu sendiri, misalnya variabel, perulangan, dan lain-lain. Di
atasnya, programmer bisa menambahkan toolbox yang berisi subrutin yang sudah ditulis untuk
melakukan tugas tertentu. Alat ini, jika didesain dengan sangat baik, bisa dijadikan kotak hitam
yang sesungguhnya, yaitu kotak hitam yang kita betul-betul tidak perlu tahu bagaimana dia
bekerja.

Bagian yang inovatif adalah bagaimana merangkai alat tadi menjadi sesuatu yang berguna untuk
suatu proyek atau suatu masalah yang ingin dipecahkan (pengolah kata, browser, game, dll). Ini
disebut pemrograman aplikasi.
Toolbox suatu software adalah juga kotak hitam. Ia memiliki antar muka dengan
programmernya. Antar muka ini berisi spesifikasi tentang rutin-rutin apa saja yang ada di sana,
apa parameter yang dibutuhkan, dan tugas apa yang mereka lakukan. Informasi ini disebut API
(Applications Programming Interface = Antarmuka Pemrograman untuk Aplikasi). Windows
API adalah spesifikasi semua subrutin yang tersedia dalam toolbox Apple.

Perusahaan yang membuat hardware, misalnya sound card atau blue tooth mungkin juga akan
membuat API untuk perangkat tersebut yang berisi subrutin yang diperlukan programmer untuk
bisa menggunakan perangkat itu. Peneliti yang membuat program untuk menyelesaikan suatu
perhitungan matematis kompleks -- misalnya persamaan diferensial -- juga akan membuat API
sehingga orang lain bisa menggunakan subrutinnya tanpa harus mengerti dengan detail
bagaimana perhitungan itu dilakukan.

Bahasa pemrograman Java juga didukung oleh API yang cukup besar dan standar. Contoh API
yang pernah kita lihat misalnya Math.random(), tipe data String, dan subrutin yang terkait. Java
API standar terdiri dari subrutin untuk membuat dan mengendalikan GUI, untuk komunikasi
network, baca tulis file, dan lain-lain. Mungkin lebih mudah jika API ini dianggap sebagai
bagian dari bahasa Java, akan tetapi sebetulnya API terdiri dari subrutin yang bisa digunakan
dalam program Java.

Java merupakan bahasa yang tidak tergantung pada mesin atau sistem operasi di mana ia
dijalankan. Java API yang sama harus bisa bekerja dengan semua sistem. Akan tetapi ingat
bahwa yang sama adalah antar mukanya. Implementasinya bisa sangat berbeda antara satu sistem
operasi dengan lainnya.

Sistem Java pada suatu komputer terdiri dari implementasi pada komputer tersebut. Program
Java yang kita buat memanggil subrutin pada komputer tersebut. Ketika komputer menjalankan
program dan sampai pada perintah untuk memanggil subrutin pada API, komputer akan
menjalankan implementasi subrutin yang sesuai dengan sistem komputer di mana program
tersebut dijalankan. Artinya, kita hanya perlu belajar satu API saja untuk melakukan
pemrograman pada berbagai macam komputer dan sistem operasi.

Seperti subrutin pada Java, subrutin pada API standar dikelompokkan ke dalam kelas. Untuk
membuat organisasi lebih baik, kelas Java dapat digabungkan menjadi paket. Kita juga bisa
membuat hirarki paket yang lebih tinggi, karena paket juga bisa berisi paket lain. Kenyataannya
seluruh API standar Java diimplementasikan dalam beberapa paket. Salah satu paketnya bernama
"java", yang berisi paket-paket non-GUI dan juga GUI berbasis AWT. Paket lain, yaitu
"javax", yang ditambahkan pada versi 1.2, berisi kelas yang digunakan untuk GUI Swing.

Suatu paket dapat terdiri dari kelas ataupun pake lain. Paket yang terdapat di dalam paket lain
disebut "sub paket". Paket java dan javax juga memiliki beberapa sub paket. Salah satu sub
paket java, misalnya disebut awt. Karena awt berada di dalam paket java, nama lengkapnya
adalah java.awt. Paket inilah yang sebenarnya memiliki kelas-kelas GUI AWT, seperti kelas
Button yang melambangkan tombol, atau Graphics yang merupakan kumpulan rutin untuk
menggambar di monitor. Karena kelas ini tergabung dalam paket java.awt, maka nama
lengkapnya adalah java.awt.Button dan java.awt.Graphics. Demikian juga dengan javax
yang memiliki sub paket yang bernama javax.swing, yang terdiri dari kelas yang bernama
javax.swing.JButton dan javax.swing.JApplet.

Paket java sendiri terdiri dari beberapa sub paket lain, seperti java.io yang sudah kita pakai
dalam bab-bab sebelumnya, berguna untuk memberikan fasilitas input/output, java.net untuk
mengendalikan komunikasi jaringan, dan java.applet mengimplementasikan fungsi dasar
untuk applet. Paket yang paling dasar disebut java.lang. Di dalam paket ini terdapat kelas-kelas
fundamental misalnya String dan Math.

Mungkin akan lebih jelas jika kita lihat ilustrasi berikut tentang tingkatan paket java, sub paket,
kelas di dalam sub paket, dan subrutin di dalam kelas.

Misalkan kita akan menggunakan kelas java.awt.Color dalam program. Salah satu caranya
adalah dengan menggunakan nama lengkap dari kelas tersebut, misalnya

java.awt.Color warnaKotak;

untuk mendekalarasi variabel bernama warnaKotak yang tipenya adalah java.awt.Color. Tentu
saja akan terlalu cape jika kita harus menulis nama kelas dengan lengkap setiap kali akan
digunakan. Java mengijinkan kita untuk menggunakan langsung nama kelasnya jika kita berikan
perintah import, seperti

import java.awt.Color;

di awal program, dan kemudian di bagian lain, kita bisa menyingkat java.awt.Color hanya
dengan nama kelasnya saja, sehingga menjadi

Color warnaKotak;

(Satu-satunya keuntungan yang diberikan perintah import adalah untuk menyingkat penulisan
nama kelas, bukan untuk mengimport keseluruhan kelas ke dalam program kita. Seandainya
perintah import tidak kita berikan, dan kita panggil dengan nama lengkapnya, Java akan tetap
bisa mengakses kelas tersebut.)

Ada lagi jalan pendek untuk mengimport seluruh kelas pada suatu paket. Kita bisa import
seluruh kelas di dalam paket java.awt dengan

import java.awt.*;

Ingat pada kode kita sebelumnya yang berbentuk seperti ini?

import java.io.*;

Ketika program yang akan kita buat semakin besar, maka ada kemungkinan kita harus
mengimport banyak paket. Satu hal penting yang perlu diingat adalah ada kemungkinan
beberapa paket memiliki nama kelas yang sama. Misalnya java.awt dan java.util memiliki
kelas yang bernama List. Jika kita import kedua kelas dengan perintah java.awt.* dan
java.util.*, maka nama List menjadi rancu.

Jika kita mencoba membuat variabel dengan tipe data List, java akan menampilkan pesan
kesalahan tentang adanya nama kelas yang membingungkan. Solusinya? Gunakan nama lengkap
kelasnya, yaitu java.awt.List atau java.util.List.

Karena paket java.lang.* adalah paket yang sangat penting, setiap kelas dalam java.lang
akan diimport otomatis ke dalam semua program. Seakan-akan semua program dimulai dengan
perintah "import java.lang.*;". Artinya, kita bisa memanggil kelas seperti String saja, bukan
java.lang.String, atau Math.sqrt() bukan java.lang.Math.sqrt().

Programmer juga bisa membuat paket baru. Misalnya kita akan membuat kelas yang akan
diletakkan di paket yang bernama alatbantu. Maka pada awal program kita harus didefinisikan
dengan perintah "package alatbantu;" Program lain yang menggunakan paket ini bisa
menambah "import alatbantu.*;" untuk mengabmbil semua kelas dalam paket alatbantu.

Masalahnya hal ini agak sedikit lebih rumit. Ingat bahwa ketika suatu program menggunakan
kelas, maka kelas tersebut harus "tersedia" ketika program tersebut dikompilasi dan ketika
program terus dieksekusi. Tentunya lebih pas tergantung dari lingkungan Java yang kita lakukan.
biasanya paket yang bernama alatbantu harus berada di dalam direktori alatbantu, dan direktori
tersebut harus diletakkan pada direktori yang sama dengan program yang akan menggunakan
kelas itu.

Pada program yang menggunakan banyak kelas, maka sangat masuk akal apabila kita membagi
dan mengorganisir kelas tersebut dalam satu atau beberapa paket. Dan juga masuk akal untuk
membuat paket baru sebagai toolbox atau dengan kata lain membuat API baru yang belum
dikover oleh API Java. (Seringkali orang yang membuat API lebih disanjung akan kehebatannya
dibandingkan dengan orang yang hanya menggunakan API).
Dalam program Eclipse kita, kita sudah menggunakan paket dari awal. Bab ini menjelaskan lebih
detail tentang paket. Sebetulnya tidak ada salahnya kita mengorganisir setiap program yang kita
buat sejak awal. Pada saat program kita besar, maka perubahan yang diperlukan untuk
mengorganisir akan lebih signifikan.

Tentang Deklarasi
Posted Min, 03/01/2009 - 15:45 by belajarprogram

Versi ramah cetak

Nama adalah hal yang paling dasar dalam pemrograman. Banyak sekali tetek bengek detail di
dalam deklarasi dan menggunakan nama. Dalam bagian ini akan kita singgung beberapa hal
penting tentang deklarasi dan penggunaan variabel pada Java.

Menggabungkan Inisialisasi dan Deklarasi

Ketika perintah deklarasi variabel dilaksanakan, komputer akan menyiapkan memori untuk
digunakan oleh variabel ini. Memori ini harus diinisialisasi, yaitu diberi suatu nilai awal sebelum
bisa digunakan dalam perintah berikutnya. Pada variabel lokal, pernyataan deklarasi sering
diikuti oleh perintah pemberi nilai awal. Misalnya,

int i; // Deklarasi variabel yang bernama i


i = 0; // Beri nilai awal

Kita bisa juga melakukan deklarasi sekaligus inisialisasi variabel tersebut. Kedua pernyataan di
atas bisa kita gabung menjadi

int i = 0; // Deklarasi variabel i sekaligus memberi nilai awal 0

Komputer akan tetap melakukan perintah di atas dalam dua langkah: deklarasi variabel,
kemudian mengisi nilai awal 0. Nilai awal tidak harus berupa suatu bilangan, tetapi bisa juga
berupa ekspresi yang menghasilkan suatu nilai. Dan juga kita boleh melakukan inisialisasi
beberapa variabel sekaligus dalam 1 baris. Misalnya,

int x = 0, y = 1;
int awal, akhir = 'A'; // Ok, tapi hanya akhir yang akan diinisialisasi
int N = 3, M = N+2; // Ok, karena N sudah diberi nilai awal sebelum
digunakan oleh M

Fitur ini biasa ditemui pada perulangan for, karena pernyataan 1 baris ini bisa dimasukkan
sebagai variabel kontrol di awal pernyataan for. Karena variabel kontrol biasanya tidak
berhubungan dengan bagian program di luar perulangan, maka akan lebih praktis jika deklarasi
variabel kontrol itu dilakukan di awal perulangan. Misalnya

for ( int i = 0; i < 10; i++ ) {


System.out.println(i);
}
Perlu diingat bahwa ekspresi di atas merupakan singkatan dari blok berikut. Saya sengaja
tambahkan { dan } di awal dan akhir untuk mempertegas bahwa i hanya bersifat lokal di dalam
perulangan yang tidak bisa diakses lagi setelah perulangan selesai.

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

Variabel anggota juga bisa diinisialisasi di mana dia dideklarasikan. Misalnya,

public class Bank {


static double sukuBunga = 0.1; // sama dengan 10%
static long maxPenarikan = 2000000;
.
. // Perintah dan variabel lain
.
}

Variabel anggota statik akan dibuat pada saat kelas mulai dimasukkan memori oleh interpreter
Java, inisialisinya pun dilaksanakan pada saat itu. Pada variabel anggota, deklarasi dan
inisialisasi ini bukan hanya sekedar singkatan dari 2 perintah seperti pada variabel lokal.
Pernyataan deklarasi adalah pernyataan yang bisa dibuat di luar subrutin, sedangkan inisialisasi
tidak bisa dilakukan di luar subrutin. Contoh di bawah tidak diperbolehkan dalam Java.

public class Bank {


static double sukuBunga;
sukuBunga = 0.1; // ILEGAL, perintah ini harus ada di dalam
subrutin
}

Karenanya, deklarasi variabel anggota biasanya juga dirangkai dengan inisialisasi nilai awalnya.
Jika tidak ada nilai awal yang diberikan, maka nilai awal bawaan akan digunakan. Misalnya
"static int i;" setara dengan "static int i = 0;".

Konstanta dan Sifat "final"

Kadang-kadang dalam kondisi tertentu, kita ingin nilai suatu variabel tidak boleh berubah setelah
diberi nilai awal. Misalnya, pi diinisialisasi dengan nilai 3.14159, maka nilai ini akan bisa diubah
oleh bagian lain dalam program. Di sini mungkin sang programmer ingin mendefinisikan suatu
konstanta yang diberi nama "pi" sebagai pengganti dari bilangan 3.14159.

Dengan cara ini, program akan lebih mudah dimengerti apabila program tersebut ditulis dalam
"keliling = pi*diamater;" daripada "pokok = 3.14159*diameter;".

Dalam java, sifat "final" bisa digunakan pada deklarasi variabel untuk membuat nilai suatu
variabel tidak bisa diubah setelah diinisialisasi. Misalnya
final static double pi = 3.14159;

Apabila kita mencoba mengganti isi variabel tersebut, misalnya di tengah program dengan
perintah "pi = 20;" komputer akan menampilkan pesan kesalahan sintaks pada saat kompilasi.

Sifat "final" boleh diberikan pada variabel lokal dan bahkan pada parameter formal, akan tetapi
paling berguna apabila diberikan pada variabel anggota. Variabel anggota statik yang
dideklarasikan dengan sifat "final" juga disebut sebagai konstanta yang diberi nama.

Program akan jauh lebih mudah dibaca dengan menggunakan konstanta bernama ini jika
diberikan pada sesuatu angka penting yang digunakan dalam program. Gaya penulisan yang
dianjurkan untuk konstanta bernama ini adalah dengan menggunakan huruf besar dengan baris
bawah (jika diperlukan). Misalnya

final static double PI = 3.14159;

Gaya penulisan seperti ini juga digunakan oleh kelas standar Java, yang di dalamnya terdapat
banyak sekali konstanta bernama. Misalnya, konstanta PI sudah didefinisikan Java dalam kelas
Math, yaitu Math.PI, sehingga kita tidak perlu mendefinisikannya sendiri.

Contoh lain adalah memberikan nama untuk gaya huruf, seperti Font.PLAIN, Font.BOLD dan
Font.ITALIC. Konstanta ini digunakan untuk menandai gaya huruf untuk digunakan oleh
subrutin lain dalam kelas Font.

Salah satu alasan utama untuk menggunakan konstanta bernama adalah supaya kita bisa
mengubah isinya dengan cepat apabila di kemudian hari kita ingin memiliki nilai konstanta yang
berbeda. Apabila nilai ini diubah, maka kita harus mengkompilasi ulang program kita, karena
nilai ini tidak bisa diubah ketika program dieksekusi.

Misalnya kita definisikan sukuBunga pada contoh di atas sebagai konstanta bernama, yaitu

static final double SUKU_BUNGA = 0.1;

Suatu saat misalnya 2 tahun kemudian, bank tersebut ingin mengubah suku bunganya menjadi
5% atau 0.05. Kita bisa mengubah nilainya hanya di satu tempat yaitu di mana deklarasi
SUKU_BUNGA berada. Kita tidak perlu mencari semua nilai 0.1 di dalam program untuk
menggantinya satu per satu. Selain repot, mungkin membingungkan karena 0.1 bisa digunakan
untuk nilai lainnya, bukan hanya nilai suku bunga.

Aturan Penamaan dan Jangkauan (scope)

Ketika deklarasi variabel dieksekusi, komputer akan menyediakan tempat di memori untuk
variabel tersebut. Nama variabel dapat digunakan oleh kode program untuk mengacu pada
alamat di mana data tersebut disimpan di dalam memori. Bagian di dalam kode sumber (yaitu
program Java yang kita tulis, masih dalam bentuk yang dimengerti manusia sebelum dikompilasi
menjadi bahasa mesin) di mana variabel tersebut valid dan bisa digunakan disebut jangkauan
variabel. Bukan hanya variabel yang memiliki jangkauan, tetapi juga nama subrutin dan nama
parameter formal.

Untuk subrutin statik, jangkauannya lebih mudah dipahami. Jangkauan subrutin statik adalah
kelas di mana ia didefinisikan. Kita bisa juga memanggil subrutin itu dari dalam kelas dirinya
sendiri. Dalam pemrograman tingkat lanjut, teknik ini disebut rekursi (recursion), yaitu subrutin
yang memanggil dirinya sendiri. Teknik ini digunakan dalam bab yang akan datang yang
berbicara detail tentang struktur data dan algoritma.

Untuk variabel anggota suatu kelas, aturannya sama, tetapi dengan sedikit pengecualian. Kita
boleh memiliki variabel lokal atau parameter formal yang namanya sama dengan variabel
anggota static. Jika ini terjadi, maka variabel anggota akan disembunyikan oleh Java. Dalam
contoh berikut :

public class Game {


static int hitung; // variabel anggota
static void mainGame() {
int hitung; // variabel lokal
.
. // Perintah untuk main game
.
}
.
. // Variabel dan subrutin lain
.
 
} // akhir kelas Game

Kita lihat bahwa dalam subrutin mainGame(), "hitung" mengacu pada dua hal yaitu variabel
lokal dan variabel anggota statik. Di luar kelas Game, "hitung" hanya mengacu pada variabel
anggota statik. Dalam situasi seperti ini, di dalam subrutin mainGame() maka "hitung" sebagai
variabel anggota akan disembunyikan oleh Java. Untuk menggunakan variabel anggota ini, kita
bisa menggunakan nama lengkapnya yaitu Game.hitung. Akan tetapi trik ini tidak bisa
digunakan untuk variabel anggota yang tidak statik.

Jangkauan parameter formal di dalam suatu subrutin berada di dalam blok di mana ia
dideklarasikan. Sehingga pada "for (int i=0; i<10; i++)" variabel i hanya bisa di lihat di
dalam blok perulangan for, tetapi tidak valid di luar perulangan ini meskipun pada subrutin yang
sama.

Akan tetapi kita tidak boleh mendeklarasikan parameter formal dengan nama yang sama dengan
variabel lokal yang berlaku di sana. Misalnya,

void subrutinJelek(int y) {
int x;
while (y > 0) {
int x; // ERROR: x sudah didefinisikan sebelumnya
.
.
.
}
}

Dalam bahasa pemrograman lain, pernyataan di atas masih dibolehkan, yaitu dengan
menyembunyikan x pada deklarasi sebelumnya. Akan tetapi pada Java, segera setelah blok yang
memuat suatu variabel selesai, namanya bisa dipergunakan kembali. Misalnya.

void subrutinBagus(int y) {
while (y > 10) {
int x;
.
.
.
// Jangkauan x berakhir di sini
}
while (y > 0) {
int x; // OK: Deklarasi x sebelumnya sudah kadaluarsa
.
.
.
}
}

Ada beberapa hal lain yang menarik di Java. Nama subrutin dan variabel boleh sama, karena
komputer akan selalu dapat membedakan mana subrutin atau variabel dengan melihat tanda buka
kurung '(' setelah namanya. Variabel tidak pernah menggunakan tanda kurung setelah namanya.
Sehingga suatu kelas boleh memiliki variabel anggota yang bernama "hitung" dan subrutin yang
bernama "hitung()".

Lebih jauh lagi, nama suatu kelas boleh menggunakan nama subrutin atau variabel yang sudah
ada. Komputer bisa melihat apakah suatu nama berupa kelas, variabel atau subrutin. Kelas adalah
juga tipe data, sehingga suatu kelas bisa digunakan untuk mendeklarasikan variabel dengan tipe
kelas tersebut, atau membuat subrutin yang keluarannya bertipe kelas tersebut.

Atau sebagai contoh, perintah berikut bisa diterima oleh program Java :

static Gila Gila(Gila Gila) {


.
.
.
}

Gila pertama adalah tipe keluaran suatu fungsi. Gila kedua adalah nama subrutin. Yang ketiga
adalah tipe data parameter, dan keempat adalah nama parameter formal.

Tetapi, ingat tidak semua yang mungkin dan boleh dilakukan berarti harus dilakukan.

Lihat lebih jelas di sini : !newsletter_url


Bab VI - Pemrograman Berorientasi Objek
Posted Min, 03/01/2009 - 16:13 by belajarprogram

Versi ramah cetak

Jika subrutin hanya melambangkan suatu tugas, objek merupakan gabungan data (dalam bentuk
variabel instansi - atau "instance variable") dan beberapa tugas atau disebut "perilaku"
terhadap kumpulan data tersebut (dalam bentuk metode instansi - atau "instance method"). Oleh
karena itu objek merupakan stuktur baru yang dapat menangani semakin rumitnya kompleksitas
suatu program

Bagian ini meliputi pembuatan dan penggunaan objek dalam bahasa Java. Juga akan dibahas inti
tentang pemrograman berorientasi objek, yaitu : pewarisan dan poli morfisme (perubahan
wujud).

 Objek, Metode Instansi dan Variable Instansi


 Konstruktor dan Inisialisasi Objek
 Pemulung Memori (Garbage Collector)
 Pewarisan, Polimorfisme, dan Kelas Abstrak
 this dan super
 Antar Muka (interface), Kelas Bertingkat, dan Detail Lain

Objek, Metode Instansi dan Variable Instansi


Posted Sen, 03/02/2009 - 18:42 by belajarprogram

Versi ramah cetak

Pemrograman berorientasi objek bermaksud untuk memecahkan masalah programming mirip


dengan cara berfikir manusia dan bagaimana manusia berinteraksi dengan dunia. Kita telah
melihat bagaimana masalah programming dipecahkan dengan membaginya menjadi instruksi-
instruksi kecil yang dirangkai menjadi suatu kesatuan tugas. Cara ini disebut juga dengan
pemrograman berdasarkan prosedur.

Pada pemrograman berorientasi objek, kita membagi masalah pemrograman berdasarkan objek
atau "sesuatu" benda. Objek ini diibaratkan seperti makhluk hidup, yaitu memiliki ciri-ciri fisik
dan juga perilaku. Dalam pemrograman berorientasi objek, ciri-ciri fisik ini disebut juga sebagai
atribut, pada dasarnya berisi informasi tentang objek tersebut. Sedangkan perilaku disebut
sebagai metode, yaitu bagaimana suatu objek bertindak atau melakukan sesuatu.

Dengan cara ini diharapkan pemrograman berorientasi objek merupakan pemrograman yang
lebih alami dibandingkan dengan pemrograman berorientasi prosedur, karena cara fikir kita
sudah terbiasa dengan bagaimana kita berinteraksi dengan dunia.
Sampai tingkat tertentu, PBO hanya merubah cara pandang programmer. Objek dalam kaitannya
dengan dasar pemrograman adalah gabungan dari variabel (dalam hal ini atribut) dan subrutin
(yaitu metode) yang berinteraksi dengan variabel pada objek.

Banyak bahasa pemrograman lain yang juga mendukung konsep PBO, akan tetapi Java
merupakan bahasa yang mendukung penuh PBO, di antaranya karena Java memiliki beberapa
fitur penting yang berbeda dari bahasa standar. Untuk menggunakan fitur ini, kita harus
mengubah cara pandang kita terlebih dahulu.

Objek terkait erat dengan kelas. Kita telah bahas dan mencoba beberapa contoh kelas pada bab-
bab sebelumnya. Seperti kita lihat pula bahwa kelas memiliki variabel dan subrutin.

Jika objek juga memiliki variabel dan subrutin, lalu apa bedanya dengan kelas? Lalu mengapa
kita harus memiliki cara pandang berbeda dengan cara kita melihat kelas? Sepertinya apabila kita
lihat contoh-contohnya sebelumnya, perbedaannya hanya menghilangkan kata "static" dari
deklarasi variabel dan subrutinnya, khan?

Seperti disebutkan sebelumnya bahwa kelas mendeskripsikan suatu objek, atau lebih tepatnya,
bagian non "static" mendeskripsikan suatu objek. Mungkin bahasa biologi, kelas adalah
species, sedangkan objek merupakan individu. Human sapiens (nama biologi manusia) adalah
kelas, sedangkan Anda, saya, ibu, bapak, pak hansip adalah objek. Masing-masing dari kita
memiliki "blueprint" atau cetak biru yang sama, tetapi kita memiliki ciri-ciri yang berbeda,
rambut, mata, telinga, tinggi badan, berat badan, dan juga perilaku kita saat makan, minum,
belajar, dan lain-lain.

Dalam sudut pandang pemrograman, kelas digunakan untuk menciptakan suatu objek. Atau
dengan kata lain, kelas adalah pabrik pembuat objek. Bagian non-statik dari suatu kelas adalah
bagian yang memuat detail suatu objek, yaitu apa isi variabel dan metodenya. Perbedaan kelas
dan objek adalah : Objek diciptakan dan dihancurkan ketika program berjalan, sehingga kita bisa
memiliki beberapa objek sekaligus.

Kita lihat contoh sederhana, dimana kelas sederhana digunakan untuk menggabungkan beberapa
variabel statik. Misalnya

class DataPenduduk {
static String nama;
static int umur;
}

Pada program yang menggunakan kelas ini, hanya ada satu kopi dari setiap variabel
DataPenduduk.nama dan DataPenduduk.umur. Hanya akan ada satu penduduk, karena kita
menyimpan data tersebut sebagai data statik, yang artinya hanya satu tempat di memori di mana
data tersebut disimpan. Kelas DataPenduduk dan variabel isinya akan ada selama program
tersebut berjalan.

Sekarang kita lihat kode berikut yang memiliki variabel non-statik:


class DataPenduduk {
String nama;
int umur;
}

Dalam hal ini tidak ada lagi yang variabel DataPenduduk.nama dan DataPenduduk.umur, karena
nama dan umur bukan anggota statik kelas DataPenduduk. Jadi, tidak ada yang bisa kita lakukan
dengan kelas ini sama sekali, kecuali membuat objek dari kelas ini.

Setiap objek akan memiliki variable sendiri yang dinamakan "nama" dan "umur". Kita bisa
membuat banyak "penduduk" karena kita bisa membuat objek untuk setiap penduduk. Misalnya
setiap kali seseorang dilahirkan, kita bisa membuat objek penduduk baru. Atau jika seseorang
meninggal dunia, kita bisa hapus objek tersebut.

Suatu sistem yang terdiri dari kumpulan objek digunakan untuk memodelkan apa yang terjadi di
alam nyata. Kita tidak bisa membuat beberapa objek dengan menggunakan variabel statik.

Contoh lainnya adalah pada GUI. Bayangkan kita memiliki beberapa tombol, misalnya tombol
OK, Cancel dan Apply. Masing-masing tombol ini memiliki kelas yang sama akan tetapi apa
yang dilakukan tombol ini berbeda-beda. Teks yang ditampilkan (OK, Cancel atau Apply)
merupakan variabel masing-masing objek.

Suatu objek yang diciptakan dari suatu kelas disebut instansi dari kelas tersebut. Variabel yang
dimiliki oleh objek disebut variabel instansi. Sedangkan subrutinnya disebut . (Dalam PBO
subrutin disebut metode)

Misalnya dalam kelas DataPenduduk di atas, kemudian kita buat suatu objek dari kelas ini, maka
objek yang diciptakan disebut instansi dari kelas DataPenduduk, "nama" dan "umur" adalah
variabel instansi di dalam objek tersebut.

Penting untuk diingat bahwa kelas suatu objek menentukan tipe data dari variabel instansi, akan
tetapi isi datanya sendiri tidak disimpan di dalam kelas, akan tetapi di dalam objek yang
diciptakan, sehingga setiap objek akan memiliki data masing-masing.

Begitu juga dengan metode instansi, misalnya pada kelas tombol, kita memiliki metode yang
dinamakan klik(). Masing-masing tombol akan melakukan tugas berbeda-beda tergantung dari
objeknya.

Seperti kita lihat di sini bahwa bagian statik dan non-statik dari suatu kelas merupakan hal yang
sama sekali berbeda. Banyak kelas yang hanya memiliki anggota statik, atau hanya memiliki
anggota non-statik. Akan tetapi kita juga bisa mencampur keduanya dalam suatu kelas. Variabel
anggota statik suatu kelas juga bisa disebut variabel kelas dan metode anggota statik suatu kelas
juga bisa disebut metode kelas, karena mereka adalah milik kelas dan bukan milik objek yang
diciptakan dari suatu kelas.

Sekarang kita gunakan contoh yang lebih real. Kita akan buat versi sederhana dari kelas Murid,
dimana kita akan menyimpan informasi tentang murid yang terdaftar pada suatu sekolah.
class Murid {
String nama ; // nama murid
double nilai1, nilai2, nilai3; // nilai ulangan murid tersebut
double hitungRataRata() { // hitung rata-rata nilai ulangan
return (nilai1 + nilai2 + nilai3) / 3;
}
}

Kita lihat bahwa semua anggota kelas tersebut bukan anggota statik, artinya kelas ini hanya bisa
digunakan untuk membuat objek. Definisi kelas ini artinya bahwa di dalam objek yang akan
diciptakan, akan ada variabel instansi yang bernama nama, nilai1, nilai2, dan nilai3, dan
juga metode instansi yang bernama hitungRataRata(). Setiap murid memiliki nilai rata-rata
yang berbeda-beda. (Makanya ini disebut perilaku suatu objek berbeda-beda).

Dalam Java, kelas merupakan tipe data, yaitu mirip dengan tipe data bawaan seperti int atau
boolean. Jadi nama kelas bisa digunakan untuk menentukan tipe suatu variabel dalam deklarasi
pernyataan, dalam parameter formal dan juga dalam tipe keluaran suatu fungsi. Misalnya,
program mendefinisikan seorang murid dengan pernyataan seperti :

Murid amir;

Akan tetapi membuat variabel seperti di atas TIDAK menciptakan objek. Initinya, ini adalah hal
Yang Sangat Amat Penting :

Dalam Java, tidak ada variabel yang bisa menyimpan objek. Variabel hanya bisa
menyimpan referensi (alamat di memori) suatu objek. Komputer akan menggunakan
referensi ini untuk mencari objek di dalam memori.

Objek diciptakan dengan pernyataan new, yang bertugas menciptakan objek kemudian
mengembalikan referensi ke objek yang sudah diciptakan. Misalnya amir adalah variabel dengan
tipe Murid seperti dideklarasikan di atas, maka pernyataan berikut :

amir = new Murid();

akan membuat objek yang merupakan instansi dari kelas Murid. Variabel amir akan menyimpan
referensi ke objek yang baru saja diciptakan.

Sekarang anggap variabel amir merujuk pada objek yang diciptakan dari kelas Murid. Dalam
objek tersebut terdapat variabel nama, nilai1, nilai2, dan nilai3. Variabel instansi ini bisa
dipanggil dengan amir.nama, amir.nilai1, amir.nilai2, dan amir.nilai3. (Ingat aturan
penulisan nama lengkap, akan tetapi karena kelas ini tidak memiliki anggota statik, dan hanya
objek yang diciptakan dari kelas ini memiliki variabel atau metode ini, maka nama lengkapnya
diturunkan dari nama objek yang memilikinya).

Misalnya, program berikut :

System.out.println("Hai, " + amir.nama + " . Nilai Anda adalah : ");


System.out.println(amir.nilai1);
System.out.println(amir.nilai2);
System.out.println(amir.nilai3);

Program di atas akan mencetak nama dan nilai-nilai yang disimpan oleh objek amir. Begitu juga
kita bisa menghitung rata-rata pada suatu objek dengan menggunakan amir.hitungRataRata().
Sehingga untuk menghitung rata-rata murid tersebut, bisa kita perintahkan dengan:

System.out.println("Nilai rata-rata Anda adalah : " + amir.hitungRataRata());

Lebih umum lagi, kita bisa menggunakan amir.nama seperti layaknya variabel bertipe String,
artinya kita bisa menghitung jumlah karakter dengan menggunakan amir.nama.length().

Kita juga bisa membuat variabel seperti amir untuk tidak menunjuk atau memiliki referensi ke
obek mana pun. Dalam hal ini kita sebut bahwa objek amir berisi referensi kosong (null
reference). Referensi kosong ini ditulis dalam Java dengan ekspresi "null". Dan kita bisa
menyimpan nilai "null" pada variabel amir dengan perintah :

amir = null;

Dan kita juga bisa uji apakah amir berisi referensi kosong dengan perintah

if (amir == null) . . .

Jika suatu variabel berisi referensi kosong, maka tentu saja, kita tidak bisa mengambil variabel
instansi dan menjalankan metode instansi, karena tidak ada objek yang dirujuk pada variabel
tersebut. Misalnya jika variabel amir berisi null, maka kita tidak bisa mengambil variabel
amir.nilai1.

Jika program kita mencoba mengakses referensi kosong secara ilegal, maka di tengah-tengah
jalannya program, program akan menampilkan pesan kesalahan "null pointer exception".

Mari kita lihat beberapa pernyataan yang bisa digunakan dengan objek :

Murid mrd1, mrd2, mrd3, mrd4; // mendeklarasikan 4 variabel yang bertipe


Murid
mrd1 = new Murid(); // membuat objek baru dari kelas Murid,
kemudian menyimpan referensinya pada variabel mrd1
mrd2 = new Murid(); // membuat objek baru dari kelas Murid,
kemudian menyimpan referensinya pada variabel mrd2
mrd3 = mrd1; // menkopi „referensi" yang disimpan pada
mrd1 ke mrd3
mrd4 = null; // menyimpan referensi kosong ke mrd4
 
mrd1.nama = "Ahmad Surahmat"; // mengisi nilai variabel instansi
mrd2.nama = "Hamid Samsudin";

Setelah komputer menjalankan program tersebut, maka kira-kira memori komputer akan tampak
seperti gambar berikut :
Gambar tersebut menunjukkan variabel dalam kotak-kotak kecil dengan nama variabelnya.
Objek ditunjukkan dalam kotak dengan pojok bulat. Ketika suatu variabel berisi referensi ke
suatu objek, maka nilainya adalah seperti panah yang menunjuk pada objek tersebut.

Variabel mrd4 bernilai null, sehingga tidak menunjuk ke mana-mana. Panah dari mrd1 dan
mrd3 menjunjuk pada objek ang sama. Ini merupakan Hal Yang Sangat Penting :

Jika isi variabel suatu objek diberikan kepada variabel yang lain, maka yang dikopi hanya
referensinya saja. Isi objek tidak pernah dikopi.

Ketika pernyataan "mrd3 = mrd1;" dieksekusi, tidak ada objek baru yang dibuat. Akan tetapi
mrd3 akan merujuk pada alamat yang sama seperti mrd1. Konsekuensinya mungkin sedikit
mengejutkan. Misalnya variabel mrd1.nama dan mrd3.nama menunjuk pada variabel yang persis
sama, maka apabila mrd1.nama disi dengan "Juju Juminten", maka mrd3.nama juga berisi "Juju
Juminten".

Sekali lagi, variabel tidak berisi objek, akan tetapi berisi referensi ke suatu objek.

Kita bisa menguji beberapa objek dengan operator == dan != untuk menguji kesamaan dan
ketidaksamaan. Akan tetapi yang dicek lagi-lagi bukan isi objek, melainkan alamat memori
dimana objek tersebut dijadikan referensi. Jika alamat referensi di memori sama, artinya kedua
objek tersebut merujuk pada alamat memori yang sama. Ini berarti perubahan yang dilakukan
pada variabel yang satu akan ikut mempengaruhi variabel yang lain.

Untuk menguji isinya, maka isinya harus dibandingkan satu per satu, yaitu misalnya dengan
"mrd3.nilai1 == mrd1.nilai1 && mrd3.nilai2 == mrd1.nilai2 && mrd3.nilai3 ==
mrd1.nilai3 && mrd3.nama.equals(mrd1.nama)"

Seperti telah disebutkan sebelumnya bahwa String juga merupakan objek. Sehingga
membandingkan String yang satu dengan String yang lain dengan menggunakan tanda == adalah
membandingkan apakah alamat memori yang ditunjuk oleh String yang satu sama dengan alamat
memori yang ditunjuk oleh String yang lain. Ingat == pada objek bukan membandingkan isi
objek, tetapi membandingkan alamat memori yang ditunjuk oleh variabel tersebut. Untuk
membandingkan isi String, kita dapat menggunakan String.equals() di mana parameternya
adalah objek String yang akan dibandingkan. Metode ini akan membandingkan karakter per
karakter dari kedua String.

Misalnya, variabel salam berisi String "Selamat". Untuk menguji apakah variabel salam berisi
"Selamat", bisa kita gunakan perintah

salam.equals("Selamat")

Konsekuensi lainnya adalah apabila suatu variabel merujuk pada objek yang dideklarasikan
sebagai final. Ini berarti nilai variabel itu tidak bisa berubah setelah diinisialisasi, sedangkan isi
variabel itu adalah rujukan ke alamat memori tempat objek berada. Dengan demikian variabel
tersebut akan selalu menunjuk pada alamat memori yang sama. Akan tetapi hal ini tidak berlaku
untuk objek itu sendiri. Apabila ada variabel lain yang tidak "final" tetapi menunjuk pada
alamat memori yang sama, kemudian variabel ini mengubah isi objek tersebut, maka isi objek
tersebut bisa berubah.

Kita boleh saja untuk menulis perintah sebagai berikut.

final Murid mrd = new Murid();


murid.nama = "Ahmad Basir";

Perhatikan pada kode di atas bahwa isi objek bisa diubah. Akan tetapi jika kita mencoba menulis
seperti ini

Murid mrd99 = new Murid();


mrd = mrd99; // ILEGAL, karena mrd adalah variabel final

Konstruktor dan Inisialisasi Objek


Posted Sel, 03/03/2009 - 19:34 by belajarprogram

Versi ramah cetak


Kelas pada Java memiliki sifat yang sama sekali berbeda dengan tipe data primitif lainnya,
seperti int atau boolean. Seperti disebutkan pada bagian sebelumnya, mendeklarasikan suatu
variabel dengan tipe suatu kelas tidak berarti membuat objek dari kelas tersebut. Objek tersebut
harus dibuat (constructed). Pada saat objek dibuat, komputer akan mencari tempat yang tidak
dipakai pada memori heap untuk menempatkan objek tersebut, kemudian mengisi objek itu
dengan variabel instansi. Sebagai programmer, kita tidak peduli dengan bagaimana suatu objek
disimpan, akan tetapi kita ingin mengatur supaya nilai yang disimpan pada saat objek tersebut
dibuat sesuai dengan keinginan kita. Dalam beberapa kasus, kita bahkan ingin suatu objek
melakukan tugas tertentu untuk pertama kali begitu ia diciptakan.

Variabel instansi dapat diisi dengan nilai awal pada saat ia dideklarasikan, seperti variabel
lainnya. Misalnya, kelas berikut yang bernama PasanganDadu, yang melambangkan sepasang
dadu. Kelas ini memiliki dua variabel instansi yang melambangkan nilai yang ditunjukkan oleh
masing-masing dadu dan metode instansi untuk mengocok dadu, yaitu :

class PasanganDadu {
public int dadu1 = 3; // Angka pada dadu pertama
public int dadu2 = 4; // Angka pada dadu kedua
public void kocok() {
// Kocok dadu dengan menggunakan bilangan acak antara 1 dan 6
dadu1 = (int)(Math.random()*6) + 1;
dadu2 = (int)(Math.random()*6) + 1;
}
} // akhir kelas PasanganDadu

Variabel instansi dadu1 dan dadu2 diisi dengan nilai awal 3 dan 4. Inisialisasi ini dilakukan
setiap kali objek PasanganDadu dibuat. Ingat bahwa kelas PasanganDadu hanya 1, akan tetapi
kita bisa membuat banyak objek dari kelas ini. Setiap kali objek dibuat, objek tersebut memiliki
tempat di memori sendiri, yang disebut dengan instansi objek tersebut. Perintah "dadu1 = 3"
dan "dadu2 = 4" akan dieksekusi setiap kali objek dibuat.

Kita bisa memodifikasi kelas PasanganDadu dengan nilai awal acak, bukan 3 dan 4 misalnya,
dengan potongan kode berikut :

class PasanganDadu {
public int dadu1 = (int)(Math.random()*6) + 1; // Angka pada dadu pertama
public int dadu2 = (int)(Math.random()*6) + 1; // Angka pada dadu kedua
 
public void kocok() {
// Kocok dadu dengan menggunakan bilangan acak antara 1 dan 6
dadu1 = (int)(Math.random()*6) + 1;
dadu2 = (int)(Math.random()*6) + 1;
}
} // akhir kelas PasanganDadu

Karena inisialisasi dilakukan setiap kali objek dibuat, maka setiap objek akan memiliki nilai
yang berbeda-beda hasil dari instruksi Math.random() pada inisialisasi variabel instansi. Untuk
inisialisasi variabel static, hal ini tidak mungkin dilakukan, karena hanya ada 1 variabel statik
untuk 1 kelas, tidak peduli berapa pun banyaknya objek yang dibuat.
Jika variabel instansi tidak kita beri nilai awal, maka nilai bawaan akan diberikan secara
otomatis. Tipe data numerik (int, double, dll) memiliki nilai bawaan 0; boolean bernilai awal
false; dan char bernilai awal karakter dengan kode Unicode 0. Variabel instansi juga bisa bertipe
suatu objek. Dalam hal ini, variabel tersebut bernilai awal null. (Ingat bahwa String adalah objek,
sehingga nilai awalnya adalah null).

Objek dibuat dengan operator new, misalnya program yang ingin menggunakan objek
PasanganDadu dapat menggunakan perintah berikut :

// deklarasi variabel dan pembuatan objek dilakukan sekaligus


PasanganDadu dadu = new PasanganDadu();

Pada contoh di atas, new PasanganDadu() adalah perintah untuk membuat objek,
meletakkannya di memori dan menyimpan alamat objek ini di memori pada variabel dadu.
Bagian ekspresi PasanganDadu() mirip seperti memanggil subrutin. Sebetulnya itulah yang
terjadi, yaitu program memanggil subrutin spesial yang dinamakan konstruktor (constructor).
Mungkin Anda heran karena kita tidak melihat adanya subrutin bernama PasanganDadu(). Akan
tetapi semua kelas memiliki konstruktor, yang jika kita tidak buat secara khusus, Java akan
menambahkannya secara otomatis, yang disebut konstruktor bawaan.

Konstruktor bawaan melakukan hal-hal umum seperti mengalokasi memori, mengisi nilai
variabel instansi dengan nilai bawaannya, dan mengembalikan alamat objek yang dibuat di
memori. Jika kita menginginkan hal lain yang ikut dilaksanakan ketika suatu objek dibuat, maka
kita harus membuat konstruktor sendiri.

Bagaimana cara mendefinisikan konstruktor? Konstruktor dideklarasikan mirip dengan deklarasi


subrutin, dengan 3 perkecualian. Konstruktor tidak memiliki tipe keluaran (void pun tidak
dibolehkan. Namanya harus sama dengan nama kelas di mana ia dideklarasikan. Sifat yang bisa
digunakan hanya sifat akses, yaitu public, private, dan protected (static tidak diperbolehkan).

Di lain pihak, konstruktor memiliki blok yang terdiri dari kumpulan perintah seperti pada
subrutin. Kita bisa menggunakan perintah apapun seperti pada subrutin biasa, termasuk memiliki
satu atau lebih parameter formal. Sebetulnya salah satu alasan untuk menggunakan parameter
adalah kita bisa membuat beberapa konstruktor yang menerima data dalam berbagai bentuk,
sehingga objek yang kita buat bisa dinisialisasi dengan cara yang berbeda-beda sesuai dengan
kondisi dan kebutuhan dari program yang akan kita buat.

Misalnya, kelas PasanganDadu di atas kita ubah sehingga kita bisa memberi nilai awal sendiri.
Dalam hal ini kita buat konstruktor yang menerima 2 nilai sebagai nilai awal dadu, yaitu nilai1
dan nilai2.

class PasanganDadu {
public int dadu1; // Angka pada dadu pertama
public int dadu2; // Angka pada dadu kedua
 
public PasanganDadu(int nilai1, int nilai2) {
// Konstruktor, mengambil nilai1 dan nilai2 sebagai nilai awal untuk
dadu1 dan dadu2
dadu1 = nilai1;
dadu2 = nilai2;
}
 
public void kocok() {
// Kocok dadu dengan menggunakan bilangan acak antara 1 dan 6
dadu1 = (int)(Math.random()*6) + 1;
dadu2 = (int)(Math.random()*6) + 1;
}
} // akhir kelas PasanganDadu

Konstruktor dideklarasikan dalam bentuk "public PasanganDadu(int nilai1, int nilai2) ...", tanpa
tipe keluaran dan dengan nama yang sama dengan nama kelas. Ini adalah cara Java mengenal
suatu konstruktor dan membedakannya dengan subrutin biasa. Konstruktor ini memiliki 2
parameter yang harus diisi ketika konstruktor dipanggil. Misalnya,

PasanganDadu dadu = new PasanganDadu(1,2);

Membuat objek baru yang variabel intansinya dadu1 dan dadu2 bernilai 1 dan 2.

Karena sekarang kita telah membuat konstruktor, kita tidak bisa lagi membuat objek dengan
perintah "new PasanganDadu()". Java akan membuat konstruktor bawaan apabila tidak ada
satupun konstruktor yang didefinisikan. Akan tetapi, kita bisa membuat konstruktor lain di kelas
tersebut, karena suatu kelas bisa terdiri dari beberapa konstruktor asalkan parameternya berbeda.

Sekarang kita akan modifikasi lagi kelas tersebut dengan 2 konstruktor, yang mana apabila tidak
ada parameter yang diberikan, maka objek tersebut akan mengisi nilai dadu1 dan dadu2 dengan
bilangan acak.

class PasanganDadu {
public int dadu1; // Angka pada dadu pertama
public int dadu2; // Angka pada dadu kedua
 
public PasanganDadu() {
// Isi dadu1 dan dadu2 dengan bilangan acak, dengan memanggil metode
// kocok()
kocok();
}
 
public PasanganDadu(int nilai1, int nilai2) {
// Konstruktor, mengambil nilai1 dan nilai2 sebagai nilai awal untuk
// dadu1 dan dadu2
dadu1 = nilai1;
dadu2 = nilai2;
}
 
public void kocok() {
// Kocok dadu dengan menggunakan bilangan acak antara 1 dan 6
dadu1 = (int) (Math.random() * 6) + 1;
dadu2 = (int) (Math.random() * 6) + 1;
}
} // akhir kelas PasanganDadu
Sekarang kita bisa memilih bagaimana membuat objek, yaitu dengan "new PasanganDadu()"
atau dengan "new PasanganDadu(x,y)", di mana x dan y adalah ekpresi bernilai int.

Kelas ini, bisa digunakan dalam program lain yang membutuhkan sepasang dadu. Program
tersebut tidak lagi harus memanggil fungsi

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

karena perintah ini sudah diimplementasikan di dalam kelas PasanganDadu. Bagi programmer,
teknik seperti ini mempermudah pemecahan masalah dengan mengelompokkannya menjadi ciri
dan perilaku suatu objek.

Berikut ini adalah contoh program lain yang menggunakan objek PasanganDadu() untuk
menghitung berapa kali kocok akan menghasilkan jumlah nilai yang sama. Program lengkapnya
bisa diunduh di sini untuk diimport ke dalam Eclipse.

public class KocokDuaPasangDadu {


 
/**
* @param args
*/
public static void main(String[] args) {
PasanganDadu daduPertama = new PasanganDadu(); // pasangan dadu
pertama
PasanganDadu daduKedua = new PasanganDadu(); // pasangan dadu kedua
 
int jumlahKocokan; // untuk mengitung berapa kali dua pasang dadu
// tersebut dikocok
int total1; // hitung berapa kali dadu pertama muncul
int total2; // hitung berapa kali dadu kedua muncul
 
jumlahKocokan = 0;
do {
daduPertama.kocok(); // kocok dadu pertama
total1 = daduPertama.dadu1 + daduPertama.dadu2; // hitung
jumlahnya
System.out.println("Pasangan dadu pertama berjumlah " + total1);
 
daduKedua.kocok(); // kocok dadu pertama
total2 = daduKedua.dadu1 + daduKedua.dadu2; // hitung jumlahnya
System.out.println("Pasangan dadu pertama berjumlah " + total2);
 
jumlahKocokan++;
System.out.println(); // cetak baris kosong
 
} while (total1 != total2);
 
System.out.println("Butuh " + jumlahKocokan
+ " kocokan hingga pasangan "
+ " dadu pertama dan kedua berjumlah sama");
 
}
}
Keluarannya adalah sebagai berikut

Konstruktor adalah subrutin, tetapi bukan subrutin biasa, dan bukan metode instansi, karena
konstruktor tidak dimiliki oleh suatu objek. Karena tugasnya membuat objek, maka konstruktor
dijalankan sebelum objek dibuat. Konstruktor mirip dengan subrutin anggota statik, tetapi dia
tidak bisa dideklarasikan "static". Bahkan menurut spesifikasi Java, konstruktor bukan anggota
suatu kelas sama sekali.

Tidak seperti subrutin lain, konstruktor hanya bisa dipanggil melalui operator "new", dalam
bentuk

new nama_kelas(parameter);

di sini "parameter" boleh kosong. Hasil keluarannya adalah alamat memori di mana objek yang
baru dibuat tersebut disimpan. Seringkali, kita akan simpan hasil keluarannya di dalam suatu
variabel, atau bisa juga hasil keluarannya diberikan ke dalam suatu fungsi sebagai parameter.

Memanggil konstruktor lebih rumit daripada memanggil subrutin atau fungsi biasa. Hal-hal
berikut sangat membantu untuk lebih memahami apa yang dilakukan oleh konstruktor ketika ia
dipanggil untuk membuat suatu objek:
1. Pertama, komputer memberi daerah pada memori yang tidak digunakan, cukup untuk dipakai
oleh objek yang akan dibuat
2. Komputer akan mengisi variabel instansi objek tersebut dengan nilai bawaannya. Jika deklarasi
variabel instansi pada kelas memiliki nilai awal tertentu, maka nilai tersebut akan dimasukkan
sebagai nilai awalnya.
3. Parameter aktual pada konstruktor (jika ada) akan dievaluasi dan nilainya diberikan kepada
parameter formal konstruktor tersebut.
4. Perintah pada konstruktor (jika ada) akan dilaksanakan.
5. Referensi objek akan dikembalikan kepada si pemanggil.

Hasil keluarannya adalah referensi ke objek yang baru saja dibuat. Kita bisa gunakan referensi
ini untuk mengambil data pada variabel instansi objek tersebut atau memanggil metode
instansinya.

Contoh lain, mari kita ganti kelas Murid pada bagian sebelumnya. Kita akan tambahkan
konstruktor dan juga kita ganti variabel instansi "nama" menjadi bersifat privat.

class Murid {
private String nama; // Nama murid
public double nilai1, nilai2, nilai3; // Nilai-nilai ujian
 
Murid(String namaMurid) {
// Konstruktor objek Murid
nama = namaMurid;
}
 
public String getNama() {
// Metode untuk mengambil variabel anggota yang bersifat private
// misalnya variabel instansi nama
return nama;
}
 
public double hitungRataRata() {
// Hitung rata-rata ulangan
return (nilai1 + nilai2 + nilai3) / 3;
}
 
} // akhir kelas Murid

Objek bertipe Murid berisi informasi tentang murid tertentu. Konstruktor kelas ini memiliki
parameter bertipe String yaitu nama murid yang akan kita buat. Objek bertipe Murid ini bisa
dibuat dengan pernyataan seperti:

mrd1 = new Murid("Ahmad Surahmat");


mrd2 = new Murid("Hamid Samsudin")

Pada versi aslinya, isi variabel nama harus diisi dengan perintah terpisah setelah objek dibuat.
Masalahnya programmer tidak selalu ingat untuk mengisi nilai nama. Pada versi baru di atas,
setiap kali kita membuat objek, parameter namaMurid harus disertakan, karena ini dideklarasikan
pada konstruktornya. Dengan demikian potensi bug karena kelalaian programmer dapat
dihilangkan dengan mudah.
Contoh keamanan lainnya adalah dengan membuat variabel instansi nama bersifat private. Ini
berarti variabel ini tidak bisa diakses oleh dunia luar secara langsung. Variabel ini hanya bisa
diambil nilainya dengan metode instansi getNama, dan karena tidak bisa diakses langsung dari
luar, maka isi variabel ini tidak bisa diganti dari luar kelas. Sekali objek Murid dibuat, maka
namanya tidak bisa diganti selama murid tersebut ada.

Pemulung Memori (Garbage Collector)


Posted Rab, 03/04/2009 - 01:14 by belajarprogram

Versi ramah cetak

Hingga saat ini kita hanya berbicara tentang membuat objek. Lalu bagaimana menghapus objek?
Pada bahasa pemrograman Java, destruksi (lawan konstruksi yang berarti menghancurkan) objek
dilakukan secara otomatis.

Objek dibuat di dalam memori heap, dan bisa diakses hanya melalui referensi yang disimpan
oleh variabel. Apa yang akan dilakukan jika variabel tersebut hilang, misalnya selesai melakukan
tugas dalam subrutin, sehingga referensi ke objek tersebut juga hilang?

Perhatikan contoh berikut ini.

Murid mrd = new Murid("Joko Susanto");


mrd = null;

Di baris pertama, referensi objek baru akan disimpan pada variabel mrd. Pada baris berikutnya,
isi variabel mrd diisi dengan null (atau referensi kosong), sehingga referensi ke objek yang baru
kita buat menjadi hilang. Dalam kondisi seperti ini, komputer tidak bisa lagi menunjuk kepada
objek yang baru dibuat tersebut, karena refernsinya hilang. Atau dengan kata lain, objek tersebut
tidak akan pernah bisa dipakai lagi.

Java menggunakan prosedur yang dinamakan pemulung memori (garbage collector) untuk
mengambil memori di mana suatu objek tidak lagi bisa diakses oleh program. Sistem komputer
harus bertanggung jawab terhadap pengaturan memori, bukan programmer, untuk melacak objek
yang menjadi "sampah". Pada contoh di atas, sangat mudah dilihat bahwa objek Murid telah
menjadi sampah. Biasanya dalam kenyataan sehari-hari, sangat sulit untuk melacak mana objek
sampah dan mana yang ukan. Jika suatu objek telah selesai digunakan, mungkin akan ada
beberapa variabel yang masih menyimpan referensi ke objek tersebut. Suatu objek baru menjadi
sampah apabila semua referensi yang merujuk pada objek tersebut hilang.

Dalam beberapa bahasa pemrograman lain, programmer diharuskan untuk mengatur sampahnya
sendiri. Akan tetapi, mencoba mengatur penggunaan memori secara manual sangat sulit, dan
sering menimbulkan bug yang tidak terduga. Programmer mungkin tidak sengaja menghapus
objek tersebut, meskipun ada variabel lain yang masih merujuk pada objek tersebut. Ini disebut
kesalahan pointer tak bertuan, dan kesalahannya akan fatal apabila objek yang akan diakses tak
lagi berada di alamat memori tersebut.
Tipe kesalahan lain adalah kebocoran memori, yang mana programmer lupa menghapus objek
yang tidak lagi digunakan. Ini akan berakibat pada penuhnya memori dengan sampah yang tidak
bisa lagi diakses karena referensinya telah hilang. Jika dibiarkan, maka lambat laun seluruh
memori komputer akan habis, sehingga komputer bisa berhenti total.

Karena Java memiliki pemulung memori, kesalahan seperti itu tidak mungkin terjadi. Pemulung
memori sudah dibicarakan sejak lama, dan sudah digunakan pada beberapa bahasa pemrograman
sejak tahun 1960-an. Anda mungkin bertanya kenapa tidak semua bahasa pemrograman
menggunakan pemulung memori? Dulu, pemulung memori membutuhkan waktu pemrosesan
yang lama, sehingga penggunaannya akan mengurangi kinerja program secara keseluruhan.
Akan tetapi riset terbaru telah menemukan teknik pemulungan memori yang lebih canggih, dan
ditambah dengan kecepatan komputer yang makin tinggi, pemulung memori menjadi suatu hal
yang sangat realistis.

Berterima kasihlah kepada Java.

Pewarisan, Polimorfisme, dan Kelas Abstrak


Posted Kam, 03/05/2009 - 01:08 by belajarprogram

Versi ramah cetak

Kelas melambangkan cetak biru objek yang memiliki kesamaan struktuk dan perilaku. Kelas
menentukan struktur suatu objek melalui variabel yang terkandung dalam setiap objek, dan
menentukan perilaku melalui metode instansi yang merupakan perilaku suatu objek.

Ide utama dari pemrograman berorientasi objek -- yang membedakannya dari pemrograman
tradisional -- adalah menciptakan kelas yang memiliki hanya beberapa (tidak semua) struktur
dan perilaku. Kemiripan ini diekspresikan dalam bentuk pewarisan dan polimorfisme (perubahan
bentuk).

Istilah pewarisan berarti suatu kelas bisa mewariskan sebagian atau keseluruhan struktur dan
perilaku kelas lain. Jika kelas B adalah kelas turunan dari kelas A, maka kita bisa juga menyebut
kelas A adalah kelas super dari kelas B. Kelas turunan bisa memiliki struktur atau perilaku
tambahan dari kelas supernya. Atau bahkan kelas turunan bisa mengubah atau mengganti
perilaku kelas supernya. Hubungan antara kelas turunan dan kelas super sering dilukiskan dalam
bentuk diagram di mana kelas turunan digambarkan di bawah kelas supernya, dan dihubungkan
dengan garis penghubung dengan tanda segitiga yang diletakkan di dekat kelas supernya.
Dalam bahasa Java, ketika kita membuat suatu kelas, kita bisa menyatakan bahwa kelas tersebut
merupakan kelas turunan dari kelas lain. Jika kita buat kelas yang bernama "B" dan kita ingin
kelas ini menjadi kelas turunan dari kelas "A", kita akan tulis dalam bentuk :

class B extends A {
.
. // tambahan atau perubahan
. // struktur dan perilaku dari kelas A
.
}

Beberapa kelas dapat menurunkan kelas yang sama. Kelas-kelas turunan ini masing-masing
disebut kelas saudara, yaitu diwariskan dari satu kelas super yang sama. Struktur dan perilaku
kelas super ini akan dimiliki oleh masing-masing turunannya. Pada diagram berikut, kelas B, C,
dan D adalah kelas saudara. Pewarisan juga bisa dilakukan beberapa kali, atau suatu kelas bisa
memiliki cucu, buyut, dan seterusnya. Pada diagram, kelas E merupakan kelas turunan kelas D,
sehingga kelas E adalah "cucu" dari kelas A. Kelas E masih bisa disebut turunan dari kelas A,
walaupun bukan merupakan turunan langsungnya.
Mari kita buat sebuah contoh. Kita akan membuat program yang berhubungan dengan kendaraan
bermotor, yang meliputi mobil, truk, dan motor. Program tersebut memiliki kelas yang
dinamakan Kendaraan yang melambangkan semua  jenis kendaraan bermotor. Kelas Kendaraan
memiliki variabel instansi seperti nomorPolisi dan pemilik dan metode instansi yang bernama
gantiPemilik. Variabel dan metode instansi ini bisa digunakan oleh segala jenis kendaraan
bermotor.

Ada 3 kelas turunannya yaitu Mobil, Truk dan Motor yang akan menyimpan variabel dan
metode khusus untuk setiap jenis kendaraan. Kelas Mobil misalnya memiliki variabel
jumlahPintu, kelas Truk memiliki variabel jumlahRoda, dan kelas Motor memiliki variabel
jumlahTak. Kelas-kelas ini bisa dideklarasikan dalam Java dalam bentuk

class Kendaraan {
int nomorPolisi;
Orang pemilik; // (anggap kelas Orang telah dibuat sebelumnya)
void gantiPemilik(Orang pemilikBaru) {
. . .
}
. . .
}
 
class Mobil extends Kendaraan {
int jumlahPintu;
. . .
}
 
class Truk extends Kendaraan {
int jumlahRoda;
. . .
}
 
class Motor extends Kendaraan {
int jumlahTak; // 2-tak atau 4-tak
. . .
}

Anggap mobilku adalah variabel dengan tipe Mobil akan dideklarasikan dan diinisialisasi
dengan pernyataan berikut

Mobil mobilku = new Mobil();

Dengan deklarasi seperti ini, maka program akan bisa mengakses mobilku.jumlahPintu,
karena jumlahPintu adalah variabel instansi dari kelas Mobil. Akan tetapi karena kelas Mobil
merupakan turunan dari kelas Kendaraan, maka mobil ini juga memiliki stuktur dan perilaku
dari kendaraan. Artinya program juga bisa mengakses mobilku.nomorPolisi,
mobilku.pemilik, dan menjalankan metode mobilku.gantiPemilik()

Dalam dunia nyata mobil, truk dan motor memang kendaraan (bukan hanya pada program).
Dalam arti objek yang memiliki tipe Mobil atau Truk atau Motor juga secara otomatis objek
bertipe Kendaraan. Fakta penting berikutnya :

Variabel yang dapat diisi referensi ke objek suatu kelas A juga dapat diisi referensi ke
objek kelas turunan dari kelas A.
Efek praktis dari penyataan ini adalah, objek dengan tipe Mobil dapat diisi ke dalam variabel
bertipe Kendaraan, atau dengan kata lain perintah berikut adalah valid

Kendaraan kendaraanku = mobilku;

atau bahkan juga perintah berikut

Kendaraan kendaraanku = new Mobil();

Setelah pernyataan di atas, variabel kendaraanku berisi referensi ke objek Kendaraan, yang
kebetulan merupakan instansi dari kelas turunannya, yaitu kelas Mobil. Objek akan "mengingat"
bahwa yang disimpan dalam variabel tersebut adalah objek bertipe Mobil, bukan Kendaraan.
Informasi tentang objek apa yang disimpan pada memori ikut disertakan bersama objek tersebut,
sehingga variabel yang bertipe Kendaraan akan tahu dengan pasti tipe objek yang dirujuknya.
Kita juga dapat menguji jenis objek yang disimpan suatu variabel dengan menggunakan operator
instanceof. Misalnya

if (kendaraanku instanceof Mobil) { ... }

menguji apakah objek yang dirujuk pada variabel kendaraanku merupakan objek bertipe Mobil.

Kebalikannya, pernyataan berikut tidak bisa dilakukan

mobilku = kendaraanku;

karena kendaraanku bisa bertipe objek lain seperti Truk atau Motor. Apabila kita tahu persis
bahwa kendaraanku bertipe Mobil, kita bisa menggunakan casting, untuk memberi tahu
komputer untuk memperlakukan variabel kendaraanku memiliki tipe Mobil. Jadi kita bisa
gunakan perintah

mobilku = (Mobil)kendaraanku;

Atau kita juga bisa mengakses ((Mobil)kendaraanku).jumlahPintu. Mari kita gunakan kelas
ini dalam program, dan kita ingin mencetak informasi yang sesuai dengan suatu kendaraan.
Misalnya:

System.out.println("Data Kendaraan:");
System.out.println("Nomor polisi: " + kendaraanku.nomorPolisi);
if (kendaraanku instanceof Mobil)
System.out.println("Jenis kendaraan: Mobil");
Mobil m = (Mobil)kendaraanku;
System.out.println("Jumlah pintu: " + m.jumlahPintu);
}
else if (kendaraanku instanceof Truk) {
System.out.println("Jenis kendaraan: Truk");
Truk t = (Truk)kendaraanku ;
System.out.println("Jumlah roda: " + t.jumlahRoda);
}
else if (kendaraanku instanceof Motor) {
System.out.println("Jenis kendaraan: Motor");
Motor sm = (Motor)kendaraanku ;
System.out.println("Jumlah tak: " + sm.jumlahTak);
}

Lihat bahwa untuk setiap jenis objek, komputer akan menguji satu per satu tipe objek yang
disimpan dalam kendaraanku. Jika kendaraanku[code] merujuk pada objek bertipe Truk
maka casting [code](Mobil)kendaraanku akan menampilkan pesan kesalahan.

Contoh lain, mari kita buat program untuk menggambar suatu bentuk geometri pada layar.
Misalnya bentuk geometri tersebut terdiri dari persegi panjang, oval, dan kotak bersudut lingkar
dengan berbagai warna.

Kelas yang akan kita buat adalah PersegiPanjang, Oval, dan KotakLingkar. Ketiga kelas tersebut
memiliki kelas super yang sama yang disebut BentukGeometris. Kelas BentukGeometris
memiliki variabel instansi warna, lokasi, dan ukuran. Untuk mengganti warna kita bisa
mengganti variabel instansi warna pada kelas ini, kemudian menjalankan metode instansi
gambar() untuk menggambar bentuk tersebut dengan warna baru:

class BentukGeometris {
Color warna; // Warna suatu bentuk geometri
// (Kelas Color diimport dari paket java.awt)
 
void setWarna(Color warnaBaru) {
// Metode untuk mengganti warna
warna = warnaBaru; // ganti nilai variabel instansi
gambar(); // gambar ulang bentuk geometris ini, dengan warna baru
}
 
void gambar() {
// metode untuk menggambar
? ? ? // perintaha apa yang harus diletakkan di sini?
}
 
. . . // variabel dan metode instansi lain
 
} // akhir kelas BentukGeometris

Sekarang metode gambar() mungkin menjadi serba salah. Masalahnya, setiap bentuk digambar
dengan cara berbeda. Metode setWarna() dapat digunakan oleh semua bentuk. Lalu bagaimana
komputer tahu bagaimana menggambar bentuk tersebut jika metode gambar() dipanggil?
Mudahnya, kita bisa jawab dengan : Komputer akan menjalankan perintah gambar() dengan
meminta bentuk tersebut untuk menggambar sendiri. Setiap objek bentuk tahu apa yang harus
dilakukan untuk menggambar dirinya.

Dalam prakteknya, ini berarti setiap kelas turunan dari kelas BentukGeometris memiliki metode
gambar() sendiri-sendiri, yaitu :

class PersegiPanjang extends BentukGeometris {


void gambar() {
. . . // perintah untuk menggambar persegi panjang
}
. . . // metode atau variabel lain
}
 
class Oval extends BentukGeometris {
void gambar() {
. . . // perintah untuk menggambar oval
}
. . . // metode atau variabel lain
}
 
class KotakLingkar extends BentukGeometris {
void gambar() {
. . . // perintah untuk menggambar kotak bersudut lingkar
}
. . . // metode atau variabel lain
}

Jika gambarku adalah variabel bertipe BentukGeometri, variabel ini bisa merujuk pada objek
dengan bertipe PersegiPanjang, Oval, atau KotakLingkar. Ketika program dijalankan, isi
variabel gambarku akan berubah-ubah, tergantung pada objek yang dirujuknya. Suatu saat di
tengah program, jika perintah gambarku.gambar() dijalankan, maka metode gambar() akan
dijalankan tergantung pada isi variabel gambarku saat itu.

Kita tidak akan bisa menebak metode apa yang akan dipanggil pada suatu saat hanya dengan
membaca program tersebut, karena kita tidak pernah tahu isi variabel gambarku pada suatu saat
tertentu. Misalnya perintah gambar() berada dalam suatu perulangan yang dijalankan berkali-
kali. Maka akan sangat mungkin perintah gambarku.gambar() dipanggil berulang-ulang tetapi
dengan objek yang berbeda-beda.

Kita sebut metode gambar() bersifat polimorfis. Suatu metode disebut polimorfis jika aksi yang
dilakukan oleh suatu metode berbeda-beda tergantung pada objek aktual pada saat metode itu
dijalankan. Polimorfisme adalah fitur utama dalam pemrograman berorientasi objek.
Mungkin akan lebih mudah dimengerti jika kita ganti bahasanya : Dalam PBO, memanggil
metode sering disebut juga dengan mengirim pesan kepada suatu objek. Objek tersebut merespon
pesan tersebut dengan melaksanakan metode yang sesuai. Pernyataan "gambarku.gambar();"
adalah pesan yang dikirim ke objek gambarku. Karena objek tersebut tahu jenis objeknya sendiri,
dia akan tahu bagaimana merespon pesan tersebut. Dari sudut pandang ini, komputer akan selalu
mengeksekusi perintah "gambarku.gambar();" dengan cara yang sama, yaitu dengan mengirim
pesan. Pesan tersebut bergantung pada siapa yang menerima pesan tersebut.

Dengan kata lain, objek merupakan sesuatu yang memiliki perilaku aktif, yaitu sesuatu yang bisa
mengirim dan menerima pesan. Polimorfisme dianggap sebagai sifat yang natural jika dilihat
dari sudut pandang ini. Polimorfisme juga berarti bahwa beberapa objek dapat merespon suatu
pesan dengan cara yang berbeda-beda.

Salah satu keindahan dari poliformisme adalah kita bisa membuat kode program tanpa harus
mengetahui persis apa yang akan dilakukan program saat kita menulis program tersebut. Jika kita
ingin menambah objek lain, misalnya segitiga, maka kita cukup menulis kelas turunan baru dan
membuat metode gambar() sendiri. Secara otomatis, program akan tahu jika kita beri perintah
"gambarku.gambar()" maka metode gambar() pada kelas segitiga akan dijalankan apabila
gambarku menunjuk pada objek yang memiliki kelas segitiga.

Ketika suatu objek, misalnya PersegiPanjang, Oval, atau KotakLingkar, harus menggambar
dirinya sendiri, metode gambar() yang sesuai dengan objek yang menerima pesan akan
dilaksanakan. Pertanyaannya, apa yang harus kita isi pada metode gambar() di kelas
BentukGeometri?

Jawabannya: kosongkan saja. Intinya kelas BentukGeometri adalah kelas abstrak, karena tidak
ada cara untuk menggambar BentukGeometri. Apabila kelas tersebut telah direalisasikan dalam
suatu bentuk, misalnya PersegiPanjang, barulah objek tersebut bisa menggambar sesuatu.

Lalu kenapa kita harus mendeklarasikan metode gambar() di kelas BentukGeometri?


Jawabannya, itu harus ada karena metode ini dibutuhkan untuk memanggil metode setWarna()
pada kelas BentukGeometri. Program kita akan menampilkan pesan kesalahan jika kita berikan
perintah gambarku.gambar(), karena gambarku bertipe BentukGeometri, apabila di dalam kelas
ini tidak ada metode yang bernama gambar().

Kita bisa menyebut kelas BentukGeometri merupakan kelas abstrak. Kelas abstrak adalah kelas
yang tidak bisa digunakan untuk membuat suatu objek, dan hanya digunakan untuk membuat
kelas turunan. Kelas abstrak hanya ada untuk mengekspresikan sifat umum yang dimiliki oleh
kelas-kelas turunannya.

Demikian juga, kita bisa menyebut metode gambar() pada kelas BentukGeometri merupakan
metode abstrak, karena metode ini bukan untuk dipanggil. Akan tetapi metode ini ada untuk
memberi tahu komputer bahwa semua kelas turunannya mengerti dan bisa menjalankan
metode gambar().
BentukGeometri dan metode gambar() secara sematik merupakan kelas dan metode abstrak.
Kita juga bisa memberi tahu komputer secara langsung dengan memberi sifat "abstract" pada
definisinya. Untuk metode abstrak, blok perintahnya diganti dengan titik koma (;). Metode ini
harus diimplementasikan secara detail pada kelas turunannya.

Perhatikan contoh berikut.

abstract class BentukGeometri {


Color warna;
 
void setWarna(Color warnaBaru) {
// metode untuk mengganti warna suatu bentuk
warna = warnaBaru; // ganti isi variabel instansi warna
gambar(); // menggambar kembali suatu bentuk dengan warna baru
}
 
abstract void gambar();
// metode abstrak yang harus diimplementasikan
// pada kelas turunannya
 
. . . // variabel dan metode instansi lainnya
 
} // akhir kelas BentukGeometri

Setelah kita buat seperti ini, kita tidak bisa lagi membuat objek langsung dari kelas
BentukGeometri.

Dalam Java, setiap kelas yang kita buat akan memiliki kelas super, atau dengan kata lain setiap
kelas merupakan turunan dari kelas lain. Jika kita tidak memberi kelas supernya (melalui
operator extends), maka kelas tersebut otomatis memiliki kelas super Object, yaitu kelas
bawaan yang sudah didefinisikan dalam paket java.lang. Kelas Object adalah satu-satunya
kelas yang tidak memiliki kelas super.

Jadi dengan demikian, perintah

class Kelasku { ... }

sama artinya dengan

class Kelasku extends Object { . . . }

Semua kelas akan merupakan turunan langsung atau tidak langsung dari kelas Object. Artinya
suatu obek yang merupakan kelas apapun dapat direferensikan oleh variabel bertipe Object.
Kelas Objek memiliki sifat-sifat umum yang dapat digunakan oleh semua objek. Kelas Object
adalah kelas yang paling abstrak dari kelas-kelas lainnya.

Kelas Object digunakan dalam beberapa kasus di mana kumpulan objek yang sangat umum
ingin diolah. Misalnya, Java memiliki kelas standar java.util.ArrayList yang merupakan
kumpulan Objects. ArrayList akan dibahas kemudian dalam topik tentang struktur data dan
algoritma. Kelas ini digunakan untuk menampung kumpulan objek, tak ditentukan jumlahnya,
dan bisa diperbanyak ketika objek baru ditambahkan. Objek yang dapat ditampung pada
dasarnya adalah semua objek dari beragam kelas.

Kita dapat juga membuat program untuk menampung semua BentukGeometri yang telah
digambar di layar dalam kontainer ArrayList. Milsanya ArrayList kita bernama
kumpulanGambar. Suatu objek dengan tipe BentukGeometri misalnya gambarku dapat
ditambahkan ke dalam kumpulan ini dengan menggunakan perintah
"kumpulanGambar.add(gambarku);". Gambar tersebut dapat dibuang dari dalam kumpulan
dengan perintah "kumpulanGambar.remove(gambarku);". Jumlah obejk dalam
kumpulanGambar dapat diubah dengan perintah "kumpulanGambar.size()". Juga kita bisa
mengambil gambar ke-n dari dalam kumpulanGambar dengan perintah
"kumpulanGambar.get(n);". Perlu diingat bahwa metode tersebut akan mengembalikan objek
bertipe Object bukan BentukGeometri, dan sebetulnya kontainer ini bisa menampung objek apa
saja, bukan hanya BentukGeometri, sehingga untuk mengambil objek ke-n yang kemudian kita
letakkan dalam variabel bertipe BentukGeometri, kita bisa gunakan perintah

gambarku = (BentukGeometri)kumpulanGambar.get(n);

Katakan misalnya kita ingin menggambar semua objek dengan berbagai tipe di dalam kumpulan
tersebut, kita bisa gunakan perulangan for sederhana (sekaligus memberi contoh betapa indagnya
PBO dan polimorfisme), yaitu dengan :

for (int n = 0; n < kumpulanGambar.size(); n++) {


BentukGeometri bg = (BentukGeometri)kumpulanGambar.get(n);
bg.gambar();
}

Penutup

Dalam pemrograman sehari-hari, terutama bagi programmer yang baru belajar dan bekerja
dengan objek, penurunan kelas akan sering digunakan. Salah satunya adalah untuk memperluas
kegunaan suatu kelas, yang disesuaikan dengan situasi dan kondisi permasalahan yang kita
hadapi. Kita bisa membuat kelas baru yang merupakan turunan kelas yang sudah ada, menambah
beberapa variabel dan metode instansi baru, yaitu dengan operator extends seperti dijelaskan
sebelumnya pada bagian ini.

Secara umum, sintaksnya adalah dalam bentuk

class kelas_turunan extends kelas_yang_sudah_ada {


... // tambahan atau perubahan variabel dan metode instansi
}

Kita akan lihat nanti bahwa banyak kelas-kelas standar pada Java yang digunakan hanya sebagai
kelas dasar yang untuk dikembangkan lebih jauh oleh kita sebagai programmer

this dan super


Posted Sab, 03/07/2009 - 22:16 by belajarprogram

Versi ramah cetak

Meskipun ide dasar dari pemrograman berorientasi objek merupakan konsep yang cukup
sederhana dan jelas, akan tetapi untuk memahaminya dengan baik kita membuthkan lebih
banyak waktu. Sayangnya, banyak sekali detail yang harus diulas di luar konsep dasarnya.
Bagian ini dan bagian berikutnya akan berbicara tentang hal-hal detail, yang tidak perlu dikuasai
dalam waktu singkat, akan tetapi pengenalan tentang hal detail ini sangat berguna paling tidak
sebagai bahan referensi.

Variabel spesial this dan super

Anggota statik suatu kelas bisa digunakan langsung di dalam kelas tersebut. Untuk digunakan di
kelas lain, maka ia harus dipanggil dengan nama lengkapnya dalam bentuk
"namaKelas.namaAnggota", misalnya "System.out" adalah variabel anggota statik dengan
nama "out" di dalam kelas "System". Kita bisa menggunakan nama lengkap kelas tersebut di
manapun, bahkan dari dalam kelas yang sama, misalnya karena nama anggota tersebut
disembunyikan oleh variabel lokal yang namanya sama.

Variabel dan metode instansi juga bisa digunakan langsung di dalam kelas tersebut, misalnya
suatu variabel instansi bisa digunakan langsung oleh metode instansi di kelas yang sama.
Anggota instansi juga memiliki nama lengkap akan tetapi ingat bahwa anggota instansi dimiliki
oleh objek, bukan kelas. Sehingga untuk memanggil suatu anggota instansi, kita harus
menggunakan nama objek yang diciptakan dari kelas tersebut, dalam bentuk
namaObjek.namaAnggota.

Akan tetapi, misalnya kita sedang menulis metode instansi di suatu kelas. Bagaimana caranya
kita memanggil anggota instansi kelas yang sama jika kita belum tahu nama objek apa yang
diciptakan dari kelas ini?

Java memiliki variabel spesial yang dinamakan "this" yang bisa digunakan untuk kasus di atas.
Variabel ini digunakan pada suatu objek untuk memanggil metode atau variabel instansi pada
objek yang sama. Maksudnya, this, merujuk pada "objek ini" yaitu objek di mana metode
sedang dijalankan. Jika x adalah variabel instansi dalam suatu objek, maka this.x adalah nama
lengkap variabel tersebut jika dipanggil dari dalam objek yang sama. Jika metode
suatuMetode() adalah metode instansi pada suatu objek, maka this.suatuMetode() bisa
digunakan untuk memanggil metode tersebut dari objek yang sama. Ketika komputer
menjalankan perintah tersebut, komputer akan mengganti variabel this dengan objek yang
berjalan pada saat itu.

Salah satu kegunaaan this adalah pada konstruktor, misalnya :

public class Murid {


private String nama; // Nama murid
 
public Murid(String nama) {
// Konstruktor, membuat murid dengan nama yang diberikan
this.nama = nama;
}
.
. // Variabel dan metode lain.
.
}

Dalam konstruktor di atas, variabel instansi nama disembunyikan oleh parameter formal yang
bernama sama. Akan tetapi, variabel instansi masih tetap bisa dipanggil dengan nama
lengkapnya, this.nama. Cara ini merupakan cara yang lazim, artinya kita tidak perlu mengganti
nama parameter formal dengan nama lain agar namanya tidak bentrok dengan nama salah satu
variabel instansinya. Kita bisa menggunakan nama parameter formal yang sama persis dengan
variabel instansinya.

Ada lagi kegunaan lain dari this. Ketika kita sedang menulis metode instansi, kita ingin
memberikan objek sebagai parameter aktual. Dalam hal ini, kita bisa menggunakan this sebagai
parameter aktualnya. Misalnya, kita ingin mencetak suatu objek sebagai string, kita bisa
menggunakan perintah "System.out.println(this);". Atau kita ingin mengisi nilai this ke
dalam variabel lain. Pokoknya, kita bisa melakukan segala hal seperti layaknya variabel kecuali
mengganti isinya.

Java juga memiliki variabel spesial yang dinamakan "super" untuk digunakan dalam metode
instansi. Variabel super digunakan dalam kelas turunan. super mengacu pada objek di mana
metode tersebut berada, akan tetapi ia merupakan bagian dari kelas super dari objek tersebut.

Suatu kelas bisa ditambah atau dimodifikasi dari kelas turunannya. Variabel super hanya
mengacu pada bagian objek sebelum ia ditambah atau dimodifikasi, atau dengan kata lain bentuk
aslinya sebelum dia diturunkan, yang dalam hal ini sama dengan kelas supernya.

Misalnya kita akan menulis suatu kelas, dan kelas tersebut memiliki metode instansi bernama
suatuMetode(). Pernyataan super.suatuMetode() berarti menjalankan suatuMetode() pada
kelas supernya. Jika tidak ada metode sutuMetode() pada kelas supernya, Java akan
menampilkan pesan kesalahan sintaks.
Alasan mengapa Java memiliki variabel super adalah karena banyak hal yang mungkin
tersembunyi pada kelas turunan. Misalnya karena kita mengimplementasikan fungsi lain pada
kelas turunan dengan nama yang sama (dalam kaitannya dengan polimorfisme, misalkan).

Ketika kita membuat metode baru pada kelas turunan yang memiliki nama dan jenis parameter
yang sama dengan metode pada kelas supernya, metode dari kelas super akan disembunyukan.
Dalam bahasa pemrograman, metode ini menimpa (override) metode dari kelas supernya.
Variabel super bisa digunakan untuk mengakses metode aslinya yang didefinisikan di kelas
supernya.

Kegunaan utama dari super biasanya untuk memperluas kegunaan metode yang sudah ada,
bukan menggantinya secara keseluuruhan. Metode baru bisa menggunakan super untuk
menjalankan instruksi pada kelas supernya, kemudian menambahkan instruksi lain pada kelas
turunannya.

Misalnya, kita memiliki kelas PasanganDadu yang memiliki metode kocok. Kemudian kita akan
membuat kelas turunan yaitu DaduGrafis yang berfungsi untuk menggambar dadu pada layar.
Metode kocok() dalam DaduGrafis harus melakukan apa yang dilakukan oleh PasanganDadu,
dengan tambahan perintah untuk menggambar dadu tersebut di layar. Kita bisa tulis definisi
kelas DaduGrafis dalam bentuk :

public class DaduGrafis extends PasanganDadu {


public void kocok() {
// Mengocok dadu, kemudian menggambarnya di layar
super.kocok(); // Panggil metode kocok() di kelas PasanganDadu
gambar(); // Gambar ulang dadu
}
.
. // Metode dan variabel lain, termasuk metode gambar()
.
}

Dengan cara ini kita bisa memperluas apa yang dilakukan oleh metode kocok() pada kelas
supernya tanpa mengetahui dengan detail apa yang dilakukan langkah per langkah di kelas
supernya.

Konstuktor pada Kelas Turunan

Konstruktor tidak bisa diturunkan, artinya jika kita membuat kelas turunan dari suatu kelas,
konstruktor pada kelas supernya tidak termasuk bagian yang diturunkan. Jika kita ingin
konstruktor tersebut pada kelas turunannya, maka kita harus membuat kembali konstruktor
tersebut di kelas yang baru. Jika tidak, maka Java akan membuat konstruktor standar tanpa
parameter apa-apa.

Hal ini mungkin menjadi masalah jika konstruktor pada kelas supernya melakukan banyak tugas.
Artinya kita harus mengulang kembali menuliskan semua instruksi pada kelas supernya di kelas
turunan yang baru. Masalahnya akan lebih rumit jika kita tidak mengetahui sama sekali apa yang
dilakukan kelas supernya, misalnya apabila tidak ada kode sumbernya.
Cara yang paling mudah adalah menggunakan super. Di baris pertama konstruktor baru kita di
kelas turunannya, kita bisa menggunakan super untuk memanggil konstruktor kelas supernya.
Sintaksnya sedikit aneh dan membingungkan, dan hanya bisa digunakan untuk satu situasi saja :
Sintaksnya mirip seperti memanggil subrutin super (meskipun sebenarnya super bukan subrutin
dan kita tidak bisa memanggil konstruktor seperti kita memanggil subrutin biasa).

Misalnya kelas PasanganDadu memiliki konstruktor yang memiliki dua parameter bertipe int.
Maka kita bisa membuat konstruktor pada kelas DaduGrafis seperti :

public class DaduGrafis extends PasanganDadu {


 
public DaduGrafis() { // Konstruktor kelas ini
super(3,4); // Panggil konstruktor dari kelas PasanganDadu
// dengan parameter 3 dan 4
inisialisasiGrafis(); // Lakukan inisialisasi grafis
// untuk digunakan pada kelas DaduGrafis
}
.
. // Konstruktor, variabel dan metode instansi lain
.
}

Antar Muka (interface), Kelas Bertingkat, dan Detail Lain


Posted Min, 03/08/2009 - 23:11 by belajarprogram

Versi ramah cetak

Antar Muka

Beberapa bahasa pemrograman berorientasi objek, misalnya C++, membolehkan suatu kelas
memiliki dua atau lebih kelas super. Hal ini disebut pewarisan ganda (multiple inheritance). Pada
ilustrasi berikut, kelas E memiliki kelas super A dan B, sedangkan kelas F memiliki 3 kelas
super.

Pewarisan ganda seperti ini tidak diperbolehkan pada Java. Desainer Java ingin menjaga agar
bahasa Java tetap sederhana, dan mereka merasa pewarisan ganda ini sangat kompleks dengan
keuntungan yang tidak begitu besar. Akan tetapi, Java memiliki fitur lain yang bisa digunakan
seperti halnya pewarisan berganda, yaitu antar muka (interface).
Kita telah mengenal istilah "antar muka" sebelumnya, yaitu dalam konteks umum tentang kotak
hitam dan subrutin. Antar muka suatu subrutin terdiri dari nama, jenis keluarannya, jumlah dan
tipe parameternya. Informasi ini dibutuhkan jika kita ingin memanggi subrutin tersebut. Suatu
subrutin juga memiliki implementasi : yaitu blok yang berisi perintah yang akan dijalankan
ketika subrutin ini dipanggil.

Dalam Java, kata interface adalah kata kunci yang memiliki arti tambahan. Suatu interface
dalam hal ini adalah antar muka yang terdiri dari subrutin tanpa implementasi apa-apa. Suatu
kelas dapat mengimplementasi suatu interface dengan memberikan kode detail pada setiap
subrutin yang ditulis pada interface tersebut. Berikut adalah contoh interface Java sederhana
:

public interface Gambar {


public void gambar(Graphics g);
}

Deklarasi di atas mirip dengan definisi suatu kelas, akan tetapi isi metode gambar()
dikosongkan. Suatu kelas yang mengimplementasi interface ini, yaitu interfaceGambar,
harus mengisi implementasi metode gambar() ini. Tentunya kelas tersebut juga bisa memiliki
variabel dan metode lain. Misalnya,

class Garis implements Gambar {


public void gambar(Graphics g) {
. . . // perintah untuk menggambar garis
}
. . . // variabel dan metode lain
}

Kelas apapun yang mengimplementasi antar muka Gambar[code] harus memberikan detail
apa yang akan dilakukan oleh metode [code]gambar(). Objek yang diciptakan dari kelas
tersebut akan memiliki metode gambar(). Perlu diingat bahwa hanya menambah metode
gambar() saja tidak cukup. Definisi kelas yang ingin mengimplementasikan suatu interface
harus menulis "implements Gambar" dalam definisi kelasnya.

Suatu kelas bisa menurunkan hanya satu kelas lain, akan tetapi suatu kelas bisa
mengimplementasikan lebih dari suatu antar muka. Sebenarnya, suatu kelas bisa menurunkan
kelas lain dan mengimplementasikan satu atau lebih antar muka sekaligus. Misalnya

class LingkaranBerwarna extends Lingkaran


implements Gambar, BerisiWarna {
. . .
}

Intinya adalah meskipun interface bukan kelas, akan tetapi interface mirip dengan kelas.
suatu interface mirip seperti kelas abstrak, yaitu kelas yang hanya digunakan untuk membuat
kelas lain, bukan untuk membuat objek. Subrutin pada suatu interface merupakan metode
abstrak yang harus diimplementasikan pada kelas kongkrit yang mengimplementasikan
interface tersebut.
Seperti kelas abstrak, meskipun kita tidak bisa membuat objek dari interface, akan tetapi suatu
variabel dapat bertipe suatu interface. Misalnya, jika Gambar adalah suatu interface, dan jika
Garis dan LingkaranBerwarna adalah kelas yang mengimplementasikan Gambar, maka kita
bisa menulis kode seperti :

Gambar gambarku; // Deklarasi variabel dengan tipe Gambar.


// Variabel ini bisa diisi objek yang
// mengimplementasi interface Gambar
 
gambarku = new Garis(); // gambarku berisi objek dengan kelas Garis
gambarku.gambar(g); // memanggil metode gambar() dari kelas Garis
 
gambarku = new LingkaranBerwarna(); // Sekarang gambarku berisi objek
dengan
// kelas LingkaranBerwarna
gambarku.gambar(g); // memanggil metode gambar() dari kelas
LingkaranBerwarna

Variabel dengan tipe Gambar boleh merujuk pada kelas apapun yang mengimplementasikan antar
muka Gambar. Pernyataan di atas seperti "gambarku.gambar(g)" boleh ditulis karena gambarku
adalah variabel dengan tipe Gambar, dan setiap objek bertipe Gambar pasti memiliki metode
gambar().

Catatan bahwa tipe data merupakan sesuatu yang biasa digunakan untuk mendeklarasikan
variabel. Tipe data juga digunakan untuk memberikan tipe suatu parameter pada subrutin, atau
sebagai tipe keluaran suatu fungsi. Pada Java, tipe data bisa berupa kelas, interface, atau salah
satu dari 8 tipe data primitif. Dari semuanya, hanya kelas yang bisa digunakan untuk membuat
objek baru.

Kita biasanya tidak perlu menulis interface kita sendiri hingga program kita menjadi sangat
kompleks. Akan tetapi ada beberapa interface yang sudah disediakan oleh Java yang mungkin
bisa digunakan atau diimplementasi dalam program kita.

Kelas Bertingkat

Suatu kelas merupakan blok bangunan suatu program, yang melambangkan suatu ide beserta
data dan perilaku yang dimilikinya. Kadang-kadang kita mungkin berasa sedikit aneh untuk
membuat kelas kecil hanya untuk menggabungkan beberapa data. Akan tetapi kadang-kadang
kelas-kelas kecil ini sering bermanfaat dan penting. Untungnya Java membolehkan kita untuk
membuat kelas di dalam kelas lain, sehingga kelas-kelas kecil ini tidak perlu berdiri sendiri.
Kelas kecil ini menjadi bagian dari suatu kelas besar yang bisa melakukan hal-hal kompleks
lainnya. Kelas kecil ini misalnya berguna untuk mendukung operasi yang akan dikerjakan oleh
kelas besarnya.

Dalam Java, kelas bertingkat atau kelas bagian dalam adalah kelas yang ditulis di dalam definisi
kelas lain. Kelas bagian dalam ini bisa memiliki nama atau anonim (tanpa nama). Kelas bagian
dalam yang memiliki nama tampak seperti kelas biasa, tetapi ia ditulis di dalam kelas lain. (Kelas
bagian dalam ini juga bisa memiliki kelas bagian dalam yang lain, akan tetapi ingat akan
konsekuensi kerumitannya apabila kita membuat terlalu banyak tingkatan).

Seperti komponen lain dalam suatu kelas, kelas bagian dalam yang memiliki nama bisa berupa
kelas statik atau kelas non-statik. Kelas bertingkat statik merupakan bagian dari struktur statik
dari kelas yang menaunginya. Kelas tersebut bisa digunakan di dalam kelas induknya untuk
membuat objek seperti biasa. Jika tidak dideklarasikan sebagai private, makan kelas tersebut juga
bisa digunakan dari luar kelas induknya. Jika digunakan dari luar kelas induknya, namanya harus
jelas mencantumkan nama kelas induknya. Mirip seperti komponen statik dari suatu kelas : kelas
bertingkat statik adalah bagian kelas di mana kelas tersebut mirip dengan variabel anggota statik
lainnya di dalam kelas tersebut.

Misalnya, suatu kelas bernama ModelRangkaKawat melambangkan kumpulan garis dalam ruang
3 dimensi. Misalnya kelas ModelRangkaKawat memiliki kelas bertingkat statik yang bernama
Garis yaitu sebuah garis. Maka dari luar kelas ModelRangkaKawat, kelas Garis akan dipanggil
sebagai ModelRangkaKawat.Garis.

Kelas ModelRangkaKawat dan kelas bagian dalamnya dapat dituliskan seperti berikut :

public class ModelRangkaKawat {


 
. . . // anggota lain kelas ModelRangkaKawat
 
static public class Garis {
// Melambangkan garis dari titik (x1,y1,z1)
// ke titik (x2,y2,z2) dalam ruang 3-dimensi
double x1, y1, z1;
double x2, y2, z2;
} // akhir kelas Garis
 
. . . // anggota lain kelas ModelRangkaKawat
 
} // akhir kelas ModelRangkaKawat

Di dalam kelas ModelRangkaKawat, objek Garis bisa dibuat dengan konstruktor "new
Garis()". Di luar kelas, perintah "new ModelRangkaKawat.Garis()" harus digunakan.

Kelas bertingkat statik memiliki akses penuh kepada anggota dari kelas induknya, termasuk ke
anggota private. Mungkin ini juga motivasi sebagian orang untuk membuat kelas bertingkat,
karena kelas bagian dalamnya bisa mengakses anggota private kelas lain tanpa harus membuat
variabel atau metode anggotanya menjadi public.

Ketika kita mengkompilasi definisi kelas di atas, dua file kelas akan dibuat. Meskipun definisi
kelas Garis berada di dalam ModelRangkaKawat, akan tetapi kelas Garis akan disimpan dalam
file terpisah. Nama file kelas Garis akan menjadi ModelRangkaKawat$Garis.class
Kelas bertingkat yang tidak statik, pada prakteknya, tidak jauh berbeda dengan kelas bertingkat
statik, akan tetapi kelas bertingkat non-statik berkaitan dengan suatu objek, bukan kelas
induknya.

Anggota non-statik dari suatu kelas sebenarnya bukan merupakan bagian dari kelas itu. Hal ini
juga berlaku untuk kelas bertingkat non-statik seperti juga bagian kelas non-statik lainnya.
Anggota non-statik suatu kelas menjelaskan apa yang akan disimpan dalam objek yang
diciptakan dari kelas tersebut. Hal ini juga berlaku (secara logis) dari kelas bertingkat non-statik.

Dengan kata lain, setiap objek yang diciptakan dari kelas induknya memiliki kopi kelas
bertingkat masing-masing. Kopi ini memiliki akses ke semua variabel dan metode instansi objek
tersebut. Dua objek kelas bagian dalam pada dua objek induk merupakan objek berbeda karena
metode dan variabel instansi yang bisa diakses berasal dari objek yang berbeda.

Pada dasarnya, aturan untuk menentukan kapan suatu kelas bisa dimasukkan ke dalam kelas lain
sebagai kelas statik atau non-statik adalah : Jika kelas tersebut perlu menggunakan variabel atau
metode instansi suatu objek (bukan variabel atau metode statik kelas), maka kelas tersebut harus
dibuat non-statik, jika tidak maka harus dibuat statik.

Dari luar kelas induknya, kelas bertingkat non-statik harus dipanggil dalam bentuk
namaVariabel.NamaKelasBertingkat, misalnya namaVariabel adalah variabel yang merujuk
pada objek yang memiliki kelas bertingkat tersebut. Sebetulnya cara ini agak langka. Kelas
bertingkat non-statik biasanya digunakan hanya di dalam kelas induknya, sehingga bisa diakses
dengan nama yang sederhana.

UNtuk membuat objek yang merupakan kelas bertingkat non-statik, kita harus membuat objek
yang merupakan kelas induknya. (Ketika bekerja di dalam kelas, objek "this" akan secara
otomatis digunakan). Objek dari kelas bertingkat tersebut dihubungkan secara permanen dengan
objek dari kelas induknya, dan memiliki akses penuh atas anggota kelas induknya.

Mari lihat contoh berikut, dan mungkin bisa memberi pemahaman lebih baik bagaimana kelas
bertingkat non-statik sebetulnya merupakan hal yang sangat alami. Misalnya suatu kelas yang
melambangkan permainan kartu. Kelas ini memiliki kelas beringkat yang melambangkan para
pemainnya. Struktur MainKartu bisa berbentuk seperti :

class MainKartu { // Melambangkan permainan kartu


class Pemain { // Melambangkan salah satu pemain game ini
.
.
.
} // akhir kelas Pemain
private Tumpukan tumpukan; // Tumpukan kartu
 
.
.
.
 
} // akhir kelas MainKartu
Jika game adalah variabel dengan tipe MainKartu, maka game memiliki kelas Pemain[code]
sendiri. Dalam metode instansi objek [code]MainKartu, objek Pemain bisa dibuat
dengan perintah "new Pemain()", seperti halnya kelas biasa. (Objek Pemain bisa dibuat di luar
kelas MainKartu dengan perintah seperti "new game.Pemain()", tapi ini jarang dilakukan).
Objek Pemain memiliki akses ke variabel instansi tumpukan dalam objek MainKartu.

Masing-masing objek MainKartu memiliki tumpukan dan Pemain sendiri-sendiri. Pemain kartu
pada game tersebut akan menggunakan tumpukan kartunya sendiri sedangkan pemain kartu pada
game yang lain akan menggunakan tumpukan kartu lain lagi.

Jika Pemain merupakan kelas bertingkat statik, maka pemain tersebut akan bermain di semua
permainan kartu, yang tentu saja tidak mungkin terjadi.

Dalam beberapa kasus, mungkin kita harus menulis kelas bertingkat dan kemudian menggunakan
kelas tersebut hanya 1 kali dalam program kita. Apakah berguna membuat kelas bertingkat jika
begini kondisinya? Mungkin ya mungkin tidak. Dalam kasus seperti ini kita juga bisa membuat
kelas bertingkat anonim. Kelas anonim dapat dibuat dengan menggunakan variasi dari operator
new dengan bentuk

new kelassuper_atau_interface () {
metode_dan_variabel
}

Konstruktor ini membuat suatu kelas baru tanpa memberi nama, dan pada saat yang sama
membuat objek dari kelas tersebut. Bentuk operator [code] seperti ini bisa digunakan dalam
pernyataan apapun di mana pernyataan new biasa digunakan. Maksud dari pernyataan di atas
adalah untuk membuat : "objek baru di dalam suatu kelas yang namanya sama dengan
kelassuper_atau_interface dengan ditambah dengan metode_dan_varaibel baru."

Artinya pernyataan di atas sama dengan membuat objek baru dengan konfigurasi yang baru pula.
Kita juga bisa membuat kelas anonim yang diturunkan dari interface. Dalam hal ini, kelas
anonim tersebut harus mengimplementasikan semua metode yang dideklarasikan oleh
interface tersebut.

Kelas anonim sering digunakan untuk menangani event pada GUI (graphical user interfaces).
Misalnya interface Gambar seperti didefinisikan di awal bagian ini. Misalnya kita ingin membuat
objek berupa gambar bujur sangkar berisi warna merah dengan ukuran 100 x 100 piksel.
Daripada membuat kelas baru kemudian menggunakan kelas tersebut untuk membuat objek, kita
bisa menggunakan kelas anonim untuk membuat objek sekaligus dalam satu pernyataan :

Gambar kotakMerah = new Gambar() {


void gambar(Graphics g) {
g.setColor(Color.red);
g.fillRect(10,10,100,100);
}
};

Tanda titik koma (;) di akhir pernyataan ini bukan bagian dari definisi suatu kelas, tapi
merupakan bagian dari pernyataan secara keseluruhan.

Ketika kelas Java dikompilasi, setiap kelas bertingkat anonim akan dibuat dalam file kelas
terpisah. Jika nama kelas utama adalah KelasUtama, misalnya, maka nama file kelas untuk setiap
kelas bertingkat anonimnya menjadi KelasUtama$1.class, KelasUtama$2.class,
KelasUtama$3.class dan seterusnya.

Sifat Akses dalam Kelas

Suatu kelas dapat dideklarasikan sebagai public, yang bisa diakses dari manapun. Beberapa
kelas harus dideklarasikan sebagai publik, misalnya sebagai aplikasi desktop biasa, sehingga
sistem operasi bisa menjalankan prosedur main() nya. Kelas pada applet misalnya harus juga
dideklarasikan sebagai public supaya bisa diakses oleh web browser.

Jika suatu kelas tidak dideklarasikan sebagai public maka ia hanya akan bisa diakses dari paket
yang sama. Bagian ini membahas tentang paket. Kelas yang tidak ditulis dalam suatu paket
tertentu akan dimasukkan dalam paket default.

Suatu paket seharusnya terdiri dari beberapa kelas yang saling berhubungan. Beberapa dari kelas
ini memang sengaja dibuat public agar bisa diakses dari desktop atau program lain misalnya.
Bagian lain, yang merupakan bagian internal dari bagaimana paket tersebut bekerja dan tidak
boleh disentuh dari luar, tidak boleh dibuat menjadi public. Paket adalah salah satu jenis dari
kotak hitam, dan kelas public dalam paket tersebut adalah antar muka dengan dunia luarnya.

Variabel atau metode anggota suatu kelas juga bisa dideklarasikan sebagai public yang juga
berarti bisa diakses dari manapun. Variabel atau metode anggota ini juga bisa dideklarasikan
sebagai private yang artinya hanya bisa diakses dari dalam kelas di mana dia dideklarasikan.
Membuat variabel menjadi private memastikan bahwa tidak ada bagian lain yang akan bisa
mengubah variabel ini kecuali dari dalam kelas atau objek itu sendiri.

Jika kita tidak memberikan sifat akses pada metode atau variabel anggota tertentu, maka ia akan
otomatis bisa diakses oleh semua kelas dalam paket yang sama.

Ada satu jenis sifat akses lain yang bisa digunakan pada variabel atau metode anggota kelas,
yaitu protected. Sifat protected digunakan apabila kita ingin variabel atau metode anggota
tersebut bisa diakses oleh turunan kelas tersebut. Artinya lebih leluasa dari private tapi lebih
ketat daripada public. Kelas yang didesain untuk diturunkan, biasanya memiliki anggota
protected. Anggota protected digunakan untuk menambah fondasi bagi kelas turunannya,
akan tetapi tetap tak terlihat dari dunia luar.
Menggabungkan Statik dan Non-Statik

Seperti disebutkan sebelumnya, kelas dapat memiliki dua kegunaan yang sangat berbeda. Kelas
bisa digunakan untuk menggabungkan variabel dan subrutin statik. Atau juga bisa digunakan
sebagai produsen pembuat objek. Variabel dan subrutin non-statik dalam suatu kelas akan
menentukan metode dan variabel instansi pada objek yang diciptakan dari kelas tersebut. Dalam
banyak kasus, suatu kelas dapat melakukan salah satu atau kedua fungsi tersebut secara
bersamaan.

Dalam hal anggota statik dan non-statik digabung dalam satu kelas, kelas tersebut mengharapkan
adanya interaksi antara bagian statik dan bagian non-statik dari suatu kelas. Misalnya, metode
instansinya menggunakan variabel statik atau memanggil subrutin statik. Metode instansi
dimiliki oleh suatu objek, bukan oleh kelas tersebut. Karena kita bisa membuat banyak objek dari
suatu kelas, di mana setiap objek yang diciptakan memiliki metode instansi masing-masing.
Akan tetapi akan hanya ada satu variabel statik yaitu yang dimiliki oleh suatu kelas. Dengan
demikian, kita memiliki banyak objek yang bisa mengakses variabel statik tersebut bersama-
sama.

Misalnya anggap kita akan menulis kelas PasanganDadu yang menggunakan kelas Random
seperti pada bagian sebelumnya untuk mengocok dadu. Objek PasanganDadu perlu mengakses
objek Random. Akan tetapi membuat objek Random untuk setiap objek PasanganDadu adalah
terlalu berlebihan, karena fungsinya hanya digunakan untuk menghasilkan nilai acak saja. Solusi
yang bagus adalah dengan menggunakan variabel static yang digunakan oleh semua objek
yang dibuat dari kelas PasanganDadu. Misalnya pada kode berikut ini :

class PasanganDadu {
private static Random randGen = new Random();
// (Catatan: java.util.Random telah diimpor sebelum kelas ini dibuat)
 
public int dadu1; // Angka pada dadu pertama
public int dadu2; // Angka pada dadu kedua
 
public PasanganDadu() {
// Konstruktor. Membuat pasangan dadu dengan angka
// awal berupa bilangan acak
kocok();
}
 
public void kocok() {
// Kocok dadu dengan membuat masing-masing dadu
// bernilai bilangan acak 1 hingga 6
dadu1= randGen.nextInt(6) + 1;
dadu2= randGen.nextInt(6) + 1;
}
 
} // akhir kelas PasanganDadu

Contoh lain adalah kelas Murid yang digunakan pada bagian sebelumnya. Kita tambahkan
variabel instansi nomorMurid yaitu nomor unik yang berbeda untuk setiap murid. Untuk itu kita
perlu melacak nomor baru yang belum dipakai dengan variabel nomorBerikutnya yang
berbentuk variabel statik sehingga semua objek akan mengacu pada variabel yang sama. Ketika
objek baru dibuat, objek baru akan mengambil nilai nomorBerikutnya untuk dijadikan
nomorMurid yang baru.

public class Murid {


 
private String nama; // Nama murid
private int nomorMurid; // nomor murid unik
public double ujian1, ujian2, ujian3; // Nilai ujian
 
private static int nomorBerikutnya = 0;
// simpan nomor murid berikutnya
 
Murid(String namaBaru) {
// Konstruktor objek Murid:
// memberi nama, dan memberi nomor murid baru
nama = namaBaru;
nomorBerikutnya++;
nomorMurid = nomorBerikutnya;
}
 
public String getNama() {
// Fungsi untuk mengambil isi variabel instansi private: nama
return nama;
}
 
public int getNomorMurid() {
// Fungsi untuk membaca isi nomorMurid
return nomorMurid;
}
 
public double hitungRataRata() {
// Hitung rata-rata nilai ujian
return (ujian1 + ujian2 + ujian3) / 3;
}
 
} // akhir kelas Murid

Inisialisasi "nomorBerikutnya = 0" hanya dilakukan satu kali, yaitu ketika kelas ini pertama
kali dipanggil (pada saat program dijalankan). Ketika objek baru bertipe Murid dibuat, dan di
dalam konstruktor perintah "nomorBerikutnya++;", maka nomor berikutnya akan disimpan
untuk digunakan pada objek baru lainnya.

Ketika objek pertama dibuat, nilai nomorBerikutnya akan bernilai 1. Ketika objek kedua dibuat,
nilai nomorBerikutnya bernilai 2, dan seterusnya. Konstruktor akan menyimpan nilai baru
nomorBerikutnya pada variabel instansinya sendiri yang tidak di-share dengan objek-objek lain
yaitu nomorMurid. Dengan cara ini setiap murid baru akan selalu memiliki nomorMurid baru
yang berbeda satu dengan yang lain.

Bab VII - Kebenaran dan Ketangguhan Program


Posted Jum, 03/13/2009 - 17:54 by belajarprogram
Versi ramah cetak

Kita sering sekali menemukan program komputer yang gagal. Kesalahan sedikit dapat membuat
program berperilaku tidak sesuai dengan yang diharapkan atau bahkan mati total. Kita sendiri
sering mengalaminya. Dan kita sering mendengar berita atau cerita tentang kesalahan suatu
software yang menyebabkan pesawat jatuh, sambungan telepon putus seketika, atau bahkan
(dalam kasus yang langka) menyebabkan kematian orang.

Program sebetulnya tidak sejelek yang kita pikir. Mungkin kita tidak bisa membuat program
yang sama sekali bebas dari masalah, akan tetapi pemrograman yang baik dan alat pemrograman
yang didesain dengan baik akan membantu kita membuat program dengan masalah yang
sesedikit mungkin. Bagian ini akan membahas tentang program yang "benar" dan "tangguh".
Kita juga akan melihat pengecualian (exceptions), yaitu salah satu alat dalam bahasa Java yang
dapat membantu kita membuat program yang "tangguh" tersebut.

 Pengenalan tentang Program yang Benar dan Tangguh


 Membuat Program yang Benar
 Pengecualian dan Pernyataan "try ... catch"
 Pemrograman dengan Pengecualian

Pengenalan tentang Program yang Benar dan Tangguh


Posted Jum, 03/13/2009 - 18:01 by belajarprogram

Versi ramah cetak

Suatu program disebut "benar" jika ia menyelesaikan suatu tugas sesuai dengan desainnya.
Program disebut "tangguh" jika ia bisa menangani suatu situasi yang tidak biasa dengan cara
yang masuk akal. Misalnya, suatu program didesain untuk membaca angka yang diketik oleh
user, kemudian menampilkan angka dengan urutan tertentu. Program tersebut benar jika ia
bekerja untuk angka berapa pun. Program tersebut tangguh jika program tersebut bisa menangani
input yang salah, misalnya jika user memasukkan sesuatu yang bukan angka, misalnya, dengan
cara memberi tahu user bahwa input yang dia masukkan salah, dan mengabaikan input yang
salah tersebut. Program yang tidak tangguh akan keluar tiba-tiba atau memberikan keluaran yang
tidak bermakna dalam kondisi tertentu.

Semua program harusnya bekerja dengan benar. (Program yang dibuat untuk mengurutkan angka
tetapi tidak mengurutkan dengan benar adalah program yang tidak berguna). Program tidak
selalu harus tangguh secara total. Akan tetapi tergantung pada siapa yang akan menggunakan dan
bagaimana program tersebut digunakan. Misalnya, program kecil yang digunakan hanya oleh
Anda sendiri tidak harus tangguh total, karena kita tahu batas-batas dan bagaimana program
tersebut bekerja.

Kebenaran suatu program sebenarnya lebih sulit dari apa yang kita bayangkan. Seorang
programmer mencoba membuat program sesuai dengan spesifikasi tentang bagaimana sebuat
program "seharusnya" bekerja. Hasil kerja programmer tersebut benar jika program yang ia buat
bekerja sesuai dengan spesifikasinya. Tapi apakah itu berarti program tersebut benar? Bagaimana
jika ternyata spesifikasinya kurang lengkap atau salah? Program yang benar seharusnya
merupakan implementasi dari spesifikasi yang lengkap dan benar. Pertanyaannya apakah
spesifikasi tersebut lengkap dan sesuai dengan yang diinginkan tercakup di luar domain ilmu
komputer.

Banyak pengguna komputer memiliki pengalaman di mana program tidak bekerja atau crash.
Dalam banyak hal, masalah tersebut hanya mengganggu saja, tapi kadang-kadang masalahnya
lebih kompleks dari itu, misalnya hilangnya data atau uang. Jika komputer diberi tugas penting,
konsekuensinya akan lebih serius apabila program tersebut berperilaku tidak normal.

Beberapa tahun yang lalu, kegagalan dua misi ruang angkasa ke Mars masuk dalam berita.
Kedua kegagalan tersebut dipercaya karena masalah pada software, akan tetapi pada kedua kasus
tersebut masalahnya bukan pada program yang tidak benar. Pada bulan September 1999, Orbiter
Iklim Mars terbakar di atmosfer Mars karena data yang ditulis dalam satuan Inggris (inci, kaki,
dll) dimasukkan ke dalam program komputer yang didesain untuk menerima input satuan Metrik
(sentimeter, kilometer, dll). Beberapa bulan kemudian, Pendarat Kutub Mars jatuh karena
softwarenya mematikan mesinnya terlalu cepat. Program yang dibuat seharusnya bisa
mendeteksi tumpuan ketika pesawat mendarat dan baru kemudian mematikan mesin. Akan
tetapi, roda pendarat kemungkinan macet yang menyebabkan program pemati mesin aktif
sebelum pesawat menyentuh tanah. Sistem yang lebih tangguh akan mengecek terlebih dahulu
ketinggian pesawat sebelum mesin dimatikan.

Masih banyak beberapa kisah tentang masalah yang disebabkan oleh jeleknya desain atau
implementasi suatu software. Silakan lihat buku Computer Ethics karangan Tom Forester dan
Perry Morrison untuk melihat beberapa insiden yang pernah terjadi. (Buku ini menceritakan
tentang isu etika dalam bidang komputer. Buku ini mungkin penting sekali untuk dibaca oleh
orang yang berkecimpung dalam dunia ilmu komputer).

Pada tahun 1985 dan 1986, satu orang tewas dan beberapa lainnya terluka karena overdosis
radiasi, pada saat melakukan perawatan radiasi dengan mesin radiasi yang komputernya tidak
diprogram dengan benar. DI kasus lain, selama 10 tahun hingga tahun 1992, sekitar 1000 pasien
kanker menerima dosis radiasi sekitar 30% lebih rendah dari yang diberikan dokter karena
kesalahan pemrograman.

Pada tahun 1985, sebuah komputer di Bank of New York menghancurkan data-data transaksi
sekuritas yang sedang berjalan karena adanya kesalahan pada program. Butuh kurang dari 24 jam
untuk memperbaiki program tersebut, akan tetapi pada saat itu, bank sudah kehilangan sekitar 5
juta US dollar karena bunga overnight yang harus dipinjam untuk mengkover masalah tersebut.

Pemrograman sistem kendali inersia dari pesawat tempur F-16 bisa membalik pesawat dari atas
ke bawah ketika digunakan di atas khatulistiwa, untungnya masalah ini sudah ditemukan dalam
simulasi. Pemindai luar angkasa Mariner 18 hilang karena kesalahan di satu baris program.
Kapsul luar angkasa Gemini V salah mendarat beberapa ratus kilometer lebih jauh karena
programmer lupa untuk memasukkan perputaran bumi ke dalam perhitungan.

Pada tahun 1990, layanan telephon jarak jauh AT&T terganggu di seluruh Amerika Serikat
ketika program komputer yang baru dijalankan terbukti memiliki bug.

Contoh-contoh di atas adalah beberapa yang pernah terjadi. Masalah software adalah masalah
yang sangat umum. Sebagai programmer, kita harus mengerti kenapa itu bisa terjadi dan
bagaimana cara mengatasinya.

Salah satu bagian dari masalahnya dapat dilacak kepada bahasa pemrogramannya itu sendiri,
begitu kata para penemu Java. Java didesain untuk memberikan proteksi terhadap beberapa jenis
kesalahan. Bagaimana caranya suatu bahasa pemrograman menghindari kesalahan? Mari kita
lihat beberapa contohnya.

Bahasa pemrograman terdahulu tidak membutuhkan variabel untuk dideklarasikan. Pada bahasa
pemrograman tersebut, ketika suatu nama variabel digunakan dalam program, variabel akan
otomatis dibuat. Mungkin ini terlihat lebih mudah dan nyaman daripada harus mendeklarasikan
variabel beserta tipenya terlebih dahulu. Akan tetapi, ada konsekuensinya : Kesalahan ketik
sedikit saja akan membuat komputer menciptakan variabel baru yang sebetulnya tidak kita
inginkan. Kesalahan seperti ini pernah terjadi dan mengakibatkan hilangnya pesawat ruang
angkasa.

Dalam bahasa pemrograman FORTRAN, perintah "DO 20 I = 1,5" adalah pernyataan pertama
dari suatu perulangan. Sekarang, spasi tidak lagi suatu hal yang penting pada bahasa FORTRAN,
sehingga perintah ini akan sama dengan "DO20I=1,5". Di lain pihak, perintah "DO20I=1.5"
dengan tanda titik bukan koma, merupakan pernyataan pemberi nilai yang memberi nilai 1.5 ke
dalam variabel DO20I. Misalnya ada kesalahan dalam mengetik koma menjadi titik, bisa jadi
akan menyebabkan suatu roket meledak sebelum diluncurkan.

Karena FORTRAN tidak memerlukan variabel untuk dideklarasi, kompilernya akan senang
menerima perintah "DO20I=1.5". Ia akan membuat variabel baru bernama DO20I. Jika
FORTRAN membutuhkan variabel untuk dideklarasikan di awal, kompiler akan mengeluarkan
pesan kesalahan di awal karena variabel DO20I tidak pernah dideklarasikan sebelumnya.

Hampir semua bahasa pemrograman saat ini perlu mendeklarasikan variabel sebelum digunakan,
akan tetapi masih ada beberapa fitur pada bahasa pemrograman yang bisa menyebabkan
kesalahan. Java sudah membuang fitur ini. Beberapa orang tidak suka karena ini membuat Java
menjadi kurang feksibel dan kurang ampuh. Walaupun mungkin kritik ini benar, meningkatnya
tingkat keamanan dan ketangguhan suatu program mungkin lebih dipentingkan dalam beberapa
hal.

Pertahanan yang paling baik untuk mencegah beberapa macam jenis kesalahan adalah mendesain
bahasa pemrograman di mana membuat kesalahan tidak mungkin sama sekali. Dalam kasus lain,
di mana kesalahan tidak bisa dihilangkan sama sekali, bahasa pemrograman bisa didesain
sehingga apabila kesalahan terjadi, maka kesalahan ini akan dapat dideteksi secara otomatis.
Paling tidak cara ini akan mencegah kesalahan tersebut membuat bencana yang lebih besar,
karena akan memberi peringatan kepada programmer bahwa ada sesuatu bug yang harus
diperbaiki. Mari lihat beberapa contoh yang diberikan Java untuk mengatasi permasalahan ini.

Suatu array dibuat dengan beberapa lokasi, dimulai dengan 0 hingga ke indeks maksimumnya.
Kita tidak dibolehkan untuk menggunakan lokasi array di luar rentang yang sudah dibuat. Pada
Java, jika kita memaksakan untuk melakukan itu, sistem akan otomatis mendeteksi hal ini. Pada
bahasa pemrograman lain seperti C dan C++, programmer diberi keleluasaan penuh untuk
memastikan bahwa indeks array berada di dalam rentang tersebut.

Misalnya suatu array, A, memiliki tiga lokasi A[0], A[1], dan A[2]. Maka A[3], A[4], dan
berikutnya adalah lokasi pada memori di luar array tersebut. Pada Java, apabila kita mencoba
untuk menyimpan data pada A[3], Java akan mendeteksi ini. Program akan dihentikan saat itu
juga (kecuali kesalahan ini "ditangkap" yang akan dibahas kemudian). Pada bahasa C atau C++,
komputer akan diam saja dan melakukan penyimpanan di lokasi ini. Hasilnya akan tidak bisa
diprediksi. Konsekuensinya akan jauh lebih berat daripada jika program berhenti (Kita akan
diskusikan tentang tumpahan buffer di bagian ini nanti).

Pointer (penunjuk memori) juga merupakan kesalahan pemrograman yang paling sulit. Dalam
Java, variabel dari suatu objek menyimpan pointer atau rujuan ke alamat memori di mana objek
tersebut disimpan, atau isinya bisa juga null. Jika kita mencoba untuk menggunakan nilai null
seperti layaknya rujukan ke objek sungguhan, maka sistem komputer akan mendeteksinya.
Dalam bahasa pemrograman lain, lagi-lagi, adalah tanggung jawab programmer untuk mencegah
digunakannya rujukan ke null. Pada komputer Macintosh lama, alamat null merupakan alamat
ke lokasi di memori dengan alamat 0. Program dapat menggunakan memori di dekat alamat 0.
Sayangnya, Macintosh menyimpan data penting tentang sistem di lokasi tersebut. Mengubah
data di lokasi tersebut akan membuat sistem crash atau hang, bukan hanya program tersebut saja
tetapi keseluruhan sistem operasi akan berhenti.

Kesalahan pointer lain adalah jika isi pointer menunjuk pada tipe data yang salah atau lokasi di
memori yang tidak memiliki objek sama sekali. Kesalahan seperti ini tidak mungkin dalam
bahasa Java, karena programmer tidak diperbolehkan untuk mengganti pointer sama sekali. Di
dalam bahasa pemrograman lain, programmer bisa mengganti lokasi pointer ke lokasi lain,
intinya, ke lokasi memori manapun. Jika tidak dilakukan dengan benar, pointer ini bisa
menunjuk pada lokasi berbahaya atau menghasilkan sesuatu yang tidak bisa diperkirakan.

Kesalahan lain yang bisa terjadi pada Java adalah kebocoran memori. Pada Java, sewaktu tidak
ada lagi pointer yang merujuk ke pada suatu objek, objek tersebut akan diambil oleh pemulung
memori, sehingga memori tersebut dapat digunakan lagi oleh bagian program lain. Dalam bahasa
pemrograman lain, programmer bertanggung jawab untuk mengembalikan memori yang tidak
digunakan kepada sistem operasi. Jika programmer tidak melakukannya, makan memori yang
tidak terpakai akan terakumulasi, sehingga jumlah memori yang tersedia akan berkurang. Ini
adalah salah satu contoh masalah umum yang terjadi pada komputer Windows di mana banyak
sekali kebocoran memori yang terjadi, sehingga komputer harus direstart ulang setiap beberapa
hari.

Banyak program yang terjangkit masalah tumpahan buffer (buffer overflow error). Tumpahan
buffer sering menjadi berita utama karena hal ini sering mengakibatkan kompromi masalah
keamanan komputer. Ketika komputer menerima data dari komputer lain dari network atau
internet misalnya, data tersebut akan disimpan dalam buffer. Buffer adalah bagian memori yang
telah dialokasikan program untuk menyimpan data tersebut. Tumpahan buffer terjadi jika data
yang diterima lebih banyak dari jumlah data yang bisa ditampung oleh buffer. Pertanyaannya
adalah kapan ini terjadi?

Jika kesalahan ini bisa dideteksi oleh program atau program yang mengatur lalu lintas network,
maka satu-satunya kemungkinan adalah pada karena kesalahan transmisi data pada network.
Masalah utamanya terjadi ketika program tidak bisa mendeteksi tumpahan buffer secara benar.
Dalam hal ini, software terus mensuplai data ke memori meskipun buffer telah terisi penuh, dan
data lebihnya disimpan pada bagian memori yang tidak dialokasikan untuk buffer tersebut.
Bagian memori yang tertunpah tersebut mungkin digunakan untuk fungsi lain. Mungkin juga
digunakan untuk menyimpan data penting lain. Atau bahkan mungkin menyimpan kode program
itu sendiri. Ini yang akan menjadi masalah keamanaan. MIsalnya tumpahan buffer ini menimpa
bagian dari program. Ketika komputer mengeksekusi bagian program yang telah diganti, maka
sebetulnya komputer akan menjalankan data yang diterima dari komputer lain. Data ini bisa
berisi apa saja. Bisa jadi program untuk menghentikan komputer atau bahkan mengendalikan
komputer. Programmer jahat yang bisa menemukan kesalahan tumpahan memori dalam software
pengendali network bisa menggunakan lubang ini untuk menjalankan program-program
jahatnya.

Untuk software yang ditulis dalam Java, kesalahan tumpahan buffer tidak dimungkinkan. Bahasa
Java tidak mungkin menyimpan data di memori yang tidak dialokasikan kepadanya. Untuk bisa
menyimpan data, komputer membutuhkan pointer yang menunjuk pada lokasi memori yang
belum terpakai, atau menggunakan lokasi array yang berada di luar lokasi yang disediakan untuk
array tersebut. Seperti dijelaskan sebelumnya, kedua kemungkinan tersebut tidak diperbolehkan
sama sekali pada Java. (Akan tetapi, masih mungkin kesalahan seperti ini muncul pada kelas
standar Java, karena beberapa metode pada kelas ini sebenarnya ditulis dalam bahasa C bukan
Java).

Sudah jelas desain bahasa bisa membantu mencegah kesalahan atau membantu mendeteksi
masalah yang mungkin terjadi. Atau dibutuhkan pengujian, misalnya menguji apakah pointer
bernilai null. Beberapa programmer mungkin merasa harus mengorbankan kecanggihan dan
efisiensi. Akan tetapi, ada banyak situasi di mana keamanan merupakan prioritas utama. Java
didesain untuk situasi seperti ini.

Ada satu bagian di mana desainer Java tidak memasukkan pendeteksi masalah secara otomatis,
yaitu perhitungan numerik. Pada Java, nilai suatu bilangan int dinyatakan dalam bilangan biner
32-bit. Dengan 32 bit, maka terdapat kurang lebih 4 milyar bilangan yang bisa dibentuk. Nilai int
memiliki rentang antara -2147483648 hingga 2147483647. Apa yang terjadi jika hasil
perhitungan berada di luar rentang ini? Misalnya, berapa 2147483647 + 1? Dan berapa
2000000000 * 2? Jawaban yang benar secara matematis berada di luar nilai int. Contoh-contoh
di atas disebut tumpahan bilangan bulat (integer overflow). Dalam banyak kasus, tumpahan
bilangan bulat termasuk suatu kesalahan. Akan tetapi Java tidak otomatis mendeteksi kesalahan
tersebut. Misalnya, perhitungan 2147483647 + 1 akan bernilai negatif -2147483648 (Apa yang
terjadi sebenarnya adalah bit tambahan di luar bit ke-32 diabaikan. Nilai yang lebih besar dari
2147483647 akan "terpotong" sehingga menjadi nilai negatif. Secara matematis, hasilnya akan
selalu merupakan sisa pembagian dari pembagian dengan 232).

Banyak kesalahan program yang disebabkan oleh kesalahan semacam ini. Program tersebut
benar, akan tetapi tidak bisa menangani bilangan lebih besar daripada 32 bit. Contoh sederhana
adalah kesalahan Y2K sebenarnya merupakan kesalahan yang mirip dengan ini.

Untuk jenis bilangan real seperti double, masalahnya bahkan lebih kompleks lagi. Bukan hanya
tumpahan yang mungkin terjadi. Untuk jenis double, rentangnya berlaku hingga 10308. Nilai yang
lebih dari nilai ini tidak "terpotong" menjadi negatif. Akan tetapi ia akan diubah menjadi suatu
konstanta yang bernilai tak berhingga. Nilai Double.POSITIVE_INFINITY dan
Double.NEGATIVE_INFINITY melambangkan nilai positif tak hingga dan negatif tak hingga.
Nilai spesial lainnya dari tipe data double adalah Doube.NaN atau bukan bilangan (not a number),
yang melambangkan suatu nilai yang tidak berarti. Misalnya pembagian dengan 0 atau akar
kuadrat suatu bilangan negatif. Kita bisa menguji apakah suatu variabel berisi bukan bilangan
dengan memanggil fungsi yang bertipe keluaran boolean, yaitu Double.isNaN(x).

Untuk bilangan real, ada komplikasi tambahan yaitu hampir semua bilangan real hanya bisa
dilambangkan dalam bentuk pendekatan. Bilangan real bisa memiliki jumlah digit di belakang
koma yang tak terhingga banyaknya. Nilai bertipe double biasanya akurat sekitar 15 digit di
belakang koma. Bilangan real 1/3, misalnya, berarti 0.33333333......, dan bilangan ini tidak bisa
digantikan dengan bilangan dengan jumlah bit terbatas. Perhitungan dengan bilangan real
biasanya memiliki kesalahan akurasi. Sebenarnya, jika kita kurang berhati-hati, akan
menyebabkan perhitungan sama sekali salah. Ada bidang tertentu dalam ilmu komputer yang
dinamakan analisis numerik yang berkonsentrasi pada algoritma untuk memanipulasi bilangan
real.

Tidak semua kesalahan yang mungkin terjadi bisa dideteksi otomatis oleh Java. Lebih jauh,
bahkan ketika suatu kesalahan bisa dideteksi secara otomatis, reaksi standar dari sistem adalah
melaporkan kesalahan dan menghentikan jalannya program. Ini bukan ciri program yang
tangguh! Sehingga programmer harus mempelajari teknik untuk mencegah dan mengatasi
kesalahan. Topik ini akan dibahas pada bab ini.

Membuat Program yang Benar


Posted Jum, 03/13/2009 - 18:03 by belajarprogram
Versi ramah cetak

Program benar tidak jadi dengan sendirinya. Ia membutuhkan perencanaan dan perhatian kepada
detail untuk mencegah kesalahan dalam program. Ada beberapa teknik yang bisa digunakan oleh
programmer untuk meningkatkan kebenaran suatu program.

Dalam beberapa kasus, kita bisa membuktikan bahwa program tersebut benar. Yaitu dengan
menggunakan pembuktian secara matematis bahwa urutan penghitungan yang dilakukan
program akan selalu menghasilkan hasil yang benar. Pembuktian yang komprehensive sangat
sulit dibuat karena secara praktek pembuktian semacam ini hanya bisa dilakukan pada program
yang cukup kecil.

Seperti telah disebutkan sebelumnya, program yang benar menurut spesifikasi tidak berguna
apabila spesifikasinya salah. Artinya, bahkan dalam pemrograman sehari-hari pun, kita harus
terus mencari ide dan teknik yang bisa kita gunakan untuk membuktikan bahwa program yang
kita tulis adalah benar.

Ide dasarnya adalah proses (process) dan keadaan (state). Suatu keadaan terdiri dari semua
informasi yang terkait dengan eksekusi suatu program pada saat tertentu. Keadaan mencakup,
misalnya, nilai semua variabel pada program, keluaran yang telah diproduksi, input yang sedang
diambil, dan posisi dalam di mana program tersebut sedang dieksekusi. Proses adalah urutan
keadaan yang harus dilalui oleh komputer ketika menjalankan suatu program.

Dari sudut pandang ini, arti suatu pernyataan dalam suatu program dapat diekspresikan dalam
akibat apa yang dihasilkan dari eksekusi suatu perintah terhadap keadaan saat itu. Sebagai contoh
sederhana, arti dari pernyataan "x = 7;" adalah setelah pernyataan ini dieksekusi, nilai dari
variabel x adalah 7. Kita bisa yakin tentang fakta ini, sehingga fakta ini bisa dijadikan salah satu
bukti matematis.

Sebenarnya, kita juga seringkali bisa menilai suatu program dan menyimpulkan bahwa suatu
fakta adalah benar pada saat tertentu pada eksekusi suatu program. Misalnya, perhatikan
perulangan berikut :

do {
N = Math.random();
} while (N <= 0.5);

Setelah perulangan selesai, kita yakin betul bahwa nilai variabel N pasti lebih besar dari 0.5.
Perulangan tidak bisa berhenti jika kondisi ini tidak tercapai. Bukti ini merupakan bagian dari
arti perulangan while. Lebih umum, jika perulangan while menggunakan pengujian "while
(kondisi)" maka bisa dipastikan bahwa setelah perulangan selesai kondisi bernilai false.
Kemudian kita bisa menggunakan fakta ini untuk menyimpulkan apa yang akan terjadi ketika
eksekusi program berlanjut. (Dengan perulangan, kita juga harus memastikan kapan perulangan
tersebut akan berakhir. Hal ini harus dipikirkan lebih lanjut secara terpisah).

Suatu fakta yang pasti benar setelah bagian program dieksekusi disebut kondisi akhir dari bagian
program tersebut. Kondisi akhir adalah fakta yang bisa kita gunakan untuk menyimpulkan
tentang perilaku suatu program. Kondisi akhir suatu program secara keseluruan adalah fakta
yang bisa dibuktikan ketika program selesai dieksekusi. Suatu program bisa dibuktikan bahwa ia
melakukan fungsinya dengan benar jika kondisi akhirnya sesuai dengan spesifikasi program.

Misalnya, kita lihat potongan program berikut, di mana semua variabelnya memiliki tipe double:

det = B*B - 4*A*C;


x = (-B + Math.sqrt(det)) / (2*A);

Persamaan kuadrat (darti matematika di SMU) menyatakan bahwa nilai x adalah solusi
persamaan A*x2 + B*x + C = 0 jika det bernilai 0 atau lebih. Jika kita menganggap atau
menjamin bahwa B*B - 4*A*C >= 0 dan A != 0, maka x yaitu solusi persamaan kuadrat
merupakan kondisi akhir.

Kita sebut B*B - 4*A*C >= 0 sebagai kondisi awal potongan program tersebut. Kondisi A != 0
adalah kondisi awal lainnya. Kondisi awal adalah kondisi yang harus bernilai benar pada suatu
waktu di tengah eksekusi program untuk menjamin bahwa program akan dapat terus dieksekusi
tanpa kesalahan. Kondisi awal adalah sesuatu yang kita ingin selalu benar. Kondisi awal harus
kita cek agar program kita benar.

Mari kita lihat potongan program yang lebih panjang berikut ini. Program ini menggunakan kelas
KonsolInput yang dibahas pada bagian sebelumnya.

do {
System.out.println("Masukkan A, B, dan C. B*B-4*A*C harus >= 0.");
 
System.out.print("A = ");
A = KonsolInput.ambilDouble();
 
System.out.print("B = ");
B = KonsolInput.ambilDouble();
 
System.out.print("C = ");
C = KonsolInput.ambilDouble();
 
if (A == 0 || B*B - 4*A*C < 0)
System.out.println("Input Anda tidak benar, masukkan lagi.");
 
} while (A == 0 || B*B - 4*A*C < 0);
 
det = B*B - 4*A*C;
x = (-B + Math.sqrt(det)) / (2*A);

Setelah perulangan berakhir, kita yakin bahwa B*B-4*A*C >= 0 dan juga A != 0. Kondisi awal
untuk dua baris terakhir sudah dipenuhi, sehingga kondisi akhir bahwa x merupakan solusi
persamaan A*x2 + B*x + C = 0 juga benar. Potongan progam ini menghitung solusi suatu
persamaan dengan benar dan bisa dibuktikan secara matematis (Sebetulnya karena ada masalah
utama dalam merepresentasi angka terutama bilangan real pada komputer, hal ini tidak 100%
benar. Algoritma ini benar, akan tetapi programnya bukan implementasi sempurna dari algoritma
ini.)
Berikut ini adalah contoh lain, di mana kondisi awal diuji dengan suatu perintah. Di bagian awal
pernyataan if, di mana solusi dihitung kemudian dicetak ke layar, kita yakin bahwa kondisi awal
telah dipenuhi. Di bagian lain, kita tahu bahwa salah satu kondisi awal tidak bisa dipenuhi.
Bagaimana pun kondisinya, program akan tetap benar.

System.out.println("Masukkan nilai A, B, dan C.");


 
System.out.print("A = ");
A = KonsolInput.ambilDouble();
 
System.out.print("B = ");
B = KonsolInput.ambilDouble();
 
System.out.print("C = ");
C = KonsolInput.ambilDouble();
 
if (A != 0 && B*B - 4*A*C >= 0) {
det = B*B - 4*A*C;
x = (-B + Math.sqrt(disc)) / (2*A);
System.out.println("Solusi persamaan A*X*X + B*X + C = 0 is " + x);
} else if (A == 0) {
System.out.println("Nilai A tidak boleh 0.");
} else {
System.out.println("Karena B*B - 4*A*C kurang dari nol, maka");
System.out.println("persamaan A*X*X + B*X + C = 0 tidak memiliki
solusi.");
}

Ketika kita menulis suatu program, akan lebih baik jika kita mencari tahu kondisi awal suatu
program dan memikirkan bagaimana program kita harus menanganinya. Sering kali, kondisi
awal suatu program bisa memberi informasi tentang bagaimana cara menulis program.

Misalnya, untuk setiap referensi pada array, misalnya A[i], memiliki suatu kondisi awal.
Indeksnya harus berada di dalam rentang yang diperbolehkan pada array tersebut. Untuk A[i],
kondisi awalnya adalah 0 <= i < A.length. Komputer akan menguji kondisi ini ketika ia
mengevaluasi A[i], dan jika kondisi tidak dipenuhi, program akan dihentikan. Untuk mencegah
hal ini, kita harus menguji bahwa indeks i berada di dalam nilai yang diperbolehkan (Sebetulnya
ada lagi kondisi awal yang lain, yaitu A tidak boleh null, akan tetapi mari kita abaikan untuk
sementara waktu.) Misalnya kode berikut digunakan untuk mencari nilai x di dalam array A :

i = 0;
while (A[i] != x) {
i++;
}

Dalam program ini, kita melihat bahwa program tersebut memiliki kondisi awal, yaitu x harus
ada di dalam array. JIka kondisi awal ini dipenuhi, maka perulangan akan berhenti ketika A[i] ==
x. Akan tetapi, jika x tidak berada di dalam array, maka nilai i akan terus dinaikkan hingga
nilainya sama dengan A.length. Pada saat tersebut, referensi ke A[i] menjadi ilegal sehingga
program akan dihentikan. Untuk mencegah hal ini, kita bisa menambahkan pengujian untuk
menjamin bahwa kondisi awal untuk merujuk pada A[i] bisa dipenuhi, yaitu :
i = 0;
while (i < A.length && A[i] != x) {
i++;
}

Sekarang, perulangan pasti akan selesai. Setelah selesai, nilai i akan bernilai i == A.length
atau A[i] == x. Pernyataan if bisa ditambahkan di akhir perulangan untuk menguji apa yang
menyebabkan perulangan berhenti : 

i = 0;
while (i < A.length && A[i] != x) {
i++;
}
 
if (i == A.length)
System.out.println("x berada di luar array");
else
System.out.println("x berada pada posisi " + i);

Pengecualian dan Pernyataan "try ... catch"


Posted Jum, 03/13/2009 - 18:04 by belajarprogram

Versi ramah cetak

Membuat program untuk bekerja dalam kondisi ideal jauh lebih mudah daripada membuat
program yang tangguh. Program tangguh dapat tahan dari kondisi yang tidak biasa atau dalam
kondisi "pengecualian". Salah satu pendekatanya adalah dengan melihat kemungkinan masalah
yang mungkin terjadi dan menambahkan tes/pengujian pada program tersebut untuk setiap
kemungkinan masalah yang mungkin terjadi.

Misalnya, program akan berhenti jika mencoba mengakses elemen array A[i], di mana i tidak
berada di dalam rentang yang dibolehkan. Program tangguh harus dapat mengantisipasi
kemungkinan adanya indeks yang tak masuk akal dan menjaganya dari kemungkinan itu.
Misalnya bisa dilakukan dengan :

if (i < 0 || i >= A.length) {


... // Lakukan sesuatu untuk menangani indeks i diluar rentang
} else {
... // Proses elemen A[i]
}

Ada beberapa masalah yang mungkin terjadi dengan pendekatan seperti ini. Adalah hal yang
sangat sulit dan kadang kala tidak mungkin untuk mengantisipasi segala kemungkinan yang
dapat terjadi. Kadang tidak selalu jelas apa yang harus dilakukan apabila suatu kesalahan
ditemui. Untuk mengantisipasi semua masalah yang mungkin terjadi bisa jadi membuat program
sederhana menjadi lautan pernyataan if.
Java (seperti C++) membutuhkan metode alternatif yang lebih rapi dan terstruktur untuk
menghadapi masalah yang mungkin terjadi ketika program dijalankan. Metode ini disebut
sebagai penanganan pengecualian (exception-handling). Kata "pengecualian" diartikan sesuatu
yang lebih umum daripada "kesalahan". Termasuk di antaranya adalah kondisi yang mungkin
terjadi yang berada di luar aliran suatu program. Pengecualian, bisa berupa kesalahan, atau bisa
juga kasus tertentu yang kita inginkan terpisah dari algoritma kita.

Ketika pengecualian terjadi dalam eksekusi suatu program, kita sebut bahwa pengecualian
tersebut di-lempar-kan (thrown). Ketika ini terhadi, aliran program artinya terlempar dari
jalurnya, dan program berada dalam bahaya akan crash. Akan tetapi crash bisa dihindari jika
pengecualian tersebut ditangkap (catch) dan ditangani dengan cara tertentu. Suatu pengecualian
dapat dilempar oleh satu bagian program dan ditangkap oleh bagian program lain. Pengecualian
yang tidak ditangkap secara umum akan menyebabkan program berhenti. (Lebih tepat apabila
disebut thread yang melemparkan pengecualian tersebut akan berhenti. Dalam program
multithreading, mungkin saja thread lain akan terus berjalan apabila thread yang satu berhenti.)

Karena program Java dijalankan di dalam interpreter, program yang crash berarti bahwa program
tersebut berhenti berjalan secara prematur. Tidak berarti bahwa interpreter juga akan crash. Atau
dengan kata lain, interpreter akan menangkap pengecualian yang tidak ditangkap oleh program.
Interpreter akan merespon dengan menghentikan jalannya program. Dalam banyak bahasa
pemrograman lainnya, program yang crash sering menghentikan seluruh sistem hingga kita
menekan tombol reset. Dalam Java, kejadian seperti itu tidak mungkin -- yang artinya ketika hal
itu terjadi, maka yang salah adalah komputer kita, bukan program kita.

Ketika pengecualian terjadi, yang terjadi adalah program tersebut melemparkan suatu objek.
Objek tersebut membawa informasi (dalam variabel instansinya) dari tempat di mana
pengecualian terjadi ke titik di mana ia bisa ditangkap dan ditangani. Informasi ini selalu terdiri
dari tumpukan panggilan subrutin (subrutin call stack), yaitu daftar di mana dan dari mana
subrutin tersebut dipanggil dan kapan pengecualian tersebut dilemparkan. (Karena suatu subrutin
bisa memanggil subrutin yang lain, beberapa subrutin bisa aktif dalam waktu yang sama.)
Biasanya, objek pengecualian juga memiliki pesan kesalahan mengapa ia dilemparkan, atau bisa
juga memiliki data lain. Objek yang dilemparkan harus diciptakan dari kelas standar
java.lang.Throwable atau kelas turunannya.

Secara umum, setiap jenis pengecualian dikelompokkan dalam kelas turunan Throwable.
Throwable memiliki dua kelas turunan langsung, yaitu Error dan Exception. Kedua kelas
turunan ini pada akhirnya memiliki banyak kelas turunan lain. Kita juga bisa membuat kelas
pengecualian baru untuk melambangkan jenis pengecualian baru.

Kebanyakan turunan dari kelas Error merupakan kesalahan serius dalam mesin virtual Java
yang memang seharusnya menyebabkan berhentinya program karena sudah tidak dapat
diselamatkan lagi. Kita sebaiknya tidak mencoba untuk menangkap dan menangani kesalahan
jenis ini. Misalnya ClassFormatError dilempar karena mesin virtual Java menemukan data
ilegal dalam suatu file yang seharusnya berisi kelas Java yang sudah terkompilasi. Jika kelas
tersebut dipanggil ketika program sedang berjalan, maka kita tidak bisa melanjutkan program
tersebut sama sekali.

Di lain pihak, kelas turunan dari kelas Exception melambangkan pengecualian yang memang
seharusnya ditangkap. Dalam banyak kasus, pengecualian seperti ini adalah sesuatu yang
mungkin biasa disebut "kesalahan", akan tetapi kesalahan seperti ini adalah jenis yang bisa
ditangani dengan cara yang baik. (Akan tetapi, jangan terlalu bernafsu untuk menangkap semua
kesalahan hanya karena kita ingin program kita tidak crash. Jika kita tidak memiliki cara untuk
menanganinya, mungkin menangkap pengecualian dan membiarkannya akan menyebabkan
masalah lain di tempat lain).

Kelas Exception memiliki kelas turunan lainnnya, misalnya RuntimeException. Kelas ini
mengelompokkkan pengecualian umum misalnya ArithmeticException yang terjadi misalnya
ada pembagian dengan nol, ArrayIndexOutOfBoundsException yang terjadi jika kita mencoba
mengakses indeks array di luar rentang yang diijinkan, dan NullPointerException yang terjadi
jika kita mencoba menggunakan referensi ke null di mana seharusnya referensi objek
diperlukan.

RuntimeException biasanya menginidikasikan adanya bug dalam program yang harus


diperbaiki oleh programmer. RuntimeException dan Error memiliki sifat yang sama yaitu
program bisa mengabaikannya. ("Mengabaikan" artinya kita membiarkan program crash jika
pengecualian tersebut terjadi). Misalnya, program yang melemparkan
ArrayIndexOutOfBoundsException dan tidak menanganinya akan menghentikan program saat
itu juga. Untuk pengecualian lain selain Error dan RuntimeException beserta kelas turunannya,
pengecualian wajib ditangani.

Diagram berikut menggambarkan hirarki suatu kelas turunan dari kelas Throwable. Kelas yang
membutuhkan penanganan pengecualian wajib ditunjukkan dalam kotak merah.
 

Untuk menangkap pengecualian pada program Java, kita menggunakan pernyataan try.
Maksudnya memberi tahu komputer untuk "mencoba" (try) menjalankan suatu perintah. Jika
berhasil, semuanya akan berjalan seperti biasa. Tapi jika pengecualian dilempar pada saat
mencoba melaksanakan perintah tersebut, kita bisa menangkapnya dan menanganinya. Misalnya,

try {
double determinan = M[0][0]*M[1][1] - M[0][1]*M[1][0];
System.out.println("Determinan matriks M adalah " + determinan);
}
catch ( ArrayIndexOutOfBoundsException e ) {
System.out.println("Determinan M tidak bisa dihitung karena ukuran M
salah.");
}

Komputer mencoba menjalankan perintah di dalam blok setelah kata "try". Jika tidak ada
pengecualian, maka bagian "catch" akan diabaikan. Akan tetapi jika ada pengecualian
ArrayIndexOutOfBoundsException, maka komputer akan langsung lompat ke dalam blok
setelah pernyataan "catch (ArrayIndexOutOfBoundsException)". Blok ini disebut blok yang
menangani pengecualian (exception handler) untuk pengecualian
ArrayIndexOutOfBoundsException". Dengan cara ini, kita mencegah program berhenti tiba-
tiba.
Mungkin kita akan sadar bahwa ada kemungkinan kesalahan lagi dalam blok di dalam
pernyataan try. Jika variabel M berisi null, maka pengecualian NullPointerException akan
dilemparkan. Dalam pernyataan try di atas, pengecualian NullPointerException tidak
ditangkap, sehingga akan diproses seperti biasa (yaitu menghentikan program saat itu juga,
kecuali pengecualian ini ditangkap di tempat lain). Kita bisa menangkap pengecualian
NullPointerException dengan menambah klausa catch lain, seperti :

try {
double determinan = M[0][0]*M[1][1] - M[0][1]*M[1][0];
System.out.println("Determinan matriks M adalah " + determinan);
}
catch ( ArrayIndexOutOfBoundsException e ) {
System.out.println("Determinan M tidak bisa dihitung karena ukuran M
salah.");
}
catch ( NullPointerException e ) {
System.out.print("Kesalahan program! M tidak ada: " + );
System.out.println( e.getMessage() );
}

Contoh ini menunjukkan bagaimana caranya menggunakan beberapa klausa catch. e adalah
nama variabel (bisa kita ganti dengan nama apapun terserah kita). Ingat kembali bahwa ketika
pengecualian terjadi, sebenarnya yang dilemparkan adalah objek. Sebelum menjalankan klausa
catch, komputer mengisi variabel ini dengan objek yang akan ditangkap. Objek ini mengandung
informasi tentang pengecualian tersebut.

Misalnya, pesan kesalahan yang menjelaskan tentang pengecualian ini bisa diambil dengan
metode getMessage() seperti contoh di atas. Metode ini akan mencetak daftar subrutin yang
dipanggil sebelum pengecualian ini dilempar. Informasi ini bisa menolong kita untuk melacak
dari mana kesalahan terjadi.

Ingat bahwa baik ArrayIndexOutOfBoundsException dan NullPointerException adalah


kelas turunan dari RuntimeException. Kita bisa menangkap semua pengecualian dalam kelas
RuntimeException dengan klausa catch tunggal, misalnya :

try {
double determinan = M[0][0]*M[1][1] - M[0][1]*M[1][0];
System.out.println("Determinan matriks M adalah " + determinan);
}
catch ( RuntimeException e ) {
System.out.println("Maaf, ada kesalahan yang terjadi.");
e.printStackTrace();
}

Karena objek yang bertipe ArrayIndexOutOfBoundsException maupun


NullPointerException juga bertipe RuntimeException, maka perintah seperti di atas akan
menangkap kesalahan indeks maupun kesalahan pointer kosong dan juga pengecualian runtime
yang lain. Ini menunjukkan mengapa kelas pengecualian disusun dalam bentuk hirarki kelas.
Kita bisa membuat klausa catch secara spesifik hingga tahu persis apa yang salah, atau
menggunakan klausa penangkap umum.
Contoh di atas mungkin tidak begitu realistis. Sepertinya kita jarang harus menangani kesalahan
indeks ataupun kesalahan pointer kosong seperti di atas. Masalahnya mungkin terlalu banyak,
dan mungkin kita akan bosan jika harus menulis try ... catch setiap kali kita menggunakan
array. Yang penting kita mengisi variabel tersebut dengan sesuatu yang bukan null dan menjaga
agar program tidak keluar indeks sudah cukup. Oleh karena itu kita sebut penanganan ini tidak
wajib. Akan ada banyak hal yang bisa jadi masalah. (Makanya penanganan pengecualian tidak
menyebabkan program makin tangguh. Ia hanya memberikan alat yang mungkin kita gunakan
dengan cara memberi tahu di mana kesalahan mungkin muncul).

Bentuk pernyataan try sebenarnya lebih kompleks dari contoh di atas. Sintaksnya secara umum
dapat ditulis seperti:

try {
perintah
}
klausa_catch_tambahan
klausa_finally_tambahan

Ingat bahwa di sini blok ( yaitu { dan } ) diperlukan, meskipun jika perintah hanya terdiri dari
satu perintah. Pernyataan try boleh tidak dimasukkan, dan juga klausa finally boleh ada boleh
tidak. (Pernyataan try harus memiliki satu klausa finally atau catch). Sintaks dari klausa
catch adalah:

catch (nama_kelas_pengecualian nama_variabel) {


pernyataan
}

dan sintaks klausa finally adalah

finally {
pernyataan
}

Semantik dari klausa finally yaitu pernyataan di dalam klausa finally akan dijamin untuk
dilaksanakan sebagai perintah akhir dari pernyataan try, tidak peduli apakah ada pengecualian
yang dilempar atau tidak. Pada dasarnya klausa finally dimaksudkan untuk melakukan langkah
pembersihan yang tidak boleh dihilangkan.

Ada beberapa kejadian di mana suatu program memang harus melempar pengecualian. Misalnya
apabila program tersebut menemukan adanya kesalahan pengurutan atau kesalahan lain, tapi
tidak ada cara yang tepat untuk menanganinya di tempat di mana kesalahan tersebut ditemukan.
Program bisa melempar pengecualian dengan harapan di bagian lain pengecualian ini akan
ditangkap dan diproses.

Untuk melempar pengecualian, kita bisa menggunakan pernyataan throw dengan sintaks :
throw objek_pengecualian;

objek_pengecualian harus merupakan objek yang bertipe kelas yang diturunkan dari
Throwable. Biasanya merupakan kelas turunan dari kelas Exception. Dalam banyak kasus,
biasanya objek tersebut dibuat dengan operator new, misalnya :

throw new ArithmeticException("Pembagian dengan nol");

Parameter dalam konstruktor adalah pesan kesalahan dalam objek pengecualian.

Pengecualian bisa dilempar baik oleh sistem (karena terjadinya kesalahan) atau oleh pernyataan
throw. Pengecualian ini ditangani dengan cara yang sama. Misalnya suatu pengecualian
dilempar dari pernyataan try. Jika pernyataan try tersebut memiliki klausa catch untuk
menangani tipe pengecualian tersebut, maka klausa ini akan melompat ke klausa catch dan
menjalankan perintah di dalamnya. Pengecualian tersebut telah ditangani.

Setelah menangani pengecualian tersebut, komputer akan menjalankan klausa finally, jika ada.
Kemudian program akan melanjutkan program seperti biasa. Jika suatu pengecualian tidak
ditangkap dan ditangani, maka pengolahan pengecualian akan berlanjut.

Jika pengecualian dilempar pada saat eksekusi suatu subrutin dan pengecualian tersebut tidak
ditangani di dalam subrutin yang sama, maka subrutin tersebut akan dihentikan (setelah
menjalankan klausa finally, jika tersedia). Kemudian rutin yang memanggil subrutin tersebut
memiliki kesempatan untuk menangani pengecualian tersebut. Artinya, jika subrutin tersebut
dipanggil di dalam pernyataan try dan memiliki klausa catch yang cocok, maka klausa catch
tersebut akan dieksekusi dan program akan berlanjut seperti biasa.

Lagi-lagi jika rutin tersebut tidak menangani pengecualian tersebut, rutin tersebut akan
dihentikan dan rutin yang memanggilnya akan mencoba menangani pengecualian tersebut.
Pengecualian akan menghentikan program secara keseluruhan jika keseluruhan rantai panggil
subrutin hingga main() tidak menangani pengecualian tersebut.

Suatu subrutin yang mungkin melempar pengecualian dapat memberi tahu dengan menambahkan
klausa "throws nama_kelas_pengecualian" pada definisi suatu subrutin. Misalnya :

static double akar(double A, double B, double C)


throws IllegalArgumentException {
// Menghasilkan akar yang lebih besar
 // dari persamaan kuadrat A*x*x + B*x + C = 0.
// (Lempar pengecualian jika A == 0 atau B*B-4*A*C < 0.)
if (A == 0) {
throw new IllegalArgumentException("A tidak boleh nol.");
}
else {
double diskriminan = B*B - 4*A*C;
if (diskriminan < 0)
throw new IllegalArgumentException("Diskriminan < nol.");
return (-B + Math.sqrt(diskriminan)) / (2*A);
}
}

Seperti kita diskusikan pada bagian sebelumnya, perhitungan dalam subrutin ini memiliki
kondisi awal di mana A != 0 dan B*B-4*A*C >= 0. Subrutin akan melempar pengecualian
dengan tipe IllegalArgumentException jika salah satu dari kondisi awal ini tidak dipenuhi.
Jika kondisi ilegal ditemukan dalam suatu subrutin, melempar pengecualian kadang kala menjadi
pilihan yang lebih bijaksana. Jika program yang memanggil subrutin tersebut mengetahui
bagaimana cara yang tepat untuk menangani pengecualian tersebut, program tersebut dapat
menangkapnya. JIka tidak, maka program akan crash dan programmer akan tahu apa yang harus
diperbaiki.

Penanganan Pengecualian Wajib

Dalam contoh-contoh sebelumnya, mendeklarasikan subrutin akar() yang dapat melempar


pengecualian IllegalArgumentException adalah sesuatu yang "sopan" untuk pembaca rutin
tersebut. Menangani IllegalArgumentException bukan sesuatu yang "wajib" dilakukan.
Subruin dapat melempar IllegalArgumentException tanpa mengumumkan kemungkinan
tersebut. Kemudian program yang memanggil rutin tersebut bebas untuk menangkap atau
membiarkan pengecualian yang dilempar oleh rutin tersebut. Begitu juga halnya dengan tipe
NullPointerException[/code, programmer bebas untuk menangkap atau mengabaikan
pengecualian tersebut.</p><p>Untuk kelas pengecualian yang mewajibkan
penanganan pengecualian, siatuasinya sedikit berbeda. Jika suatu subrutin bisa
melempar pengecualian seperti ini, maka klausa [code]throws harus ditulis pada
definisi subrutin. Jika tidak, maka compiler akan menampilkan kesalahan sintaks.

Di sisi lain, misalnya suatu pernyataan dalam program dapat melemparkan pengecualian yang
mewajibkan penanganan pengecualian. Pernyataan tersebut bisa berasal dari pernyataan throw
yang sengaja dilemparkan atau hasil dari pemanggilan suatu subrutin yang melempar
pengecualian tersebut. Pengecualian ini harus ditangani dengan salah satu dari dua cara, yaitu :
Menggunakan pernyataan try yang memiliki klausa catch untuk menangani pengecualian
tersebut. Atau dengan menambahkan klausa throws di kepala definisi subrutin.

Jika klausa throws digunakan, maka subrutin lain yang memanggil subrutin kita akan
bertanggung jawab menangani pengecualian tersebut. Jika kita tidak menangani pengecualian
tersebut dengan cara-cara di atas, maka Java akan menganggap sebagai kesalahan sintaks.

Penanganan pengecualian menjadi wajib untuk kelas yang bukan kelas turunan dari Error atau
RuntimeException. Pengecualian yang wajib biasanya merupakan kondisi yang berada di luar
jangkauan programmer. Misalnya, input ilegal atau aksi ilegal oleh user. Program tangguh harus
bisa menangani kondisi seperti ini. Desain Java tidak memungkinkan programmer untuk
mengabaikan kondisi tersebut.
Di antara pengecualian yang mewajibkan penanganan pengecualian adalah yang berhubungan
dengan rutin input/output. Artinya kita tidak boleh menggunakan rutin ini jika kita mengetahui
bagaimana menangani pengecualian. Bagian berikutnya akan membahas tentang contoh-contoh
input/output dan penanganan pengecualian dengan lebih gamblang.

Pemrograman dengan Pengecualian


Posted Jum, 03/13/2009 - 18:06 by belajarprogram

Versi ramah cetak

Pengecualian bisa digunakan untuk membantu kita menulis program tangguh. Pengecualian
adalah pendekatan yang terstruktur dan terorganisir untuk membuat program tangguh. Tanpa
pengecualian, program akan dipenuhi dengan pernyataan if untuk menguji berbagai macam
kondisi kesalahan. Dengan pengecualian, kita bisa menulis program yang algoritma yang lebih
jelas, di mana kasus-kasus pengecualian akan ditangani di bagian lain, yaitu di dalam klausa
catch.

Membuat Kelas Pengecualian Baru

Ketika suatu program menemukan kondisi yang tidak biasa dan tidak ada cara yang masuk akal
untuk ditangani pada saat itu juga, program akan melempar pegecualian. Dalam beberapa kasus,
mungkin akan lebih mudah apabila pengecualian yang dilemparkan merupakan objek dari salah
satu kelas pengecualian bawaah Java, seperti IllegalArgumentException atau IOException.

Akan tetapi, jika tidak ada kelas standar yang cukup mewakili jenis pengecualian tersebut,
programmer bisa membuat kelas pengecualian baru. Kelas baru tersebut harus diturunkan dari
kelas standar Throwable atau kelas turunannya. Secara umum, kelas baru merupakan turunan
dari kelas RuntimeExceptionatau kelas turunannya jika programmer tidak mewajibkan
penanganan kesalahan. Untuk membuat kelas pengecualian baru yang mewajibkan penanganan
kesalahan, programmer dapat membuat turunan dari kelas Exception atau salah satu kelas
turunannya.

Berikut ini adalah contoh suatu kelas yang merupakan turunan dari kelas Exception yang
mewajibkan penanganan kesalahan apabila ia dilemparkan :

public class KelasahanBaca extends Exception {


public KelasahanBaca(String pesan) {
// Konstruktor. Membuat objek dari KesalahanBaca yang berisi
// pesan kesalahan
super(pesan);
}
}

Kelas tersebut hanya memiliki konstruktor sehingga kita bisa membuat objek dari kelas
KesalahanBaca yang berisi pesan kesalahan. (Pernyataan "super(pesan)" memanggil
konstruktor di kelas supernya, yaitu Exception. Lihat bagian sebelumnya). Tentunya kelas
tersebut juga mewariskan metode getMessage() dan printStackTrace() dari kelas supernya.
Jika e merujuk pada objek dengan tipe KesalahanBaca maka perintah e.getMessage() akan
mengambil pesan kesalahan yang diberikan pada konstruktornya.

Apabila objek dengan tipe KesalahanBaca dilempar, ini berarti jenis kesalahan tertentu telah
terjadi. (Mungkin misalnya terjadi apabila pembacaan suatu String yang diproses program tidak
sesuai dengan format yang diharapkan).

Pernyataan throw bisa digunakan untuk melempar kesalahan dengan tipe KesalahanBaca.
Konstruktor objek ini harus memiliki pesan kesalahan, misalnya :

throw new ParseError("Ditemukan bilangan negatif ilegal.");

atau

throw new ParseError("Kata '" + word + "' bukan nama file yang benar.");

Jika pernyataan throw tidak terdapat dalam pernyataan try yang menangkap kesalahan tersebut,
maka subrutin yang melemparnya harus dideklarasikan di awal bahwa subrutin tersebut bisa
melempar KesalahanBaca, yaitu dengan menambah klausa "throws KesalahanBaca".
Misalnya :

void ambilNamaUser() throws KesalahanBaca {


. . .
}

Klausa ini tidak diperlukan apabila KesalahanBaca didefinisikan sebagai turunan dari kelas
RuntimeException, karena pengecualian ini tidak wajib untuk ditangani.

Suatu subrutin yang ingin menangani KesalahanBaca dapat menggunakan pernyataan try
dengan klausa catch untuk menangkap KesalahanBaca. Misalnya

try {
ambilNamaUser();
olahNamaUser();
}
catch (KesalahanBaca kb) {
. . . // Tangani kesalahan
}

Ingat bahwa karena KesalahanBaca adalah kelas turunan dari Exception, maka klausa catch
dalam bentuk "catch (Exception e)" juga akan menangkap KesalahanBaca dan juga objek
yang bertipe Exception.

Kadang-kadang, ada gunanya untuk menyimpan data dalam objek pengecualian, misalnya :

class KapalMeledak extends RuntimeException {


Kapal kapal; // Kapal yang meledak
 int lokasi_x, lokasi_y; // Lokasi tempat kapal meledak
 KapalMeledak(String pesan, Kapal k, int x, int y) {
// Konstruktor: Buat objek KapalMeledak yang menyimpan
 // pesan kesalahan dan informasi bahwa kapal k
// meledak pada lokasi x,y pada layar
super(pesan);
kapal = k;
lokasi_x = x;
lokasi_y = y;
}
}

Di sini, objek KapalMeledak berisi pesan kesalahan dan informasi tambahan tentang kapal yang
meledak, yang bisa digunakan dalam perintah berikut:

if ( kapalUser.isTertembak() )
throw new KapalMeledak("Anda Tertembak!", kapalUser, xLok, yLok);

Ingat bahwa kondisi objek KapalMeledak mungkin bukan suatu kesalahan. Mungkin hanya
merupakan jalan lain dari alur suatu game. Pengecualian bisa juga digunakan sebagai
percabangan besar seperti ini dengan cara yang lebih rapi.

Kelas dan Subrutin Pengecualian

Kemungkinan untuk melempar pengecualian akan berguna dalam penulisan subrutin dan kelas
umum yang digunakan oleh lebih dari satu program. Dalam hal ini orang yang menulis subrutin
atau kelas tersebut tidak memiliki cara yang umum untuk menangani kesalahan tersebut.
Terutama karena ia tidak tahu bagaimana subrutin atau kelas tersebut akan digunakan. Dalam
kondisi seperti itu, programmer pemula biasanya lebih memilih untuk mencetak pesan kesalahan
dan melanjutkan program, akan tetapi cara ini tidak memuaskan karena mungkin akan ada
masalah di kemudian hari. Mencetak pesan kesalahan dan menghentikan program juga bukan
solusi karena program tidak berkesempatan untuk mengatasi kesalahan tersebut.

Program yang memanggil subrutin atau menggunakan kelas tersebut perlu tahu bahwa suatu
kesalahan telah terjadi. Dalam bahasa yang tidak memiliki pengecualian, satu-satunya alternatif
adalah mengembalikan nilai khusus atau mengeset nilai variabel tertentu untuk memberi tahu
bahwa suatu kesalahan telah terjadi. Misalnya, fungsi ambilDouble() bisa saja mengembalikan
nilai NaN jika input dari user salah. Akan tetapi, cara ini hanya efektif jika program utama
mengecek nilai keluarannya. Pengecualian akan lebih rapi jika suatu subrutin memiliki cara
untuk tahu apabila suatu kesalahan telah terjadi.

Asersi

Ingat bahwa kondisi awal adalah kondisi yang harus benar pada suatu titik di dalam program
sehingga program akan berjalan benar dari titik tersebut dan seterusnya. Dalam hal ini, ada
kemungkin bahwa suatu kondisi awal mungkin tidak bisa dipenuhi. Untuk itu, akan lebih baik
jika kita letakkan pernyataan if untuk mengujinya. Pertanyaan berikutnya adalah apa yang harus
kita lalukan jika kondisi awal tidak benar? Salah satunya adalah melempar pengecualian, yang
kemudian akan menghentikan program kecuali jika pengecualian tersebut ditangkap dan
ditangani di tempat lain.

Bahasa pemrograman seperti C dan C++ memiliki fasilitas untuk menambah asersi (assertions)
dalam program. Asersi dapat berbentuk assert(kondisi), di mana kondisi adalah ekspresi
bernilai boolean. Kondisi adalah suatu kondisi awal yang harus benar pada satu titik di dalam
program. Ketika komputer menemukan asersi dalam eksekusi suatu program, ia akan
mengevaluasi kondisi tersebut. Jika kondisi tersebut salah, maka program akan berhenti. Jika
benar, maka program akan terus berjalan. Asersi dalam bentuk ini tidak tersedia pada Java, akan
tetapi sesuatu yang mirip seperti ini bisa dilakukan dengan pengecualian.

Bentuk asersi assert(kondisi) dapat diganti dalam bahasa Java dalam bentuk :

if (kondisi == false)
throw new IllegalArgumentException("Asersi gagal.");

Kita bisa mengganti pesan kesalahan dengan pesan yang lebih baik, dan mungkin akan lebih
cantik apabila kelas pengecualiannya juga diganti dengan kelas yang lebih spesifik.

Asersi sangat umum digunakan dalam pengujian dan debugging. Setelah kita merilis program
kita, kita tidak ingin program kita crash. Akan tetapi banyak program yang dibuat pada dasarnya
seperti

try {
.
. // Jalankan program
.
}
catch (Exception e) {
System.out.println("Pengecualian dalam program terjadi.");
System.out.println("Harap kirimkan pesan bug kepada programmernya.");
System.out.println("Detail kesalahan:"):
e.printStackTrace();
}

Jika suatu program memiliki banyak asersi, maka akan menyebabkan program lebih lambat.
Salah satu keuntungan asersi pada C dan C++ adalah asersi bisa "dimatikan". Dalam arti jika
program dikompilasi dengan cara lain, maka asersi akan dibuang dari dalam program utama.
Versi rilis dari program dikompilasi dengan asersi yang dimatikan. Dengan cara ini versi rilis
akan lebih efisien, karena komputer tidak perlu mengevaluasi semua asersi tersebut. Keuntungan
lainnya adalah kita tidak perlu membuang asersi tersebut dari kode sumber programnya.

Ada cara seperti ini yang mungkin juga bisa diterapkan pada Java, yang tergantung dari seberapa
canggih kompiler kita. Misalnya kita tentukan suatu konstanta

static final boolean DEBUG = true;

dan kita menulis asersi seperti


if (DEBUG == true && kondisi <span style="color: #00bb00;"></span>== false)
throw new IllegalArgumentException("Asersi Gagal.");

Karena DEBUG bernilai true, maka nilai "DEBUG == true && kondisi == false" sama dengan
nilai kondisi, sehingga pernyataan if ini sama dengan pengujian suatu kondisi awal. Sekarang
misalnya kita telah selesai melakukan debugging. Sebelum kita mengkompilasi versi rilis suatu
program, kita ganti definisi DEBUG menjadi

static final boolean DEBUG = false;

Sekarang, nilai "DEBUG == true && kondisi == false" selalu bernilai false, dan kompiler
canggih akan bisa mendeteksi ini pada saat kompilasi. Karena nilai if ini akan selalu bernilai
false, kompiler canggih akan mengabaikan perintah ini dalam hasil kompilasinya, karena if ini
tidak akan pernah dieksekusi. Hasilnya, kode ini tidak akan dimasukkan ke dalam versi rilis
program. Dan kita hanya cukup mengganti satu baris saja pada kode sumbernya.

Bab VIII - Pengenalan Struktur Data dan Algoritma


Posted Kam, 03/19/2009 - 22:44 by belajarprogram

Versi ramah cetak

Komputer bisa menjadi canggih seperti sekarang karena struktur data. Struktur dala adalah
koleksi dari suatu data yang saling berhubungan. Suatu objek adalah struktur data, tapi tipe
struktur data seperti ini -- yang memiliki sedikit variabel instansi -- hanya awalnya saja. Dalam
banyak hal, programmer akan membuat struktur data kompleksnya sendiri, yaitu dengan
menghubungkan objek satu sama lain.

Bab ini akan membahas tentang array dan beberapa struktur data dalam Java.

 Array
 Pencarian, Pengurutan dan Rekursi
 Struktur Data Berantai

Array
Posted Kam, 03/19/2009 - 22:57 by belajarprogram

Versi ramah cetak

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

 Membuat dan Menggunakan Array


 Pemrograman dengan Array
 Array Dinamis
 ArrayLists dan Vector
 Array Multi Dimensi

Membuat dan Menggunakan Array


Posted Kam, 03/19/2009 - 23:25 by belajarprogram

Versi ramah cetak

Jika sekumpulan data digabungkan dalam satu unit, hasilnya adalah suatu struktur data. Data
struktur dapat berupa struktur yang sangat kompleks, akan tetapi dalam banyak aplikasi, data
struktur yang cocok hanya terdiri dari kumpulan data berurutan. Struktur data sederhana seperti
ini bisa berupa array atau record.

Istilah "record" sebetulnya tidak digunakan pada Java. Suatu record pada intinya mirip dengan
objek pada Java yang hanya memiliki variabel instansi tanpa metode instansi. Beberapa bahasa
pemrograman lain yang tidak mendukung objek biasanya mendukung record. Dalam bahasa C
yang bukan bahasa berorientasi objek, misalnya, memiliki tipe data record, dimana pada C
disebut "struct". Data pada record -- dalam Java, adalah variabel instansi suatu objek -- disebut
field suatu record. Masing-masing item disebut nama field. Dalam Java, nama field adalah nama
variabel instansi. Perbedaan sifat dari suatu record adalah bahwa item pada record dipanggil
berdasarkan namanya, dan field yang berbeda dapat berupa tipe yang berbeda. Misalnya, kelas
Orang didefisikan sebagai :

class Orang {
String nama;
int nomorID;
Date tanggalLahir;
int umur;
}

maka objek dari kelas Orang bisa disebut juga sebagai record dengan 4 field. Nama fieldnya
adalah nama, nomorID, tanggalLahir dan umur. Lihat bahwa tipe datanya berbeda-beda yaitu
String, int, dan Date.

Karena record hanya merupakan bagian lebih kecil dari objek, kita tidak akan bahas lebih lanjut
di sini.

Seperti record, suatu array adalah kumpulan item. Akan tetapi, item pada record dipanggil
dengan nama, sedangkan item pada array dinomori, dan masing-masing item dipanggil besarkan
nomor posisi pada array tersebut. Semua item pada array harus bertipe sama. Definisi suatu
array adalah : kumpulan item bernomor yang semuanya bertipe sama. Jumlah item dalam suatu
array disebut panjang array. Nomor posisi dari array disebut indeks item tersebut dalam array.
Tipe dari item tersebut disebut tipe dasar dari array.

Tipe dasar suatu array bisa berupa tipe Java apa saja, baik berupa tipe primitif, nama kelas, atau
nama interface. Jika tipe dasar suatu array adalah int, maka array tersebut disebut "array int".
Suatu array bertipe String disebut "array String". Akan tetapi array bukan urutan int atau
urutan String atau urutan nilai bertipe apapun. Lebih baik jika array adalah urutan variabel
bertipe int atau String atau tipe lainnya.

Seperti biasa, ada dua kemungkinan kegunaan variabel : sebagai nama suatu lokasi di memori,
dan nama suatu nilai yang disimpan pada lokasi memori. Setiap posisi pada array bersifat seperti
variabel. Setiap posisi dapat menyimpan nilai dengan tipe tertentu (yaitu tipe dasar array). Isinya
bisa diganti kapanpun. Nilai tersebut disimpan di dalam array. Array merupakan kontainer bukan
kumpulan nilai.

Item pada array (maksudnya setiap anggota variabel dalam array tersebut) sering juga disebut
elemen array. Dalam Java, elemen array selalu dinomori mulai dari nol. Yaitu, indeks dari
elemen pertama suatu array adalah nol. Jika panjang array adalah N, maka indeks elemen
terakhir adalah N-1. Sekali array dibuat, maka panjangnya tidak bisa diubah lagi.

Dalam Java, array adalah objek. Ada beberapa konsekuensi yang lahir dari fakta ini. Array harus
dibuat dengan operator new. Variabel tidak bisa menyimpan array; variabel hanya bisa merujuk
pada array. Variabel lain yang bisa merujuk array juga bisa bernilai null yang berarti ia tidak
merujuk pada lokasi memori apapun. Seperti objek lain, array juga bagian dari suatu kelas, di
mana seperti kelas lain adalah kelas turunan dari kelas Object. Elemen array pada dasarnya
adalah variabel instansi dalam objek array, kecuali mereka dipanggil dalam indeksnya bukan
namanya.

Meskipun array berupa objek, ada beberapa perbedaan antara array dan objek lainnya, dan ada
beberapa fitur khusus Java untuk membuat dan menggunakan array.

Misalnya A adalah variabel yang merujuk pada suatu array. Maka indeks k di dalam A bisa
dipanggil dengan A[k]. Item pertama adalah A[0], yang kedua adalah A[i], dan seterusnya. A[k]
adalah suatu variabel dan bisa digunakan seperti variabel lainnya. Kita bisa memberinya nilai,
bisa menggunakannya dalam ekspresi, dan bisa diberikan sebagai parameter pada subrutin.
Semuanya akan didiskusikan di bawah nanti. Untuk sekarang ingat sintaks berikut

variabel_array [ekspresi_integer]

untuk merujuk pada suatu array.


Meskipun setiap array merupakan suatu objek, kelas array tidak harus didefinisikan sebelumnya.
Jika suatu tipe telah ada, maka kelas array dari tipe tersebut otomatis ada. Jika nama suatu tipe
adalah TipeDasar, maka nama kelas arraynya adalah TipeDasar[]. Artinya, suatu objek yang
diciptakan dari kelas TipeDasar[] adalah array dari item yang tiap itemnya bertipe TipeDasar.
Tanda kurung "[]" dimaksudkan untuk mengingat sintaks untuk mengambil item di dalam suatu
array. "TipeDasar[]" dibaca seperti "array TipeDasar". Mungkin perlu juga dijelaskan bahwa
jika KelasA adalah kelas turunan dari KelasB maka KelasA[] otomatis menjadi kelas turunan
KelasB[].

Tipe dasar suatu array dapat berupa tipe apapun yang ada atau sudah didefinisikan pada Java.
Misalnya tipe primitif int akan diturunkan kelas array int[]. Setiap elemen di dalam array
int[] adalah variabel yang memiliki tipe int dan bisa diisi dengan nilai dengan tipe int. Dari
kelas yang bernama String diturunkan tipe array String[]. Setiap elemen di dalam array
String[] adalah variabel dengan tipe String, yang bisa diisi dengan nilai bertipe String. Nilai
ini bisa null atau referensi ke objek yang bertipe String (dan juga kelas turunan dari String)

Mari kita lihat contoh lebih konkrotnya menggunakan array bilangan bulat sebagai contoh
pertama kita. Karena int[] adalah sebuah kelas, maka kita bisa menggunakannya untuk
mendeklarasikan variabel. Misalnya,

int[] daftar;

yang membuat variabel bernama daftar dengan tipe int[]. Variabel ini bisa menunjuk pada
array int, akan tetapi nilai awalnya adalah null (jika merupakan variabel anggota suatu kelas)
atau tak tentu (jika merupakan variabel lokal di dalam suatu metode). Operator new digunakan
untuk membuat objek array baru, ayng kemudian bisa diberikan kepada daftar. Sintaksnya
sama seperti sintaks sebelumnya, yaitu :

daftar = new int[5];

membuat array 5 buah integer. Lebih umum lagi, konstruktor "new TipeDasar[N]" digunakan
untuk membuat array bertipe TipeDasar[]. Nilai N di dalam kurung menyatakan panjang array,
atau jumlah elemen yang bisa ditampung. Panjang array adalah variabel instansi di dalam objek
array, sehingga array tahu berapa panjangnya. Kita bisa mendapatkan panjang suatu array,
misalnya daftar menggunakan daftar.length (akan tetapi kita tidak bisa mengubahnya)

Hasil dari pernyataan "daftar = new int[5];" dapat diilustrasikan sebagai berikut
Perlu dicatat bahwa array integer secara otomatis diisi dengan nol. Dalam Java, array yang baru
dibuat akan selalu diisi dengan nilai tertentu: nol untuk angka, false untuk boolean, karakter
dengan nilai Unicode 0 untuk char dan null untuk objek.

Elemen di dalam array daftar dapat dirujuk dengan daftar[0], daftar[1], daftar[2],
daftar[3], dan daftar[4] (ingat juga bahwa nilai indeks terbesar adalah panjangnya array
dikurang satu). Akan tetapi, referensi array sebetulnya lebih umum lagi. Tanda kurung di dalam
referensi array bisa berisi ekspresi apapun yang nilainya suatu integer. Misalnya jika idks adalah
variabel bertipe int, maka daftar[idks] dan daftar[2*idks+3] secara sintaks benar.

Contoh berikut akan mencetak semua isi integer di dalam array daftar ke layar :

for (int i = 0; i < daftar.length; i++) {


System.out.println( daftar[i] );
}

Perulangan pertama adalah ketika i = 0, dan daftar[i] merujuk pada daftar[0]. Jadi nilai
yang disimpan pada variabel daftar[0] akan dicetak ke layar. Perulangan kedua adalah i = 1,
sehingga nilai daftar[i] dicetak. Perulangan berhenti setelah mencetak daftar[4] dan i
menjadi sama dengan 5, sehingga kondisi lanjutan "i < daftar.length" tidak lagi benar. Ini
adalah contoh umum dari menggunakan perulangan untuk mengolah suatu array.

Penggunaan suatu variabel dalam suatu program menyatakan lokasi di memori. Pikirkan sesaat
tentang apa yang akan komputer lakukan ketika ia menemukan referensi ke elemen suatu array
daftar[k] ketika program berjalan. Komputer harus menentukan lokasi memori di mana ia
dijadikan referensi. Untuk komputer, daftar[k] berarti : "Ambil pointer yang disimpan di
dalam variabel daftar. Ikuti pointer ini untuk mencari objek array. Ambil nilai k. Pergi ke posisi
ke-k dari array tersebut, dan di sanalah alamat memori yang Anda ingin."

Ada dua hal yang bisa salah di sini. Misalnya nilai daftar adalah null. Dalam kasus ini, maka
daftar tidak memiliki referensi sama sekali. Percobaan merujuk suatu elemen pada suatu array
kosong adalah suatu kesalahan. Kasus ini akan menampilkan pesan kesalahan "pointer kosong".
Kemungkinan kesalahan kedua adalah jika daftar merujuk pada suatu array, akan tetapi k
berada di luar rentang indeks yang legal. Ini akan terjadi jika k < 0 atau jika k >=
daftar.length. Kasus ini disebut kesalahan "indeks array keluar batas". Ketika kita
menggunakan array dalam program, kita harus selalu ingat bahwa kedua kesalahan tersebut
mungkin terjadi. Dari kedua kasus di atas, kesalahan indeks array keluar batas adalah kesalahan
yang lebih sering terjadi.

Untuk suatu variabel array, seperti variabel lainnya, kita bisa mendeklarasikan dan mengisinya
dengan satu langkah sekaligus, misalnya :

int[] daftar = new int[5];

Jika daftar merupakan variabel lokal dalam subrutin, maka perintah di atas akan persis sama
dengan dua perintah :

int[] daftar;
daftar = new int[5];

(Jika daftar adalah variabel instansi, tentukan kita tidak bisa mengganti "int[] daftar = new
int[5];" dengan "int[] daftar; daftar = new int[5];" karena ini hanya bisa dilakukan
di dalam subrutin)

Array yang baru dibuat akan diisi dengan nilai awal yang tergantung dari tipe dasar array
tersebut seperti dijelaskan sebelumnya. Akan tetapi Java juga menyediakan cara untuk memberi
isi array baru dengan daftar isinya. Dalam pernyataan yang untuk membuat array, ini bisa
dilakukan dengan menggunakan penginisialiasi array (array initializer), misalny :

int[] daftar = { 1, 4, 9, 16, 25, 36, 49 };

akan membuat array baru yang berisi 7 nilai, yaitu 1, 4, 9, 16, 25, 36, dan 49, dan mengisi
daftar dengan referensi ke array baru tersebut. Nilai daftar[0] berisi 1, nilai daftar[1] berisi
4, dan seterusnya. Panjang daftar adalah 7, karena kita memberikan 7 nilai awal kepada array
ini.

Suatu penginisialisasi array memiliki bentuk daftar angka yang dipisahkan dengan koma dan
diapit dengan tanda kurung kurawal {}. Panjang array tersebut tidak perlu diberikan, karena
secara implisit sudah bisa ditentukan dari jumlah daftar angkanya. Elemen di dalam
penginisialisasi array tidak harus selalu berbentuk konstanta. Juga bisa merupakan variabel atau
ekspresi apa saja, asalkan nilainya bertipe sama dengan tipe dasar array tersebut. Misalnya,
deklarasi berikut membuat array dari delapan jenis Color beberapa warna telah dibentuk dengan
ekspresi "new Color(r,g,b);"

Color[] palette =
{
Color.black,
Color.red,
Color.pink,
new Color(0,180,0), // hijau gelap
Color.green,
Color.blue,
new Color(180,180,255), // biru muda
Color.white
};

Inisialisasi array bentuk seperti ini hanya bisa digunakan dalam deklarasi suatu variabel baru,
akan tetapi tidak bisa digunakan seperti operator pemberi nilai (=) di tengah-tengah suatu
program. Akan tetapi ada cara lain yang bisa digunakan sebagai pernyataan pemberian nilai atau
diberikan ke dalam subrutin. Yaitu menggunakan jenis lain dari operator new untuk membuat
atau menginisialisasi objek array baru. (Cara ini agak kaku dengan sintaks aneh, seperti halnya
sintaks kelas anonim yang telah didiskusikan sebelumnya). Misalnya untuk memberi nilai
kepada suatu variabel daftar, kita bisa menggunakan :

daftar = new int[] { 1, 8, 27, 64, 125, 216, 343 };

Sintaks umum dari bentuk operator new seperti ini adalah

new TipeDasar [ ] { daftar_nilai_nilai }

Ini adalah suatu ekspresi yang isinya merupakan objek, dan bisa digunakan untuk banyak situasi
di mana suatu objek dengan tipe TipeDasar dipentingkan. Misalnya buatTombol merupakan
metode yang mengambil array String sebagai parameter, maka kita bisa menuliskan

buatTombol( new String[] { "Stop", "Jalan", "Berikut", "Sebelum" } );

Catatan terakhir : untuk alasan sejarah, maka deklarasi

int[] daftar;

akan bernilai sama dengan

int daftar[];

di mana sintaks tersebut digunakan dalam bahasa C dan C++. Akan tetapi sintaks alternatif ini
tidak begitu masuk akan dalam Java, atau mungkin lebih baik dihindari. Lagian, maksudnya
adalah mendeklarasikan variabel dengan tipe tertentu dan namanya adalah int[]. Akan lebih
masuk akan untuk mengikuti siintaks "nama_tipe nama_variabel" seperti pada bentuk bertama.

Pemrograman dengan Array


Posted Sab, 03/21/2009 - 01:29 by belajarprogram

Versi ramah cetak


Array merupakan jenis struktur data yang sangat dasar dan sangat penting. Teknik pengolahan
array merupakan teknik pemrograman yang paling penting yang kita harus kuasai. Dua jenis
teknik pengolahan array -- pencarian dan pengurutan -- akan dibahas kemudian. Bagian ini akan
memperkenalkan beberapa ide dasar pengolahan array secara umum.

Dalam banyak hal, pengolahan array berarti menggunakan operasi yang sama kepada setiap
elemen di dalam array. Biasanya sering dilakukan dengan perulangan for. Perulangan untuk
mengolah semua elemen dalam array A dapat ditulis dalam bentuk :

// lakukan inisialiasi yang diperlukan sebelumnya


for (int i = 0; i < A.length; i++) {
. . . // proses A[i]
}

Misalnya, A adalah array dengan tipe double[]. Misalnya kita ingin menjumlah semua nilai
dalam array tersebut. Algoritma umum untuk melakukannya adalah :

Mulai dengan 0;
Tambah A[0]; (proses elemen pertama di dalam A)
Tambah A[1]; (proses elemen kedua di dalam A)
.
.
.
Tambah A[ A.length - 1 ]; (proses elemen terakhir di dalam A)

Dengan menggunakan pengetahuan yang kita telah pelajari tentang perulangan, kita bisa ubah
algoritma di atas menjadi bentuk perulangan for seperti berikut:

double jumlah; // Jumlah nilai di dalam A


jumlah = 0; // Mulai dengan 0
for (int i = 0; i < A.length; i++)
jumlah += A[i]; // tambah A[i] ke dalam jumlah untuk i = 0, 1, ...,
A.length - 1

Lihat bahwa kondisi kelanjutan "i < A.length" menyatakan bahwa nilai i terakhir yang akan
diolah adalah A.length - 1 yaitu elemen terakhir dalam array. Ingat bahwa kita menggunakan
"<" bukan "<=" karena dengan "<=" komputer akan memberikan kesalahan indeks di luar batas.

Pada akhirnya, nanti Anda akan bisa membuat perulangan seperti di atas di luar kepala. Kita
akan lihat beberapa contohnya. Di sini perulangan akan menghitung banyaknya elemen di dalam
array A yang nilainya kurang dari nol :

int hitung; // Untuk menghitung elemen


hitung = 0; // Mulai dengan nol
for (int i = 0; i < A.length; i++) {
if (A[i] < 0.0) // Jika elemen ini kurang dari nol
hitung++; // tambah hitung dengan 1
}
// Di sini nilai "hitung" adalah banyaknya elemen yang kurang dari 0.
Kita bisa mengganti "A[i] < 0.0" jika kita ingin menghitung banyaknya elemen di dalam array
yang memiliki sifat tertentu. Variasinya akan memiliki tema yang sama. Misalnya kita ingin
menghitung banyaknya elemen di dalam array A yang sama dengan elemen sesudahnya. Elemen
setelah A[i] adalah A[i+1], sehingga kita bisa mengganti klausa if dengan "if (A[i] ==
A[i+1])". Akan tetapi tunggu dulu : Tes ini tidak bisa digunakan apabila A[i] adalah elemen
terakhir dalam array, karena tidak ada lagi array sesudahnya. Komputer akan menolak
pernyataan ini. Sehingga kita harus berhenti satu elemen sebelum array terakhir, sehingga
menjadi

int hitung = 0;
// lihat kondisi for berubah dibandingkan dengan contoh sebelumnya
for (int i = 0; i < A.length - 1; i++) {
if (A[i] == A[i+1])
hitung++;
}

Masalah umum lainnya adalah mencari nilai terbesar di dalam array A. Strateginya adalah lihat
semua isi array, catat nilai terbesar saat itu. Kita akan simpan nilai terbesar yang kita temui
dalam variabel maks. Pada saat kita melihat elemen array satu per satu, kapanpun kita melihat
nilai elemen tersebut lebih besar dari maks kita akan mengganti nilai maks dengan nilai yang
lebih besar tersebut. Setelah semua elemen array diproses, maka maks merupakan nilai elemen
terbesar di dalam array tersebut. Pertanyaannya adalah, apa nilai awal maks? Salah satu
kemungkinannya adalah mulai dengan nilai maks sama dengan A[0], baru kemudian melihat isi
elemen array lainnya mulai dengan A[1]. Misalnya,

double maks = A[0]; // nilai maks berisi elemen array pertama


for (int i = 1; i < A.length; i++) { // i mulai dari elemen kedua
if (A[i] > maks)
max = A[i];
}
// Di sini maks berisi nilai elemen array yang paling besar

(Ada masalah yang lebih penting di sini. Java membolehkan array memiliki panjang nol. Artinya
bahkan A[0] pun tidak ada di dalam array, sehingga memanggil A[0] akan menghasilkan
kesalahan indeks keluar batas. Akan tetapi array biasanya array dengan panjang nol biasanya
sesuatu yang kita ingin hindarkan dalam kehidupan sehari-hari. Lagian apa artinya mencari nilai
terbesar di dalam suatu array yang panjangnya nol?)

Contoh terakhir dari operasi array, misalnya kita ingin mengkopi suatu array. Untuk mengkopi
array A, tidak cukup untuk menggunakan perintah

double[] B = A;

karena perintah ini tidak membuat objek array baru. Yang dibuat di sini adalah variabel baru
yang merujuk pada objek yang sama dengan A. (Sehingga perubahan yang terjadi pada A[i]
akan juga menyebabkan B[i] berubah). Untuk membuat array baru yang merupakan kopi dari
array A, kita harus membuat objek array baru, dan mengkopi isinya satu per satu dari array A ke
array baru, sehingga
// Buat objek array baru, yang panjangnya sama dengan panjang A
double[] B = new double[A.length];
 
for (int i = 0; i < A.length; i++)
B[i] = A[i]; // Kopi setiap elemen dari A ke B

Mengkopi nilai dari satu array ke array yang lain adalah operasi umum sehingga Java memiliki
subrutin untuk melakukannya, yaitu System.arraycopy(), yang merupakan subrutin anggota
statik dari kelas standar System. Deklarasinya memiliki bentuk seperti :

public static void arraycopy(Object arraySumber, int indeksAwalSumber,


Object arrayTujuan, int indeksAwalTujuan, int jumlah)

di mana arraySumber dan arrayTujuan bisa berbentuk array dengan tipe apapun. Nilai akan
dikopi dari arraySumber ke arrayTujuan. jumlah adalah berapa banyak elemen yang akan
dikopi. Nilai akan dikopi dari arraySumber mulai dari posisi indeksAwalSumber dan akan
disimpan pada arrayTujuan mulai dari posisi indeksAwalTujuan. Misalnya kita akan
mengkopi array A, maka kita bisa menggunakan perintah

double B = new double[A.length];


System.arraycopy( A, 0, B, 0, A.length );

Suatu tipe array, misalnya double[] adalah tipe Java biasa, sehingga kita bisa menggunakannya
seperti tipe-tipe Java lainnya. Termasuk juga digunakan sebagai parameter formal di dalam suatu
subrutin. Juga bisa digunakan sebagai tipe keluaran suatu fungsi. Misalnya, kita bisa menulis
fungsi yang membuat kopi array dengan tipe double sebagai berikut :

double[] kopi( double[] sumber ) {


// Membuat dan mengembalikan kopi array sumber
// Jika sumber null, maka kembalikan null
if ( sumber == null )
return null;
double[] kpi; // Kopi array sumber
kpi = new double[sumber.length];
System.arraycopy( sumber, 0, kpi, 0, sumber.length );
return kpi;
}

Rutin main() memiliki parameter dengan tipe String[] yang merupakan array String. Ketika
sistem memanggil rutin main(), string di dalam array ini adalah parameter dari baris perintah.
Jika kita menggunakan konsol, user harus mengetikkan perintah untuk menjalankan program.
User bisa menambahkan input tambahan dalam perintah ini setelah nama program yang akan
dijalankan.

Misalnya, jika kelas yang memiliki rutin main() bernama programKu, maka user bisa
menjalankan kelas tersebut dengan perintah "java programKu" di konsol. Jika kita tulis dengan
"java programKu satu dua tiga", maka parameter dari baris perintahnya adalah "satu", "dua", dan
"tiga". Sistem akan memasukkan parameter-parameter ini ke dalam array String[] dan
memberikan array ini pada rutin main().

Berikut ini adalah contoh program sederhana yang hanya mencetak parameter dari baris perintah
yang dimasukkan oleh user.

public class CLDemo {


public static void main(String[] args) {
System.out.println("Anda memasukkan " + args.length
+ " parameter dari baris perintah");
if (args.length > 0) {
System.out.println("Parameter tersebut adaah :");
for (int i = 0; i < args.length; i++)
System.out.println(" " + args[i]);
}
} // akhir main()
} // akhir kelas CLDemo

Perhatikan bahwa parameter args tidak mungkin null meskipun tidak ada parameter yang
dimasukkan. Jika tidak ada parameter dari baris perintah yang dimasukkan, maka panjang array
ini adalah nol.

Hingga sekarang, contoh yang telah diberikan adalah bagaimana mengolah array dengan
mengakses elemennya secara berurutan (sequential access). Artinya elemen-elemen array
diproses satu per satu dalam urutan dari awal hingga akhir. Akan tetapi salah satu keuntungan
array adalah bahwa array bisa digunakan untuk mengakses elemennya secara acak, yaitu setiap
elemen bisa diakses kapan saja secara langsung.

Misalnya, kita ambil contoh suatu masalah yang disebut dengan masalah ulang tahun: Misalnya
ada N orang di dalam suatu ruangan. Berapa kemungkinan dua orang di dalam ruangan tersebut
memiliki ulang tahun yang sama (yang dilahirkan pada tanggal dan bulan yang sama, meskipun
tahunnya berbeda)? Kebanyakan orang salah menerka jawabannya. Sekarang kita lihat dengan
versi masalah yang berbeda: Misalnya kita memilih orang secara acak dan menanyakan ulang
tahunnya. Berapa orang yang Anda harus tanya untuk mendapatkan hari ulang tahun yang sama
dengan orang sebelumnya?

Tentunya jawabannya akan tergantung pada faktor yang bersifat acak, akan tetapi kita bisa
simulasikan dengan program komputer dan menjalankan beberapa kali hingga kita tahu berapa
kira-kira orang harus dicek.

Untuk mensimulasikan percobaan ini, kita harus mencatat semua ulang tahun yang kita sudah
tanyakan. Ada 365 kemungkinan hari ulang tahun (Kita abaikan sementara tahun kabisat). Untuk
setiap kemungkinan hari ulang tahun, kita perlu tahu, apakah hari ulang tahun tersebut telah
digunakan? Jawabannya adalah nilai boolean true atau false. Untuk menyimpan data ini, kita bisa
gunakan array dari 365 nilai boolean:
boolean[] sudahDitanya;
sudahDitanya = new boolean[365];

Tanggal-tanggal pada satu tahun dinomori dari 0 hingga 364. Nilai sudahDitanya[i] akan
bernilai true jika orang yang kita tanya berulang tahun pada hari tersebut. Pada awalnya semua
nilai pada array sudahDitanya[i] bernilai false. Ketika kita memilih satu orang dan
menanyakan hari ulang tahunnya, misalnya i, kita akan mengecek terlebih dahulu apakah
sudahDitanya[i] bernilai true. Jika tidak maka orang ini adalah orang kedua dengan ulang
tahun yang sama. Artinya kita sudah selesai.

Jika sudahDitanya[i] bernilai false, maka belum ada orang sebelum ini yang memiliki hari
ulang tahun tersebut. Kita akan ganti sudahDitanya[i] dengan true, kemudian kita akan
tanyakan lagi kepada orang lain, dan begitu seterusnya hingga semua orang di dalam ruangan
ditanyakan.

static void masalahUlangTahun() {


// Melakukan simulasi dengan memilih seseorang secara acak
// dan mengecek hari ulang tahunnya. Jika hari ulang tahunnya
// sama dengan orang yang pernah kita tanya sebelumnya,
// hentikan program dan laporkan berapa orang yang sudah dicek
 
boolean[] sudahDitanya;
// Untuk mencatat ulang tahun yang sudah ditanyakan
// Nilai true pada sudahDitanya[i] berarti orang lain
// sudah ada yang berulang tahun pada hari i
 
int hitung;
// Jumlah orang yang sudah pernah ditanya
 
sudahDitanya = new boolean[365];
// Awalnya, semua nilai adalah false
 
hitung = 0;
 
while (true) {
// Ambil ulang tahun secara acak dari 0 hingga 364
// Jika ulang tahun telah ditanya sebelumnya, keluar
// Jika tidak catat dalam array
 
int ultah; // Ulang tahun seseorang
ultah = (int)(Math.random()*365);
hitung++;
if ( sudahDitanya[ultah] )
break;
sudahDitanya[ultah] = true;
}
 
System.out.println("Ulang tahun yang sama ditemukan setelah menanyakan "
+ hitung + " orang.");
 
} // akhir masalahUlangTahun()
Subrutin ini menggunakan fakta bahwa array boolean yang baru dibuat memiliki seluruh elemen
yang bernilai false. Jika kita ingin menggunakan array yang sama untuk simulasi kedua, kita
harus mereset ulang semua elemen di dalamnya menjadi false kembali dengan perulangan for

for (int i = 0; i < 365; i++)


sudahDitanya[i] = false;

Array paralel adalah menggunakan beberapa array dengan indeks yang sama. Misalnya kita ingin
membuat beberapa kolom secara paralel -- array x di kolom pertama, array y di kolom kedua,
array warna di kolom ketiga, dan seterusnya. Data untuk baris ke-i bisa didapatkan dari masing-
masing array ini. Tidak ada yang salah dengan cara ini, akan tetapi cara ini berlawanan dengan
filosofi berorientasi objek yang mengumpulkan data yang berhubungan di dalam satu objek. Jika
kita mengikuti aturan seperti ini, amaka kita tidak harus membayangkan hubungan data yang
satu dan yang lainnya karena semua data akan dikelompokkan di dalam satu tempat.

Misalnya saya menulis kelas seperti

class DataString {
// Data dari salah satu pesan
int x,y; // Posisi pesan
Color warna; // Warna pesan
}

Untuk menyimpan data dalam beberapa pesan, kita bisa menggunakan array bertipe
DataString[], yang kemudian dideklarasikan sebagai variabel instansi dengan nama data
sehingga

DataString[] data;

Isi dari data bernilai null hingga kita membuat array baru, misalnya dengan

data = new DataString[JUMLAH_PESAN];

Setelah array ini dibuat, nilai setiap elemen array adalah null. Kita ingin menyimpan data di
dalam objek yang bertipe DataString, akan tetapi tidak ada objek yang dibuat. Yang kita sudah
buat hanyalah kontainernya saja. Elemen di dalamnya berupa objek yang belum pernah kita buat.
Untuk itu elemen di dalamnya bisa kita buat dengan perulangan for seperti :

for (int i = 0; i < JUMLAH_PESAN; i++)


data[i] = new DataString();

Sekarang kita bisa mengambil data setiap pesan dengan data[i].x, data[i].y, dan
data[i].warna.
Terakhir berkaitan dengan pernyataan switch. Misalnya kita memiliki nilai bulan dari 0 hingga
11, yang melambangkan bulan dalam satu tahun dari Januari hingga Desember. Kita ingin
mencetaknya di layar, dengan perintah

switch (bulan) {
case 0:
bulanString = "Januari";
break;
case 1:
bulanString = "Februari";
break;
case 2:
bulanString = "Maret";
break;
case 3:
bulanString = "April";
break;
.
.
.
case 11:
bulanString = "Desember";
break;
default:
bulanString = "Salah bulan";
}

Kita bisa mengganti keseluruhan perintah switch tersebut dengan menggunakan array, misalnya
dengan array namaBulan yang dideklarasikan sebagai berikut :

static String[] namaBulan = { "Januari", "Februari", "Maret",


"April", "Mei", "Juni", "Juli", "Agustus", "September",
"Oktober", "November", "Desember" };

Kemudian kita bisa ganti keseluruhan switch di atas dengan

bulanString = namaBulan[bulan];

Sangat mudah bukan?

Array Dinamis
Posted Sab, 03/21/2009 - 01:39 by belajarprogram

Versi ramah cetak

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

Array Setengah Penuh

Bayangkan suatu aplikasi di mana sejumlah item yang ingin kita simpan di dalam array akan
berubah-ubah sepanjang program tersebut berjalan. Karena ukuran array tidak bisa diubah, maka
variabel terpisah digunakan untuk menyimpan berapa banyak sisa tempat kosong yang masih
bisa diisi di dalam array.

Bayangkan misalnya, suatu program yang membaca bilangan bulat positif dari user, kemudian
menyimpannya untuk diproses kemudian. Program akan berhenti membaca input apabila input
yang diterima bernilai 0 atau kurang dari nol. Bilangan input n tersebut kita simpa di dalam array
bilangan dengan tipe int[]. Katakan banyaknya bilangan yang bisa disimpan tidak lebih dari
100 buah. Maka ukuran array bisa dibuat 100.

Akan tetapi program tersebut harus melacak berapa banyak bilangan yang sudah diambil dari
user. Kita gunakan variabel terpisah bernama jmlBilangan. Setiap kali suatu bilangan disimpan
di dalam array, nilai jmlBilangan akan bertambah satu.

Sebagai contoh sederhana, masi kita buat program yang mengambil bilangan yang diinput dari
user, kemudian mencetak bilangan-bilangan tersebut dalam urutan terbalik. (Ini adalah contoh
pengolahan yang membutuhkan array, karena semua bilangan harus disimpan pada suatu tempat.
Banyak lagi contoh program misalnya, mencari jumlah atau rata-rata atau nilai maksimum
beberapa bilangan, bisa dilakukan tanpa menyimpan bilangan tersebut satu per satu)

public class BalikBilanganInput {


 
public static void main(String[] args) {
 
int[] bilangan; // Array untuk menyimpan nilai input dari user
int jmlBilangan; // Banyaknya bilangan yang sudah disimpan dalam
array
int bil; // Bilangan yang diambil dari user
 
bilangan = new int[100]; // Buat array dengan 100 bilangan int
jmlBilangan = 0; // Belum ada bilangan yang disimpan
 
System.out.println("Masukkan bilangan bulat positif (paling banyak 100
bilangan)" +
", masukkan nol untuk mengakhiri.");
 
while (true) {
System.out.print("? ");
bil = KonsolIO.ambilInt();
if (bil <= 0)
break;
bilangan[jmlBilangan] = bil;
jmlBilangan++;
}
 
System.out.println("\nBilangan yang Anda masukkan dalam urutan
terbalik adalah :\n");
 
for (int i = jmlBilangan - 1; i >= 0; i--) {
System.out.println( bilangan[i] );
}
 
} // akhir main();
 
} // akhir kelas BalikBilanganInput

Penting untuk diingat bahwa jmlBilangan memiliki dua peran. Yang pertama, adalah melacak
banyaknya bilangan yang sudah dimasukkan di dalam array. Yang kedua adalah menentukan di
mana indeks kosong berikutnya di dalam array. Misalnya, jika 4 bilangan sudah dimasukkan ke
dalam array, maka bilangan-bilangan tersebut diisi pada array di posisi 0, 1, 2, dan 3. Maka
posisi kosong berikutnya adalah posisi 4.

Ketika kita akan mencetak angka di dalam array, maka poisisi penuh berikutnya adalah di lokasi
jmlBilangan - 1, sehingga perulangan for mencetak bilangan dari jmlBilangan - 1 hingga
0.

Mari kita lihat contoh lain yang lebih realistis. Misalkan kita ingin menulis program game, di
mana pemain bisa masuk ke dalam game dan keluar dari game setiap saat. Sebagai programmer
berorientasi objek yang baik, mungkin kita memiliki kelas bernama Pemain sebagai lambang
pemain di dalam game. Daftar pemain yang sedang ada di dalam game, bisa disimpan di dalam
array ArrayPemain dengan tipe Pemain[].

Karena jumlah pemain bisa berubah-ubah maka kita bisa menggunakan variabel bantu, misalnya
jumlahPemainAktif untuk mencatat banyaknya pemain yang sedang aktif berada di dalam
game. Misalnya jumlah maksimum pemain di dalam game adalah 10 orang, maka kita bisa
mendeklarasikan variabelnya sebagai :

Pemain[] ArrayPemain = new Pemain[10]; // Hingga 10 pemain.


int jumlahPemainAktif = 0; // Di awal game, tidak ada pemain yang aktif

Setelah beberapa pemain masuk ke dalam game, variabel jumlahPemainAktif akan lebih dari 0,
dan objek pemailn akan disimpan dalam array, misalnya ArrayPemain[0], ArrayPemain[1],
ArrayPemain[2], dan seterusnya. Ingat bahwa pemain ArrayPemain[jumlahPemainAktif]
tidak ada. Prosedur untuk menambah pemain baru, secara sederhana :

// Tambah pemain di tempat kosong


ArrayPemain[jumlahPemainAktif] = pemainBaru;
// And increment playerCt to count the new player.
jumlahPemainAktif++;

Untuk menghapus seorang pemain mungkin sedikit lebih sulit karena kita tidak ingin
meninggalkan lubang di tengah-tengah array. Misalnya kita ingin menghapus pemain pada
indeks k pada ArrayPemain. Jika kita tidak peduli urutan pemainnya, maka salah satu caranya
adalah memindahkan posisi pemain terakhir ke posisi pemain yang meninggalkan game,
misalnya :

ArrayPemain[k] = ArrayPemain[jumlahPemainAktif - 1];


jumlahPemainAktif--;

Pemain yang sebelumnya ada di posisi k, tidak lagi ada di dalam array. Pemain yang sebelumnya
ada di posisi jumlahPemainAktif -1 sekarang ada di array sebanyak 2 kali. Akan tetapi
sekarang ia berada di bagian yang valid, karena nilai jumlahPemainAktif kita kurangi dengan
satu. Ingat bahwa setiap elemen di dalam array harus menyimpan satu nilai, akan tetapi satu-
satunya nilai dari posisi 0 hingga jumlahPemainAktif - 1 akan tetap diproses seperti biasa.

Misalnya kita ingin menghapus pemain di posisi k, akan tetapi kita ingin agar urutan pemain
tetap sama. Untuk melakukannya, semua pemain di posisi k+1 ke atas harus dipindahkan satu
posisi ke bawah. Pemain k+ mengganti pemain k yang keluar dari game. Pemain k+2 mengganti
pemain yang pindah sebelumnya, dan berikutnya. Kodenya bisa dibuat seperti

for (int i = k+1; i < jumlahPemainAktif; i++) {


ArrayPemain[i-1] = ArrayPemain[i];
}
jumlahPemainAktif--;

Perlu ditekankan bahwa contoh Pemain di atas memiliki tipe dasar suatu kelas. Elemennya bisa
bernilai null atau referensi ke suatu objek yang bertipe Pemain, Objek Pemain sendiri tidak
disimpan di dalam array, hanya referensinya saja yang disimpan di sana. Karena aturan
pemberian nilai pada Java, objek tersebut bisa saja berupa kelas turunan dari Pemain, sehingga
mungkin juga array tersebut menyimpan beberapa jenis Pemain misalnya pemain komputer,
pemain manusia, atau pemain lainnya, yang semuanya adalah kelas turunan dari Pemain.

Contoh lainnya, misalnya kelas BentukGeometri menggambarkan suatu bentuk geometri yang
bisa digambar pada layar, dan ia memiliki kelas-kelas turunan yang merupakan bentuk-bentuk
khusus, seperti garis, kotak, kotak bertepi bulat, oval, atau oval berisi warna, dan sebagainya.
(BentukGeometri sendiri bisa berbentuk kelas abstrak, seperti didiskusikan sebelumnya).
Kemudian array bertipe BentukGeometri[] bisa menyimpan referensi objek yang bertipe kelas
turunan dari BentukGeometri. Misalnya, perhatikan contoh pernyataan berikut

BentukGeometri[] gambar = new BentukGeometri[100]; // Array untuk menyimpan


100 gambar.
gambar[0] = new Kotak(); // Letakkan beberapa objek di dalam array.
gambar[1] = new Garis(); // (Program betulan akan menggunakan
beberapa
gambar[2] = new OvalBerwarna(); // parameter di sini
int jmlGambar = 3; // Lacak jumlah objek di dalam array

bisa diilustrasikan sebagai berikut.


Array tersebut bisa digunakan dalam program gambar. Array bisa digunakan untuk menampung
gambar-gambar yang akan ditampilkan. Jika BentukGeometri memiliki metode "void
gambarUlang(Graphics g)" untuk menggambar pada grafik g, maka semua grafik dalam array
bisa digambar dengan perulangan sederhana

for (int i = 0; i < jmlGambar; i++)


gambar[i].gambarUlang(g);

Pernyataan "gambar[i].gambarUlang(g);" memanggil metode gambarUlang() yang dimiliki


oleh masing-masing gambar pada indeks i di array tersebut. Setiap objek tahu bagaimana
menggambar dirinya sendiri, sehingga perintah dalam perulangan tersebut sebetulnya melakukan
tugas yang berbeda-beda tergantung pada objeknya. Ini adalah contoh dari polimorfisme dan
pengolahan array.

Array Dinamis

Dalam contoh-contoh di atas, ada batas tententu dalam jumlah elemennya, yaitu 100 int, 100
Pemain, dan 100 BentukGeometris. Karena ukuran array tidak bisa berubah, array tersebut hanya
bisa menampung maksimum sebanyak elemen yang didefinisikan pada pembuatan array. Dalam
banyak kasus, adanya batas maksimum tersebut tidak diinginkan. Kenapa harus bekerja dengan
hanya 100 bilangan bulat saja, bukan 101?

Alternatif yang umum adalah membuat array yang sangat besar sehingga bisa digunakan untuk
dalam kehidupan sehari-hari. Akan tetapi cara ini tidak baik, karena akan sangat banyak memori
komputer yang terbuang karena tidak digunakan. Memori itu mungkin lebih baik digunakan
untuk yang lain. Apalagi jika komputer yang akan digunakan tidak memiliki memori yang cukup
untuk menjalankan program tersebut.
Tentu saja, cara yang lebih baik adalah apabila kita bisa mengubah ukuran array sesuka kita
kapan saja. Ingat bahwa sebenarnya variabel array tidak menyimpan array yang sesungguhnya.
Variabel ini hanya menyimpan referensi ke objek tersebut. Kita tidak bisa membuat array
tersebut lebih besar, akan tetapi kita bisa membuat array baru yang lebih besar, kemudian
mengubah isi variabel array tersebut ke array baru itu.

Tentunya kita harus mengkopi semua isi di array yang lama ke array baru. Array lama akan
diambil oleh pemulung memori, karena ia tidak lagi digunakan.

Mari kita lihat kembali contoh game di atas, di mana ArrayPemain adalah array dengan tipe
Pemain[] dan jumlahPemainAktif[/code] adalah jumlah pemain yang sudah digunakan array
tersebut. Misalnya kita tidak ingin membuat limit banyaknya pemainnya yang bisa ikut main.
Jika pemain baru masuk dan array tersebut sudah penuh, kita akan membuat array baru yang
lebih besar.

Variabel ArrayPemain akan merujuk pada array baru. Ingat bahwa setelah ini dilakukan,
ArrayPemain[0] akan menunjuk pada lokasi memori yang berbeda, akan tetapi nilai
ArrayPemain[0] sama dengan sebelumnya. Berikut ini adalah kode untuk melakukan hal di
atas:

// Tambah pemain baru, meskipun array sudah penuh


 
if (jumlahPemainAktif == ArrayPemain.length) {
// Array sudah penuh. Buat array baru yang lebih besar,
// kemudian kopi isi array lama ke array baru lalu ubah
// ArrayPemain ke array baru.
int ukuranBaru = 2 * ArrayPemain.length; // Ukuran array baru
Pemain[] temp = new Pemain[ukuranBaru]; // Array baru
System.arraycopy(ArrayPemain, 0, temp, 0, ArrayPemain.length);
ArrayPemain = temp; // Ubah referensi ArrayPemain ke array baru.
}
 
// Di sini kita sudah tahu bahwa pasti ada tempat di array baru.
 
ArrayPemain[jumlahPemainAktif] = pemainBaru; // Tambah pemain baru...
jumlahPemainAktif++; // ... dan tambah satu jumlahPemainAktif nya

Jika kita akan melakukan hal ini terus menerus, akan lebih indah jika kita membuat kelas untuk
menangani hal ini. Objek mirip array yang bisa berubah ukuran untuk mengakomodasi jumlah
data yang bisa ia tampung disebut array dinamis. Array dinamis memiliki jenis operasi yang
sama dengan array : mengisi nilai pada posisi tertentu dan mengambil nilai di posisi tertentu.
Akan tetapi tidak ada batas maksimum dari jumlah array (hanya tergantung pada jumlah memori
komputer yang tersedia). Dalam kelas array dinamis, metode put dan get akan
diimplementasikan sebagai metode instansi.

Di sini misalnya, adalah kelas yang mengimplementasikan array dinamis int :

public class ArrayDinamisInt {


private int[] data; // Array untuk menyimpan data
 public DynamicArrayOfInt() {
// Konstruktor.
data = new int[1]; // Array akan bertambah besar jika diperlukan
}
 
public int get(int posisi) {
// Ambil nilai dari posisi tertentu di dalam array.
// Karena semua posisi di dalam array adalah nol, maka
// jika posisi tertentu di luar data array, nilai 0 akan dikembalikan
if (posisi >= data.length)
return 0;
else
return data[posisi];
}
 
public void put(int posisi, int nilai) {
// Simpan nilai ke posisi yang ditentukan di dalam array
// Data array tersebut akan bertambah besar jika diperlukan
 
if (posisi >= data.length) {
// Posisi yang ditentukan berada di luar array data
// Besarkan ukuran array 2x lipat. Atau jika ukurannya masih
// terlalu kecil, buat ukurannya sebesar 2*posisi
 
int ukuranBaru = 2 * data.length;
if (posisi >= ukuranBaru)
ukuranBaru = 2 * posisi;
int[] dataBaru = new int[ukuranBaru];
System.arraycopy(data, 0, dataBaru, 0, data.length);
data = dataBaru;
 
// Perintah berikut hanya untuk demonstrasi
System.out.println("Ukuran array dinamis diperbesar menjadi "
+ ukuranBaru);
}
data[posisi] = nilai;
}
 
} // akhir kelas ArrayDinamisInt

Data pada objek ArrayDinamisInt disimpan dalam array biasa, akan tetapi arraynya akan
dibuang dan diganti dengan array baru yang lebih besar apabila diperlukan. Jika bilangan
adalah variable bertipe ArrayDinamisInt, maka perintah bilangan.put(pos,nilai) akan
menyimpan bilangan pada posisi pos di array dinamis tersebut. Fungsi bilangan.get(pos)
mengambil nilai yang disimpan pada posisi pos.

Pada contoh pertama, kita menggunakan array untuk menyimpan bilangan bulat positif yang
dimasukkan oleh user. Kita bisa menulis ulang program tersebut dengan menggunakan
ArrayDinamisInt. Referensi ke bilangan[i] diganti dengan bilangan.get[i]. Perintah
"bilangan[jmlBilangan] = bil;" kita ganti dengan "bilangan.put(jmlBilangan,bil);".
Berikut ini adalah programnya:

public class BalikBilanganInput {


 
public static void main(String[] args) {
 
ArrayDinamisInt bilangan; // Array untuk menyimpan nilai input dari
user
int jmlBilangan; // Banyaknya bilangan yang sudah disimpan dalam
array
int bil; // Bilangan yang diambil dari user
 
bilangan = new ArrayDinamisInt();
jmlBilangan = 0; // Belum ada bilangan yang disimpan
 
System.out.println("Masukkan bilangan bulat positif, masukkan nol
untuk mengakhiri.");
 
while (true) {
System.out.print("? ");
bil = KonsolIO.ambilInt();
if (bil <= 0)
break;
bilangan.put(jmlBilangan,bil);
jmlBilangan++;
}
 
System.out.println("\nBilangan yang Anda masukkan dalam urutan
terbalik adalah :\n");
 
for (int i = jmlBilangan - 1; i >= 0; i--) {
System.out.println( bilangan.get(i) );
}
 
} // akhir main();
 
} // akhir kelas BalikBilanganInput

ArrayLists dan Vector


Posted Sab, 03/21/2009 - 01:41 by belajarprogram

Versi ramah cetak

ArrayList

Kelas ArrayDinamisInt bisa digunakan jika kita membutuhkan array dengan batas maksimum
yang tak terbatas. Akan tetapi jika kita ingin menyimpan BentukGeometri misalnya, kita harus
membuat kelas baru. Kelas tersebut mungkin bernama ArrayDinamisBentukGeometri, dan
akan tampak sama persis dengan ArrayDinamisInt dengan beberapa perubahan di mana "int"
muncul akan diganti dengan "BentukGeometri". Juga demikian jika kita ingin membuat kelas
ArrayDinamisDouble, ArrayDinamisPemain, dan sebagainya.

Yang agak sedikit lucu adalah kelas tersebut sangat mirip isinya, hanya kelas-kelasnya saja yang
berlainan. Akan sangat lebih baik apabila kita bisa membuat kelas umum yang berlaku untuk
semua kelas. Hal ini disebut dengan pemrograman generik. Beberapa bahasa pemrograman
seperti C++ memiliki fasilitas untuk melakukan pemrograman generik. Java tidak memiliki
fasilitas seperti itu (maksudnya tidak sama persis). Tapi kita bisa membuat sesuatu yang mirip
dengan itu pada Java dengan menggunakan struktur data yang memiliki tipe "Object".

Pada Java, setiap kelas adalah kelas turunan dari kelas yang bernama Object. Artinya setiap
objek dapat dirujuk oleh variabel bertiipe Object. Semua objek dapat dimasukkan dalam array
bertipe Object[]. Jika suatu subrutin memiliki parameter formal bertipe Object, maka objek
apapun bisa diberikan kepada subrutin tersebut.

Jika kita buat kelas ArrayDinamisObject, maka kita bisa menyimpan objek apapun. Ini
sebenarnya bukan programming generik sebenarnya, dan tidak berlaku untuk tipe primitif seperti
int dan double. Sebenarnya, kita tidak perlu membuat kelas ArrayDinamisObject sendiri,
karena Java telah memiliki kelas standar yang dinamakan ArrayList yang sifatnya mirip dengan
yang kita sebutkan sebelumnya.

ArrayList disimpan dalam paket java.util, jadi jika kita ingin menggunakan kelas ArrayList
dalam sebuat program, kita harus memberikan "import java.util.ArrayList;" atau "import
java.util.*;" di awal program kita.

Kelas ArrayList berbeda dengan kelas ArrayDinamisInt dalam arti, objek ArrayList selalu
memiliki ukuran tertentu, dan kita tidak boleh mengambil posisi di luar ukuran ArrayList.
Dalam hal ini, ArrayList mirip seperti array biasa. Akan tetapi, ukuran ArrayList bisa
bertambah kapan saja jika diperlukan. Kelas ArrayList memiliki banyak metode instansi. Kita
akan jelaskan sebagian yang sangat berguna. Misalnya daftar adalah variabel dengan tipe
ArrayList.

 daftar.size() -- Fungsi ini menghasilkan ukuran ArrayList saat ini. Posisi valid dalam
daftar adalah yang bernomor 0 hingga daftar.size() - 1. Ingat bahwa ukurannya bisa nol.
Panggilan konstruktor new ArrayList() akan membuat ArrayList dengan ukuran nol.
 daftar.add(obj) -- Menambah objek di akhir ArrayList, kemudian menambah ukurannya
dengan 1. Parameter obj merujuk pada objek dengan tipe apapun, atau bisa bernilai null.
 daftar.get(N) -- Mengambil nilai yang disimpan pada posisi N pada ArrayList. N harus
bertipe bilangan bulat antara 0 hingga daftar.size() - 1. Jika N berada di luar rentang ini,
pesan kesalahan akan ditampilkan. Memanggil fungsi ini mirip dengan memanggil array seperti
A[N] untuk suatu array A. Akan tetapi kita tidak bisa menggunakan daftar.get(N) pada
ekspresi di sebelah kiri daftar.get(N) = 5 tidak boleh dilakukan)
 daftar.set(N, obj) -- Mengisi suatu objek obj di posisi N dari suatu ArrayList, dan
mengganti apapun yang sudah disimpan sebelumnya pada posisi N. Bilangan bulat N harus
berada pada rentang 0 hingga daftar.size() - 1. Perintah ini mirip dengan perintah A[N]
= obj pada array A.
 daftar.remove(obj) -- Jika objek tersebut ada di dalam ArrayList, maka objek tersebut
akan dibuang. Elemen lain setelah posisi objek tersebut di dalam ArrayList akan digeser satu
posisi. Kemudian ukuran ArrayList akan berkurang 1. Jika obj terdapat dalam ArrayList
lebih dari satu kali, hanya yang pertama saja yang dibuang.
 daftar.remove(N) -- Untuk bilangan bulat N, maka perintah ini akan menghapus posisi ke-N
pada ArrayList. N harus berada pada rentang 0 hingga daftar.size() - 1. Elemen setelah
ini akan digeser satu posisi. Kemudian ukuran ArrayList berkurang 1.
 daftar.indexOf(obj) -- Fungsi untuk mencari suatu objek obj di dalam ArrayList. Jika objek
ditemukan, maka posisinya di dalam ArrayList akan dikembalikan. Jika tidak, maka fungsi ini
akan mengembalikan -1.

Misalnya,kita akan membuat pemain dalam game yang digambarkan dengan objek dengan tipe
Pemain. Pemain yang berada dalam game disimpan dalam ArrayList bernama paraPemain.
Variabel ini dideklarasikan seperti :

ArrayList paraPemain;

dan kita inisialisasikan dengan objek kosong dengan perintah

paraPemain = new ArrayList();

Jika pemainBaru adalah variabel yang bertipe Pemain, maka pemain baru tersebut bisa
ditambahkan ke dalam ArrayList dan ke dalam game dengan perintah :

paraPemain.add(pemainBaru);

dan jika pemain nomor i keluar dari game, maka kita hanya perlu memberikan perintah

paraPemain.remove(i);

Atau jika pemain adalah objek bertipe Pemain yang akan kita keluarkan dari game, maka kita
bisa menggunakan perintah

paraPemain.remove(pemain);

Semuanya terlihat sangat mudah. Satu-satunya kesulitan yang akan kita temui adalah ketika kita
ingin mengambil nilai yang disimpan pada posisi i di dalam ArrayList. Tipe keluaran fungsi ini
adalah Object. Dalam hal ini objek yang diambil oleh fungsi ini sebenarnya bertipe Pemain.
Supaya kita bisa menggunakan hasil keluarannya, maka kita perlu menggunakan casting tipe
untuk mengubahnya menjadi tipe Player, dengan cara :

Pemain pmn = (Pemain)paraPemain.get(i);

Misalnya, jika kelas Pemain memiliki metode instansi yang dinamakan jalan() yang dipanggil
ketika seorang pemain menjalankan dadu atau kartu, maka kita bisa menuliskan kode untuk
memberi giliran kepada semua pemain untuk jalan, yaitu dengan

for (int i = 0; i < paraPemain.size(); i++) {


Pemain pmn = (Pemain)paraPemain.get(i);
pmn.jalan();
}
Dua baris di dalam perulangan for tersebut dapat digabungkan dengan satu perintah :

((Pemain)paraPemain.get(i)).jalan();

Perintah ini akan mengambil elemen pada ArrayList mengcasting tipenya, kemudian
memanggil metode jalan() pada pemain yang baru diambil tersebut. Tanda kurung di sekitar
"(Pemain)paraPemain.get(i)" diperlukan karena aturan dalam Java sehingga perintah dalam
kurung akan dijalankan terlebih dahulu sebelum metode jalan() dipanggil.

Vector

Kelas ArrayList diperkenalkan pada Java versi 1.2, sebagai salah satu kumpulan kelas yang
digunakan untuk bekerja dengan sekumpulan koleksi objek. Jika akan bahas lebih lanjut tentang
"kelas koleksi" pada bagian berikutnya. Versi awal Java tidak memiliki ArrayList, akan tetapi
memiliki kelas yang sangat mirip yaitu java.util.Vector. Kita masih bisa melihat Vector
digunakan pada program lama, dan dalam beberapa kelas standar Java, sehingga kita perlu tahu
tentang kelas ini.

Menggunakan Vector mirip dengan menggunakan ArrayList. Perbedaannya adalah nama


metode yang berbeda untuk melakukan tugas yang sama, atau nama metode yang berbeda untuk
melakukan tugas yang sama.

Seperti ArrayList, suatu Vector mirip dengan array Object yang bisa berkembang jika
diperlukan. Konstruktor new Vector() membuat vektor tanpa elemen.

Misalnya vec adalah suatu Vector. Maka :

 vec.size() adalah fungsi untuk mengembalikan jumlah elemen di dalam vektor.


 vec.addElement(obj) akan menambahkan Object obj di akhir vektor. Sama dengan
metode add() pada ArrayList.
 vec.removeElement(obj) menghapus obj dari dalam vektor, kalau ada. Hanya objek
pertama yang ditemui akan dihapus. Sama dengan remove(obj) pada kelas ArrayList
 vec.removeElementAt(N) menghapus elemen ke-N. N harus berada pada rentang 0 hingga
vec.size() - 1. Sama dengan remove(N) pada ArrayList
 vec.setSize(N) akan mengubah ukuran vektor menjadi N. Jika di dalam vektor terdapat
elemen yang jumlahnya lebih banyak dari N, maka elemen lainnya akan dihapus. Jika lebih
sedikit, maka tempat kosong akan diisi dengan null. Kelas ArrayList tidak memiliki metode
seperti ini.

Kelas Vector memiiki banyak metode lagi, akan tetapi ini adalah metode yang sering digunakan.

Array Multi Dimensi


Posted Sab, 03/21/2009 - 01:45 by belajarprogram
Versi ramah cetak

Tipe apapun bisa digunakan sebagai tipe dasar suatu array. Kita bisa membuat array int, array
String, array Object dan seterusnya. Terutama, karena array adalah tipe Java kelas satu, kita
bisa membuat array yang bertipe array.

Misalnya suatu array bertipe int[], juga otomatis memiliki array bertipe int[][], yaitu "array
bertipe array int". Array tersebut disebut array 2 dimensi. Tentunya, dengan tipe int[][], kita
juag bisa membuat arraynya dengan tipe int[][][], yang merupakan array 3 dimensi, dan
seterusnya. Tidak ada batasan berapa dimensi array yang kita buat, akan tetapi bukan sesuatu
yang biasa dilakukan untuk membuat array lebih dari 3 dimensi. Pembahasan kita akan lebih
dikhususkan pada array 2 dimensi. Tipe TipeDasar[][] biasanya dibaca "array 2 dimensi
bertipe TipeDasar" atau "array dari array TipeDasar".

Deklarasi pernyataan "int[][] A;" adalah membuat variabel bernama A dengan tipe int[][].
Variabel ini berisi objek yang bertipe int[][]. Pernyataan pemberian nilai "A = new int[3]
[4];" akan membuat objek array 2 dimensi dan mengisi A ke objek yang baru dibuat tersebut.

Seperti biasa, deklarasi dan pemberian nilai bisa digabung menjadi satu pernyataan, seperti
"int[][] A = new int[3][4];". Objek yang baru dibuat adalah objek yang merupakan array
dari array int. Bagian int[3][4] menyatakan bahwa ada 3 array int di dalam array A, dan di
setiap array int tersebut terdapat 4 int.

Cara seperti itu mungkin sedikit membingungkan, akan tetapi akan lebih mudah apabila kita
bayangkan array tersebut seperti matriks. Istilah "int[3][4]" bisa disebut sebagai matriks
dengan 3 baris dan 4 kolom, seperti pada ilustrasi berikut ini :
 

Untuk banyak hal, kita bisa mengabaikan kenyataan di atas, dan membayangkan bentuk matriks
seperti di atas. Kadang-kadang kita juga harus ingat bahwa setiap baris sebenarnya juga
merupakan suatu array. Array-array ini bisa dirujuk dengan A[0], A[1], dan A[2]. Setiap baris
bertipe int[].

Pernyataan A[1] merujuk pada salah satu baris pada array A. Karena A[1] itu sendiri sebenarnya
adalah array int, kita bisa menambah indeks lain untuk merujuk pada posisi pada baris tersebut.
Misalnya A[1][3] adalah elemen nomor 3 pada baris 1. Seperti biasa, ingat bahwa posisi baris
dan kolom dimulai dari 0. Jadi pada contoh di atas, A[1][3] bernilai 5. Lebih umum lagi, A[i]
[j] adalah posisi pada baris i dan kolom j. Seluruh elemen pada A bisa dinamakan seperti
berikut :

A[0][0] A[0][1] A[0][2] A[0][3]


A[1][0] A[1][1] A[1][2] A[1][3]
A[2][0] A[2][1] A[2][2] A[2][3]

A[i][j] adalah variabel bertipe int. Kita bisa mengisi nilainya atau menggunakannya seperti
variabel bertipe int biasa.
Perlu juga diketahui bahwa A.length akan memberikan jumlah baris pada A. Untuk
mendapatkan jumlah kolom pada A, kita harus mencari jumlah int dalam setiap baris, yaitu yang
disimpan pada A[0]. Jumlah kolom ini bisa didapatkan dengan menggunakan A[0].length, atau
A[1].length atau A[2].length. (Tidak ada aturan baku yang menyatakan bahwa pada setiap
baris suatu array harus memiliki panjang yang sama, dan sebenarnya pada beberapa aplikasi,
juga digunakan array dengan panjang yang berbeda-beda pada setiap barisnya. Akan tetapi
apabila kita membuat array dengan perintah seperti di atas, maka kita akan selalu mendapatkan
array dengan panjang array yang sama.)

Array 3 dimensi juga dibuat dan diolah dengan cara yang sama. Misalnya, array 3 dimensi
bertipe int bisa dibuat dengan pernyataan "int[][][] B = new int [7][5][11];". Kita juga
bisa mengilustrasikannya sebagai kubus 3-dimensi. Masing-masing bloknya bertipe int yang bisa
dipanggil dalam bentuk B[i][j][k]. Array dimensi lain yang lebih tinggi juga mengikuti pola
yang sama, akan tetapi akan sangat sulit untuk membuat visualisasi struktur arraynya.

Kita bisa mengisi array multi dimensi sekaligus pada saat dideklarasikan. Ingat sebelumnya
bagaimana array 1 dimensi biasa dideklarasikan, dan bagaimana isinya diinisialisasikan, yaitu
seperti daftar nilai-nilainya yang dipisahkan dengan koma, dan diletakkan di dalam tanda kurung
kurawal { dan }.

Inisialisasi array bisa juga digunakan untuk array multi dimensi, yang terdiri dari beberapa
inisialisasi array 1 dimensi, masing-masing untuk setiap barisnya. Misalnya, array A pada
gambar di atas dapat dibuat dengan perintah :

int[][] A = { { 1, 0, 12, -1 },
{ 7, -3, 2, 5 },
{ -5, -2, 2, 9 }
};

Jika tidak ada inisialisasi yang diberikan untuk suatu array, maka nilainya akan diisi dengan nilai
awal tergantung pada tipenya : nol untuk bilangan, false untuk boolean dan null untuk objek.

Seperti halnya array 1 dimensi, array 2 dimensi juga sering diolah dengan menggunakan
perulangan for. UNtuk mengolah semua elemen pada array 2 dimensi, kita bisa menggunakan
pernyataan for bertingkat. Jika array A dideklarasikan seperti

int[][] A = new int[3][4];

maka kita bisa mengisi 0 untuk semua elemen pada A dengan menggunakan

for (int baris = 0; baris < 3; baris++) {


for (int kolom = 0; kolom < 4; kolom++) {
A[baris][kolom] = 0;
}
}

Pertama kali perulangan for bagian luar akan memproses dengan baris = 0. Bagian dalamnya
akan mengisi keempat kolom pada baris pertama, yaitu A[0][0] = 0, A[0][1] = 0, A[0][2] =
0, dan A[0][3] = 0. Kemudian perulangan for bagian luar akan mengisi baris kedua, dan
seterusnya.

Dan juga, kita bisa menjumlah semua elemen pada A dengan

int jml = 0;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; i++)
jml = jml + A[i][j];

Untuk mengolah array 3 dimensi, tentunya kita harus menggunakan perulangan for bertingkat 3.

Suatu array 2 dimensi bisa digunakan untuk menyimpan data yang secara alami memang
tersusun sebagai baris dan kolom. Misalnya papan catur terdiri dari 8 baris dan 8 kolom. Jika
suatu kelas dinamakan PapanCatur untuk merepresentasikan papan catur, maka kita bisa
deklarasikan dengan perintah

PapanCatur[][] papan = new PapanCatur[8][8];

Kadang-kadang array 2 dimensi juga digunakan untuk masalah yang tidak terlalu jelas
matriksnya. Misalnya perusahaan yang memiliki 25 toko. Anggap masing-masing toko memiliki
keuntungan yang didapat pada masing-masing toko tersebut setiap bulan pada tahun 2009. Jika
toko-toko tersebut memiliki nomor 0 hingga 24, dan 12 bulan dari Januari 09 hingga Desember
09 dinomori 0 hingga 11, maka data keuntungan dapat disimpan dalam array untung yang
dideklarasikan seperti :

double[][] untung = new double[25][12];

untung[3][2] adalah keuntungan yang dibuat oleh toko nomor 3 di bulan Maret. Atau secara
umum, untung[noToko][noBulan] adalah keuntungan toko noToko pada bulan noBulan.
Dalam contoh ini array 1 dimensi untung[noToko] memiliki arti : Data keuntungan satu toko
selama satu tahun.

Anggap array untung telah diisi dengan data. Data ini bisa diolah lebih lanjut. Misalnya, total
keuntungan seluruh perusahaan -- sepanjang tahun dari seluruh toko -- dapat dihitung dengan
menjumlahkan semua elemen pada array :

double totalUntung; // Total keuntungan perusahaan tahun 2009


 
totalUntung = 0;
for (int toko = 0; toko < 25; toko++) {
for (int bulan = 0; bulan < 12; bulan++)
totalUntung += untung[toko][bulan];
}

Kadang-kadang kita juga perlu menghitung hanya satu baris atau satu kolom saja, bukan
keseluruhan array. Misalnya, kita ingin menghitung keuntungan total perusahaan pada bulan
Desember, yaitu bulan nomor 11, maka kita bisa gunakan perulangan :

double untungDesember = 0.0;


for (noToko = 0; noToko < 25; noToko++)
untungDesember += untung[noToko][11];

Sekarang mari kita buat array 1 dimensi yang berisi total keuntungan seluruh toko setiap bulan :

double[] untungBulanan; // Keuntungan setiap bulan


untungBulanan = new double[12];
 
for (int bulan = 0; bulan < 12; bulan++) {
// hitung total keuntungan semua toko bulan ini
untungBulanan[bulan] = 0.0;
for (int toko = 0; toko < 25; toko++) {
untungBulanan[bulan] += profit[toko][bulan];
}
}

Sebagai contoh terakhir untuk mengolah array keuntungan, misalnya kita ingin tahu toko mana
yang menghasilkan keuntungan terbesar sepanjang tahun. Untuk menghitungnya, kita harus
menjumlahkan keuntungan setiap toko sepanjang tahun. Dalam istilah array, ini berarti kita ingin
mengetahui jumlah setiap baris pada array. Kita perlu mencatat hasil perhitungannya untuk
mencari mana toko dengan keuntungan terbesar.

double untungMaks; // Keuntungan terbesar suatu toko


int tokoTerbaik; // Nomor toko yang memiliki keuntungan terbesar
 
double total = 0.0; // Total keuntungan suatu toko
 
// Pertama-tama hitung keuntungan dari toko nomo 0
 
for (int bulan = 0; bulan < 12; bulan++)
total += untung[0][bulan];
 
tokoTerbaik = 0; // Mulai dengan anggapan toko nomor 0
untungMaks = total; // adalah toko paling menguntungkan
 
// Sekarang kita lihat seluruh toko, dan setiap kali
// kita melihat toko dengan keuntungan lebih besar dari
// untungMaks, kita ganti untungMaks dan tokoTerbaik
// dengan toko tersebut
 
for (toko = 1; toko < 25; toko++) {
 
// Hitung keuntungan toko tersebut sepanjang tahun
 total = 0.0;
for (bulan = 0; bulan < 12; bulan++)
total += untung[toko][bulan];
 
// Bandingkan keuntungan toko ini dengan untungMaks
if (total > untungMaks) {
untungMaks = total; // keuntungan terbesar saat ini
tokoTerbaik = toko; // datang dari toko ini
}
 
} // akhir for
 
// Di sini, untungMaks adalah keuntungan terbesar dari 25 toko
// dan tokoTerbaik adalah toko dengan keuntung tersebut
// (Mungkin juga ada toko yang menghasilkan keuntungan
// yang persis sama.)

Pencarian, Pengurutan dan Rekursi


Posted Min, 03/22/2009 - 16:08 by belajarprogram

Versi ramah cetak

Dua jenis teknik pemrosesan array yang paling umum adalah pencarian dan pengurutan.
Pencarian di sini berarti mencari item di dalam array yang memenuhi kriteria tertentu.
Pengurutan berarti menata ulang semua item di dalam array dalam urutan tertentu (urutan naik
atau turun tergantung konteksnya).

Pencarian dan pengurutan sering didiskusikan, dengan cara yang teoretis, dengan menggunakan
contoh array bilangan. Dalam situasi sebenarnya, tipe data yang lebih kompleks biasanya
digunakan. Misalnya, array bisa jadi suatu mailing list, dan setiap elemen di dalam array adalah
objek yang berisi nama dalam alamat email. Kita mungkin akan mencari alamat email seseorang
apabila namanya diketahui. Ini adalah contoh pencarian, di mana kita ingin mencari objek di
dalam array yang berisi suatu nama.

Mungkin juga kita ingin mengurut array tersebut tergantung pada kriteria tertentu. Misalnya
mengurutkan elemen pada array di mana nama diurutkan secara abjad. Contoh lainnya adalah
mengurutkan elemen pada array berdasarkan kode pos.

Contoh-contoh ini bisa dibuat lebih umum yaitu kita mempunyai array yang berisi objek, dan
kita ingin melakukan pencarian atau pengurutan array berdasarkan nilai salah satu variabel
instansi pada array tersebut. Kita bisa gunakan beberapa istilah yang bersumber pada "database",
yang sesungguhnya adalah koleksi data yang besar dan terorganisir.

Kita akan menyebut masing-masing objek di dalam array sebagai record. Variabel instansi di
dalam objek disebut field dari record tersebut. Dalam contoh mailing list di atas, masing-masing
record berisi nama dan alamat email. Field dari record tersebut mungkin nama depan, nama
akhir, alamat email, dan seterusnya. Dalam konteks pencarian dan pengurutan, salah satu field
diambil sebagai field kunci. Mencarian berarti mencari suatu record di dalam array yang
memiliki nilai tertentu pada field kuncinya. Pengurutan berarti melakukan penataan elemen di
dalam array sehingga field kunci record akan terurut berdasarkan urutan naik atau turun.

Dalam bagian ini, contoh-contoh yang disediakan akan mengikuti tradisi menggunakan array
bilangan. Kita akan contoh beberapa record dan kunci untuk mengingatkan kita pada aplikasi
yang lebih praktis.

Lebih jauh, kita akan melihat tentang rekursi dan aplikasinya. Suatu rubrutin disebut rekursif jika
ia memanggil dirinya sendiri baik secara langung atau tak langsung. Rekursi dapat digunakan
untuk menyelesaikan masalah kompleks dengan menguranginya menjadi masalah yang lebih
sederhana.

 Pencarian
 List Asosiasi
 Pengurutan
 Rekursi
 Pengurutan Cepat

Pencarian
Posted Min, 03/22/2009 - 16:38 by belajarprogram

Versi ramah cetak

Ada algoritma sederhana yang bisa digunakan untuk mencari suatu item pada array : Lihat setiap
array, dan cek apakah isinya sama dengan item yang kita cari. Jika ketemu, maka pencarian
selesai. Jika kita sudah melihat semua item dan tidak ada item yang sama, maka kita yakin
bahwa item yang kita cari tidak ada dalam array.

Subrutin untuk mengimplementasikan algoritma tersebut mudah kita tulis. Misalnya array yang
kita cari bertipe int[]. Berikut ini adalah metode untuk mencari integer tertentu dalam array.
Jika integer ditemukan, maka metode ini akan mengembalikan indeks dalam array di mana item
tersebut ditemukan. Jika integer tersebut tidak ada dalam array, maka metode tersebut akan
mengembalikan nilai -1, yang artinya integer tersebut tidak ditemukan.

static int cari(int[] A, int N) {


// Mencari integer N di dalam array A
// Kondisi akhir : jika N tidak ada dalam array
// maka kembalikan -1. Jika N ada dalam array
// kembalikan i, yaitu indeks di mana A[i] == N
 
for (int indeks = 0; indeks < A.length; indeks++) {
if ( A[indeks] == N )
return indeks; // N ditemukan pada indeks ini.
}
 
// Jika kita sampai di sini, berarti N belum ditemukan
// Kembalikan -1.
 
return -1;
}

Metode seperti ini dimana pencarian dilakukan dengan menguji setiap item disebut pencarian
linier (linear search). Jika kita tidak mengetahui apa-apa tentang isi dan urutan item pada array,
maka tidak ada lagi algoritma alternatif yang lebih baik dari ini. Akan tetapi jika kita tahu bahwa
elemen di dalam array diurut dalam urutan menaik atau urutan menurun, maka kita bisa
menggunakan algoritma lain yang lebih cepat. Tentu saja, waktu yang dibutuhkan untuk
mengurutkan array tidak sebentar, akan tetapi jika array ini akan dicari berulang kali, maka
waktu pengurutan array akan terbayarkan dengan cepat.

Pencarian biner (binary search) adalah metode untuk mencari suatu item dalam array yang sudah
diurutkan. Meskipun implementasinya tidak mudah, akan tetapi ide dasarnya sangat mudah : Jika
kita mencari suatu item dalam suatu array yang terurut, maka kita bisa menghapus setengah dari
keseluruhan elemen hanya dengan melihat satu nilai. Misalnya kita ingin mencari bilangan 42
dalam array yang sudah diurutkan yang terdiri dari 1000 bilangan bulat. Anggap bahwa array
tersebut diurutkan dalam urutan menaik (dari kecil ke besar). Kemudian kita cek item ke-500
dalam array, dan ternyata isinya adalah 93. Karena 42 kurang dari 93, dan karena elemen di
dalam array tersebut dalam urutan menaik, kita bisa simpulkan bahwa 42 tidak mungkin ada di
item ke-501 ke atas. Maka elemen tersebut pasti ada di lokasi tertentu sebelum posisi ke-500.

Cara berikutnya adalah melihat di lokasi 250. Jika misanya lokasi tersebut berisi 21, maka kita
bisa menghilangkan lokasi 0 hingga 250 dan memfokuskan pencarian antara 251 dan 499. Yang
berikutnya adalah kira-kira di lokasi ke-125 setelah itu, yang berikutnya adalah sekitar 62 lokasi
setelah itu. Setelah kira-kira 10 langkah pengujian, hanya ada satu lokasi yang akan kita cek.

Cara ini akan jauh lebih mudah dan lebih cepat daripada harus mencari semua elemen di dalam
array. Jika ada satu juta elemen di dalam array, maka kita hanya perlu mencari 20 kali. (Secara
matematika, jumlah langkah yang diperlukan adalah logaritmik dari jumlah item di dalam array).

Untuk membuat subrutin pencarian biner pada Java yang mencari item N pada array A, kita
hanya perlu mencatat rentang lokasi di mana kira-kira N bisa ditemukan. Pada setiap langkah,
kita bisa mengurangi kemungkinan dan mengurangi rentang pencarian. Operasi dasarnya adalah
mencari item di tengah-tengah rentang tersebut. Jika item ini lebih besar dari N, maka rentang
bagian atasnya bisa dibuang. Jika kurang dari N, maka rentang bawahnya bisa dibuang.

Jika nilai di tengah-tengah tersebut persisi sama denan N, maka pencarian selesai. Jika ukurang
pencarian berkurang menjadi nol, maka nilai N tidak ada dalam array. Berikut ini adalah subrutin
yang mengembalikan lokasi di mana N berada di dalam array terurut A. Jika N tidak ditemukan,
maka nilai -1 akan dikembalikan.

static int pencarianBiner(int[] A, int N) {


// Mencari bilangan N pada array A
// Kondisi awal : A harus diurut menaik (dari kecil ke besar)
// Kondisi akhir : Jika N ada dalam array, maka kembalikan
// nilai i, di mana A[i] == N. Jika tidak kembalikan -1
 
int lokasiTerkecil = 0;
int lokasiTerbesar = A.length - 1;
 
while (lokasiTerbesar >= lokasiTerkecil) {
int tengah = (lokasiTerkecil + lokasiTerbesar) / 2;
if (A[tengah] == N) {
// N ditemukan di sini
return tengah;
}
else if (A[tengah] > N) {
// buang lokasi >= tengah
lokasiTerbesar = tengah - 1;
}
else {
// buang lokasi <= tengah
lokasiTerkecil = tengah + 1;
}
}
 
// Sampai titik ini, lokasiTerbesar < lokasiTerkecil
// yang berarti nilai N tidak ada dalam array.
// Kembalikan -1, yang artinya item tidak ditemukan
 
return -1;
}

List Asosiasi
Posted Min, 03/22/2009 - 17:08 by belajarprogram

Versi ramah cetak

Salah satu aplikasi pencarian yang banyak digunakan adalah yang menggunakan list asosiasi
(association list). Contoh umum dari suatu list asosiasi adalah kamus. Kamus menghubungan
kata dengan definisi. Dengan kata tertentu, kita bisa menggunakan kamus untuk mencari
definisinya. Kita bisa membayangkan kamus sebagai daftar suatu pasangan (pair) dalam bentuk
(k,d) di mana k adalah kata dan d adalah definisi. Secara umum, kita menganggap bahwa tidak
ada dua pasangan dalam list yang memiliki kunci yang sama. Operasi dasar dari list asosiasi
adalah sebagai berikut : Dengan kunci k, cari nilai n yang berhubungan dengan k, jika ada.

List asosiasi digunakan secara luas dalam ilmu komputer. Misalnya, suatu kompiler harus
melacak di mana lokasi suatu variabel pada memori. Kompiler dapat menggunakan list asosiasi
di mana kuncinya adalah nama variabel dan nilainya adalah alamat variabel tersebut di memori.
Contoh lainnya adalah mailing list, yang menghubungkan nama dan alamat email dalam daftar
tersebut. Contoh lain yang mungkin berhubungan adalah direktori telepon yang menghubungkan
nama dan nomor telepon. Item di dalam list tersebut mungkin berupa objek dari kelas :

class EntriTelepon {
String nama;
String noTelp;
}
Data dalam direktori telepon adalah array yang bertipe EntriTelepon[] dan variabel integer
untuk menyimpan berapa banyak item yang disimpan dalam direktori tersebut. (Contoh ini
adalah contoh dari "array setengah penuh" yang dibahas pada bagian sebelumnya. Mungkin lebih
baik jika kita menggunakan array dinamis atau ArrayList untuk menyimpan daftar telepon.)
Direktori telepon mungkin berupa objek di dalam kelas

class DirektoriTelepon {
 
EntriTelepon[] info = new EntriTelepon[100]; // Tempat untuk 100 entri
int jmlEntri = 0; // Jumlah entri aktual di dalam array
 
void tambahEntri(String nama, String noTelp) {
// Tambah entri baru di akhir array
info[jmlEntri] = new EntriTelepon();
info[jmlEntri].nama = nama;
info[jmlEntri].noTelp = noTelp;
jmlEntri++;
}
 
String getNoTelp(String nama) {
// Ambil nomor telepon dari nama ini atau
// kembalikan null jika tidak ada nama ini
// di dalam array.
for (int idks = 0; idks < jmlEntri; idks++) {
if (nama.equals( info[idks].nama )) // Nama ketemu!
return info[idks].noTelp;
}
return null; // Nama tidak ketemu.
}
}

Lihat bahwa metode getNoTelphanya mengambil lokasi dalam array yang telah diisi dengan
EntriTelepon. Dan juga tidak seperti rutin pencarian yang disebutkan sebelumnya, rutin ini
tidak mengembalikan lokasi item dalam array. Akan tetapi ia mengembalikan nilai lain yang
berhubungan dengan kata kuncinya, yaitu nama. Hal ini sering dilakukan untuk list asosiasi.

Kelas ini bisa diperbaliki lebih lanjut. Satu hal, mungkin lebih baik jika kita melakukan
pencarian dengan menggunakan pencarian biner dan bukan pencarian linier sederhana dalam
metode getNoTelp. Akan tetapi, kita hanya bisa lakukan ini apabila EntriTelepon diurut
terlebih dahulu berdasarkan nama. Dan sebenarnya, tidak terlalu suit untuk membuat entri
tersebut dalam urutan, yang akan kita lihat berikutnya.

Pengurutan
Posted Min, 03/22/2009 - 17:58 by belajarprogram

Versi ramah cetak

Pengurutan Penyisipan (Insertion Sort)


Ada banyak algoritma yang tersedia untuk melakukan pengurutan. Salah satu yang paling mudah
dimengerti adalah pengurutan penyisipan (insertion sort). Metode ini juga bisa digunakan untuk
menjaga agar list selalu dalam urutan tertentu (naik atau turun) sewaktu kita menambah item
baru ke dalam list. Mari kita lihat contoh pertama :

Misalnya kita memiliki list yang sudah diurutkan, dan kita ingin menambahkan sebuat item ke
dalamnya. Jika kita ingin memastikan bahwa suatu list tetap dalam kondisi terurut, maka item
tersebut harus diletakkan di tempat yang tepat, yaitu semua item yang lebih kecil harus
ditempatkan sebelum item tersebut, dan semua item yang lebih besar ditempatkan setelahnya.
Artinya kita harus menggeser semua item yang lebih besar ke satu sisi untuk memberi ruangan
pada item baru yang akan ditambahkan.

static void sisip(int[] A, int jmlItem, int itemBaru) {


// Kondisi awal : jmlItem adalah jumlah item pada A.
// Item ini harus berada dalam kondisi terurut naik di mana
// (A[0] <= A[1] <= ... <= A[jmlItem-1]).
// Ukuran array harus lebih besar dari jmlItem.
// Kondisi akhir : jumlah item akan ditambah dengan satu,
// itemBaru telah ditambah pada array, dan semua item
// masih dalam kondisi terurut.
// Catatan: untuk menyelesaikan proses penyisipan item
// dalam array, variabel yang mencatat jumlah item dalam
// array harus ditambah satu setelah memanggil subrutin ini.
 
int lok = jmlItem - 1; // Mulai dari akhir array
 
/* Pindahkan item yang lebih besar dari itemBaru satu posisi;
Stop jika item yang lebih kecil ditemukan atau sampai ke
awal array (lok == 0) */
 
while (lok >= 0 && A[lok] > itemBaru) {
A[lok + 1] = A[lok]; // Pindahkan lokasi item dari posisi lok ke
lok+1
lok = lok - 1; // Pindah ke lokasi sebelumnya
}
 
A[lok + 1] = itemBaru; // Letakkan itemBaru di tempat kosong
}

Metode di atas bisa dikembangkan menjadi metode pengurutan jika kita mengeluarkan semua
item dari array yang belum diurutkan, kemudian memasukkannya kembali satu demi satu, sambil
menjaga agar array tetap terurut selama kita menambah item ke array baru. Setiap penyisipan
bisa dilakukan dengan rutin sisip() di atas. Dalam algoritma sesungguhnya, kita tidak benar-
benar mengambil semua item dari dalam array, kita hanya cukup mengingat bagian mana yang
sudah diurutkan.

static void urutPenyisipan(int[] A) {


// Mengurutkan array A dalam urutan menaik (dari kecil ke besar)
 
int itemTerurut; // Jumlah item yang sudah diurut
 
for (itemTerurut = 1; itemTerurut < A.length; itemTerurut++) {
// Anggap item A[0], A[1], ... A[itemTerurut-1]
// telah diurutkan. Sisipkan A[itemTerurut]
// ke dalam bagian yang sudah diurutkan
 
int temp = A[itemTerurut]; // Item yang akan disisipkan
int lok = itemTerurut - 1; // Mulai dari akhir list
 
while (lok >= 0 && A[lok] > temp) {
A[lok + 1] = A[lok]; // Pindahkan item dari lok ke lok+1
lok = lok - 1; // Pindah ke lokasi sebelumnya
}
 
A[lok + 1] = temp; // Letakkan temp di tempat kosong
}
}

Ilustrasi berikut adalah ilustrasi di tengah-tengah pengurutan, yang menunjukkan apa yang
terjadi di tengah-tengah salah satu eksekusi perulangan for dari kode di atas, ketika
itemTerurut = 5.

Pengurutan Pilihan (Selection Sort)


Metode pengurutan lainnya yang biasa digunakan adalah pengurutan pilihan (selection sort).
Metode ini mencari item terbesar di dalam list, kemudian memindahkannya ke akhir array -- atau
dengan kata lain di tempatnya, karena item terbesar akan berada di akhir array. Setelah item
terbesar ditempatkan di tempat yang benar, kita gunakan cara yang sama, yaitu cari item terbesar
berikutnya, kemudian letakkan di tempat kedua dari akhir, dan seterusnya. Metode ini dapat
ditulis sebagai :

static void urutPilihan(int[] A) {


 
// Urut A dengan urutan menaik dengan Pengurutan Pilihan
 
for (int tmptTerakhir = A.length-1; tmptTerakhir > 0; tmptTerakhir--) {
// Cari nilai terbesar di antara A[0], A[1], ..., A[tmptTerakhir],
// dan pindahkan ke tmptTerakhir dengan cara menukarny
// dengan nilai yang ada di tmptTerakhir
 
int lokMaks = 0; // Lokasi nilai terbesar saat ini
 
for (int j = 1; j <= tmptTerakhir; j++) {
if (A[j] > A[lokMaks]) {
// Karena A[j] lebih besar dari nilai maksimum yang pernah
// kita lihat, j adalah lokasi baru tempat di mana nilai
// maksimum tersebut berada
lokMaks = j;
}
}
 
int temp = A[lokMaks]; // Tukar nilainya dengan A[tmptTerakhir].
A[lokMaks] = A[tmptTerakhir];
A[tmptTerakhir] = temp;
} // akhir perulangan
}

Pengurutan penyisipan dan pengurutan pilihan cocok digunakan untuk mengurut array dengan
ukuran kecil (hingga beberapa ratus elemen). Ada beberapa algoritma pengurutan lain yang jauh
lebih cepat dari pengurutan penyisipan dan pengurutan pilihan untuk array yang sangat besar.
Kita akan diskusikan kemudian.

Mengacak Nilai

Kita akan sudahi bagian ini dengan masalah yang sedikit berkaitan, lebih jarang muncul, akan
tetapi menarik, yaitu bagaimana caranya meletakkan elemen array dengan urutan acak. Misalnya
adalah untuk mengocok kartu. Algoritma baik untuk mengocok mirip dengan pengurutan pilihan,
akan tetapi kita tidak memindahkan item terbesar ke array paling belakang. Item dipilih secara
acak dan dipindahkan ke akhir array. Berikut ini adalah subrutin untuk mengocok array bertipe
int.

static void kocok(int[] A) {


// Kondisi akhir : Item pada A diatur dalam urutan yang acak
 
for (int tmptTerakhir = A.length-1; tmptTerakhir > 0; tmptTerakhir--) {
// Pilih lokasi acak di antara 0,1,...,tmptTerakhir.
int lokAcak = (int)(Math.random()*(tmptTerakhir+1));
 
// Tukar item pada lokAcak dengan A[tmptTerakhir]
int temp = A[lokAcak];
A[lokAcak] = A[tmptTerakhir];
A[tmptTerakhir] = temp;
}
}

Rekursi
Posted Rab, 03/25/2009 - 22:35 by belajarprogram

Versi ramah cetak

Definisi rekursi adalah definisi yang menggunakan konsep atau sebagian dari definisi tersebut
menjadi definisi yang komplit.

Misalnya : "keturunan" bisa berarti anak atau keturunan dari anak. "Kalimat" bisa berarti dua
kalimat yang digabung dengan kata hubung "dan". "Direktori" adalah bagian pada hard disk
yang berisi file dan direktori. Dalam matematika, "himpunan" adalah koleksi elemen, di mana
elemen tersebut bisa berupa himpunan. "Pernyataan" pada Java misalnya pernyataan while yang
didalamnya terdapat kata while, kondisi bernilai boolean dan pernyataan lainnya.

Definisi rekursi bisa menjelaskan situasi yang sangat kompleks dalam beberapa kata. Definisi
istilah "keturunan" tanpa menggunakan rekursi bisa jadi "anak, cucu, cicit, dan seterusnya".
Akan tetapi mengatakan "dan seterusnya" bukan arti "keturunan" secara lengkap.

Kita juga akan kesulitan jika kita mencoba mendefinisikan "direktori" sebagai "file yang berisi
daftar file, dimana beberapa file bisa berisi daftar file, di mana beberapa file tersebut bisa berisi
daftar file, dan seterusnya". Mencoba untuk menjelaskan pernyataan Java tanpa menggunakan
rekursi dalam definisinya akan sulit dilakukan.

Rekursi bisa digunakan dalam teknik pemrograman. Subrutin rekursif adalah subrutin yang
memanggil dirinya sendiri, baik langsung maupun tak langsung. Subrutin tersebut memanggil
dirinya sendiri secara tidak langsung yaitu jika ia memanggil subrutin lain yang akhirnya
memanggil subrutin pertama (baik langsung maupun tak langsung).

Suatu subrutin rekursi bisa menyelesaikan tugas kompleks dalam beberapa baris perintah. Kita
akan lihat beberapa contohnya pada bagian ini.

Mari kita mulai dengan contoh yang sudah kita lihat sebelumnya: algorithma pencarian biner
pada bagian sebelumnya. Pencarian biner digunakan untuk mencari suatu nilai dalam list terurut
(atau jika item nilai tersebut tidak ada di dalam list tersebut, akan memberitahu hasilnya
misalnya dengan mengembalikan -1).
Caranya adalah dengan mengecek elemen di tengah list tersebut. Jika elemen tersebut sama
dengan nilai yang dicari, maka pencarian tersebut selesai. Jika nilai yang dicari lebih kecil
daripada nilai elemen di tengah list tersebut, maka kita harus mencari di separuh awal dari list
tersebut. Jika lebih besar, kita harus mencari di separuh akhir list tersebut. Kemudian, pada
separuh list yang kita pilih tersebut, kita akan mengecek kembali elemen tengahnya. Kita akan
melihat kembali apakah nilainya sama dengan nilai yang kita cari, lebih besar atau lebih kecil,
yang dari sini kita tahu paruh mana yang akan kita cari berikutnya. Dan begitu seterusnya,
hingga besar list yang akan dicari berkurang menjadi 0.

Ini adalah definisi rekursif, dan kita bisa membuat subrutin rekursif untuk
mengimplementasikannya.

Sebelumnya, ada dua pertimbahangan yang harus kita masukkan ke dalam perhitungan kita, yang
merupakan fakta tentang subrutin rekursif. Pertama, algoritma pencarian biner dimulai dengan
mengecek "elemen tengah suatu list". Apa yang terjadi jika list tersebut kosong? Jika tidak ada
elemen di dalam list, maka kita tidak mungkin melihat elemen di tengahnya. Atau dengan kata
lain, ini disebut "kondisi awal" untuk mengecek elemen di tengah list, yaitu memiliki list yang
tidak kosong.

Apa yang terjadi kita ternyata harus mencari nilai di list kosong? Jawabannya mudah : Kita bisa
mengatakan bahwa nilai yang kita cari tidak ada di dalam list. List kosong adalah kasus dasar
untuk algoritma pencari biner. Kasus dasar untuk algoritma rekursif adalah kasus yang akan
ditangani secara langsung, bukan dilakukan secara rekursif. Algoritma pencarian biner memiliki
kasus dasar lain, yaitu jika kita menemukan nilai yang kita cari di tengah suatu list, maka
program tersebut selesai. Kita tidak perlu melakukan rekursi lebih lanjut.

Pertimbangan kedua adalah parameter subrutin tersebut. Dalam subrutin non-rekursif dari
pencarian biner yang dibahas sebelumnya, parameternya adalah suatu array. Akan tetapi dalam
pendekatan rekursif, kita harus bisa menerapkan subrutin secara rekursif hanya sebagian dari list
aslinya. Pada subrutin aslinya yang non-rekursif, kita melakukan pencarian di seluruh array,
sedangkan subrutin rekursif harus bisa mencari di sebagian array. Parameter subrutin tersebut
harus bisa memberi tahu di bagian mana array akan dicari.

Berikut ini adalah algoritma pencarian biner rekursif yang mencari suatu nilai dalam bagian dari
array integer:

static int cariBiner(int[] A, int idksRendah, int idksTinggi, int nilai) {


// Cari "nilai" pada array "A" dari posisi "idksRendah" ke "idksTinggi",
// Asumsinya adalah array diurut dalam urutan menaik
// Jika nilai ditemukan kembalikan indeks pada array
// dimana nilai tersebut berada. Jika tidak kembalikan -1
 
if (idksRendah > idksTinggi) {
// Artinya list kosong karena seharusnya idksRendah lebih rendah
// dari idksTinggi. "Nilai" tidak mungkin ada di list kosong.
return -1;
}
else {
// Cek elemen di tengah list. Jika nilai sama dengan isi elemen
// tengah, maka kembalikan posisi tersebut.
// Jika tidak, cari secara rekursif di awal atau akhir
// dari setengah list
int idksTengah = (idksRendah + idksTinggi) / 2;
if (nilai == A[idksTengah])
return idksTengah;
else if (nilai < A[idksTengah])
return cariBiner(A, idksRendah, idksTengah - 1, nilai);
else // nilai > A[idksTengah]
return cariBiner(A, idksTengah + 1, idksTinggi, nilai);
}
} // akhir cariBiner()

Dalam rutin di atas, parameter idksRendah dan idksTinggi menyatakan bagian array yang akan
dicari. Untuk mencari keseluruhan array, kita hanya perlu memanggil cariBiner(A, 0,
A.length - 1, nilai). Dalam kedua kasus dasar -- yaitu tidak ada elemen di dalam rentang
indeks yang diberikan dan ketika tidak ada nilai yang ditemukan di tengah-tengah rentang
tersebut -- subrutin dapat memberikan jawabannya secara langsung, tanpa rekursi. Pada kasus
lain, subrutin akan memanggil dirinya sendiri secara rekursif untuk menghitung dan
mengembalikan hasilnya.

Banyak orang yang merasa sulit untuk memahami bagaimana rekursi bekerja. Kuncinya ada 2
hal yang harus dipenuhi agar rekursi bisa bekerja dengan benar :

 Harus ada minimum satu kasus dasar, yang bisa ditangani tanpa menggunakan rekursi.
 Jika subrutin dilakukan secara rekursif, ia harus dipanggil dalam lingkup yang lebih kecil, makin
kecil hingga mendekati kasus dasarnya.

Satu kesalahan umum yang terjadi ketika menulis subrutin rekursif adalah jika kita melanggar
salah satu dari kedua aturan di atas. Jika aturan ini dilanggar, hasilnya bisa jadi rekursi tak
hingga, di mana subrutin tersebut akan memanggil dirinya terus menerus tanpa henti, karena
tidak pernah mencapai kasus dasarnya.

Rekrusi tak hingga mirip dengan perulangan yang tak pernah berhenti. Akan tetapi karena setiap
panggilan rekursif menggunakan memori komputer, maka program yang tersangkut di dalam
rekursi tak hingga, pada akhirnya akan kehabisan memori.

Pencarian biner dapat diimplementasikan dengan perulangan while selain dengan menggunakan
rekursi. Sekarang mari kita lihat suatu masalah yang lebih mudah diselesaikan dengan rekursi
tapi sulit dilakukan dengan metode lain. Berikut ini adalah contoh yang biasa digunakan, yand
dinamakan "Menara Hanoi".

Persoalannya dapat dituliskan sebagai berikut : sebuah tumpukan piringan dengan ukuran
berbeda ditumpuk dari urutan terbesar di bagian paling bawah hingga terkecil di bagian paling
atas. Seluruh piringan harus dipindahkan dari satu tiang ke tiang lain, dengan dua aturan
 dalam setiap langkah hanya boleh memindahkan satu piringan, dan
 piringan yang lebih besar tidak boleh diletakkan di atas piringan yang lebih kecil.

Ada tiang lain yang berfungsi sebagai tiang cadangan, dan bisa digunakan sebagai tempat
sementara. Gambar berikut (atas) mengilustrasikan tumpukan 10 piringan. Gambar lainnya
(bawah) adalah ilustrasi setelah beberapa langkah telah dijalankan.

Kita akan memindahkan 10 piringan dari tiang 0 ke tiang 1, dan tiang 2 bisa dijadikan cadangan.
Bisakah kita mengurangi persoalan ini menjadi persoalan yang sama dengan skala yang lebih
kecil? Mungkin kita harus sedikit mengeneralisir persoalannya sehingga kita bisa melihat lebih
jelas.

Jika ada N piringan pada tiang 0, kita tahu bahwa pada akhirnya kita haris memindahkan
piringan paling bawah dari tiang 0 ke tiang 1. Akan tetapi sebelum itu, menurut aturan di atas,
piringan 0 hingga N-1 harus dipindahkan terlebih dahulu ke tiang 2. Setelah kita pindahkan
piringan ke-N ke tiang 1, maka kita harus memindahkan kembali N-1 piringan dari tiang 2 ke
tiang 1 untuk menyelesaikan masalahnya. Lihat bahwa memindahkan N-1 piringan adalah
persoalan yang sama seperti memindahkan N piringan, akan tetapi sekarang persoalannya
menjadi lebih kecil.

Ini bisa dilakukan dengan mudah dengan rekursi.

Suatu persoalan harus digeneralisir terlebih dahulu, di sini kita lihat bahwa persoalan yang lebih
kecil adalah memindahkan piringan dari tiang 0 ke tiang 2 dan kemudian dari tiang 2 ke tiang 1,
bukan dari tiang 0 ke tiang 1. Untuk subrutin rekursiif yang akan kita buat, kita harus
menyatakan tiang asal, tiang tujuan, dan tiang cadangannya. Kasus dasarnya adalah jika hanya
ada satu piringan yang akan dipindahkan, yang mana jawabannya mudah : pindahkan satu
piringan itu dalam satu langkah.
Berikut ini adalah contoh subrutin untuk menyelesaikan masalah ini :

void MenaraHanoi(int piringan, int asal, int tujuan, int cadangan) {


// Memecahkan persoalan untuk memindahkan sejumlah "piringan"
// dari tiang "asal" ke tiang "tujuan". Tiang "cadangan" bisa
// digunakan sebagai tempat sementara
if (piringan == 1) {
// Hanya ada satu piringan, pindahkan langsung
System.out.println("Pindahkan piringan dari tiang "
+ asal + " ke tiang " + tujuan);
}
else {
// Pindahkan semua piringan minus 1 ke tiang cadangan,
// kemudian pindahkan piringan paling bawah ke tiang tujuan,
// kemudian pindahkan sisanya dari tiang cadangan ke
// tiang tujuan.
MenaraHanoi(piringan-1, asal, cadangan, tujuan);
System.out.println("Pindahkan piringan dari tiang "
+ asal + " ke tiang " + tujuan);
MenaraHanoi(piringan-1, cadangan, tujuan, asal);
}
}

Subrutin ini mengekspresikan solusi persoalan secara alami. Rekursi bisa bekerja dengan benar
karena setiap panggil rekursif selalu akan dipanggil dengan jumlah piringan yang semakin
sedikit. Dan ketika sampai pada kasus dasarnya, yaitu hanya ada satu piringan, persoalannya bisa
diselesaikan langsung dengan memindahkan satu piringan tersebut ke tiang tujuannya.

Untuk memecahkan persoalan ini pada "level paling atas", yaitu memindahkan N piringan dari
tiang 0 ke tiang 1, subrutin ini bisa dipanggil dengan perintah MenaraHanoi(N,0,1,2).

Ceritanya, dahulu kala ada kisah yang merupakan nama dari persoalan ini. Menurut cerita ini,
pada saat bumi pertama kali dicipkatan, sekumpulan biksu pada suatu menara di dekat Hanoi
diberi tumpukan 64 piringan dan diberi tugas untuk memindahkan satu piringan setiap hari
dengan aturan yang sama seperti di atas. Pada hari ketika tugas ini selesai, alam semesta akan
kiamat. Tapi tenang saja, karena jumlah langkah yang diperlukan untuk menyelesaikan tugas ini
untuk N piringan adalah 2N - 1, dan 264 - 1 hari sama dengan lebih dari 50 trilyun tahun.

Pengurutan Cepat
Posted Min, 03/29/2009 - 19:49 by belajarprogram

Versi ramah cetak

Aplikasi rekursi yang cukup populer adalah Pengurutan Cepat (Quicksort) yang digunakan untuk
mengurutkan array. Di bagian sebelumnya kita telah melihat bagaimana mengurutkan array
dengan menggunakan pengurutan pilihan dan pengurutan penyisipan yang relatif lebih mudah,
akan tetapi akan berjalan lebih lambat untuk array yang besar. Algoritma pengurutan yang lebih
cepat sudah tersedia. Salah satunya adalah pengurutan cepat (quick sort), yaitu algoritma rekursif
yang ternyata paling cepat hampir pada segala kondisi.
Algoritma pengurutan cepat dibuat berdasarkan ide yang sederhana namun cerdas : Dari
beberapa item, pilih satu item. Item ini kita sebut pivot. Pindahkan semua item yang lebih kecil
dari pivot ke awal array, dan pindahkan item yang lebih besar ke akhir array. Kemudian letakkan
pivot di tengah-tengah kedua grup tersebut. Atau dengan kata lain, posisi pivot adalah posisi
terakhir dan tidak perlu dipindahkan lagi.

LangkahUrutCepat bukan algoritma rekursif. Kecepatan pengurutan cepat tergantung dari


kecepatan LangkahUrutCepat. Karena ini bukan diskusi utama kita, kita akan tuliskan algoritma
LangkahUrutCepat tanpa diskusi lebih lanjut.

static int LangkahUrutCepat(int[] A, int rendah, int tinggi) {


// Jalankan LangkahUrutCepat pada array dengan indeks
// antara rendah dan tinggi pada array A. Nilai yang dikembalikan
// adalah posisi akhir pivot dalam array
 
// Kita ambil sembarang pivot, yaitu pada indeks pertama
int pivot = A[rendah];
 
// Nilai antara rendah dan tinggi adalah nilai yang belum pernah
// kita uji. Kurangi tinggi dan naikkan rendah hingga keduanya
// bernilai sama, pindahkan nilai yang lebih besar dari pivot
// sehingga nilai tersebut berada di atas tinggi dan pindahkan
// nilai yang lebih kecil dari pivot sehingga nilainya berada
// di bawah rendah. Ketika kita mulai, A[rendah] adalah tempat
// kosong, karena ini adalah posisi awal nilai pivot
 
while (tinggi > rendah) {
 
while (tinggi > rendah && A[tinggi] > pivot) {
// Pindahkan tinggi hingga melewati nilai yang lebih rendah
// dari pivot. Nilai ini tidak perlu dipindahkan
hi--;
}
 
if (tinggi == rendah)
break;
 
// Nilai pada A[tinggi] kurang dari pivot. Pindahkan ke tempat
// kosong pada A[rendah], sehingga tempat di A[tinggi]
// menjadi kosong
 
A[rendah] = A[tinggi];
rendah++;
 
while (tinggi > rendah && A[rendah] < pivot) {
// Pindahkan rendah hingga melewati nilai yang lebih tinggai
// pivot. Nilai ini tidak perlu dipindahkan
rendah++;
}
 
if (tinggi == rendah)
break;
 
// Nilai A[rendah] lebih tinggi dari pivot. Pindahkan ke tempat
// kosong pada A[tinggi], sehingga tempat di A[rendah]
// menjadi kosong.
 
A[tinggi] = A[rendah];
tinggi--;
 
} // akhir while
 
// Di sini, rendah sama dengan tinggi, dan ada tempat kosong
// di sini. Posisi ini berada di antara nilai yang lebih tinggi dan
// nilai yang lebih rendah dari pivot. Letakkan pivot di sini
// dan kembalikan posisinya.
 
A[rendah] = pivot;
return rendah;
 
} // akhir LangkahUrutCepat

Degan subrutin ini, maka pengurutan cepat mudah dilakukan. Algoritma untuk mengurutkan
deretan nilai yaitu dengan menjalankan LangkahUrutCepat pada nilai-nilai tersebut, kemudian
menjalankan pengurutan cepat secara rekursif terhadap item yang ada di sebelah kiri pivot dan
item yang ada di sebelah kanan pivot. Tentunya kita juga membutuhkan kasus dasar. Yaitu jika
list hanya memiliki satu item atau kosong, maka list tersebut telah diurutkan.

static void urutcepat(int[] A, int rendah, int tinggi) {


// Jalankan pengurutan cepat untuk mengurutkan array
// antara posisi rendah dan posisi tinggi dalam urutan naik
if (tinggi <= rendah) {
// List memiliki panjang nol atau 1. Tidak ada yang perlu
// dilakukan, jadi kita keluar dari subrutin
return;
}
else {
// Jalankan LangkahUrutCepat dan dapatkan posisi pivot
// Kemudian jalankan urutcepat untuk mengurut item sebelum
// pivot dan item setelah pivot
int posisiPivot = LangkahUrutCepat(A, rendah, tinggi);
urutcepat(A, rendah, pivotPosition - 1);
urutcepat(A, pivotPosition + 1, tinggi);
}
}

Seperti biasa, kita telah melihat masalah dengan mengeneralisirnya. Masalah awalnya adalah
untuk mengurutkan array, akan tetapi algoritma rekursif dibuat untuk mengurutkan sebagian
array. Untuk mengurut keseluruhan array A, kita bisa menggunakan urutcepat() yaitu dengan
perintah urutcepat(A, 0, A.length -1).

Struktur Data Berantai


Posted Kam, 03/26/2009 - 17:17 by belajarprogram

Versi ramah cetak

Pada bagian ini kita akan melihat teknik pemrograman tingkat lanjut lainnya, yaitu struktur data
berantai (linked data structure), dan applikasinya.

Suatu referensi ke suatu objek bisa disimpan sebagai variabel instansi di objek lain, sehingga
"terkait" satu sama lain. Struktur data kompleks bisa dibuat dengan mengaitkan satu objek
dengan objek lainnya menjadi struktur data berantai.

Yang menarik adalah apabila objek ini dikaitkan dengan objek lain yang memiliki kelas yang
sama. Di sini kelas tersebut digunakan dalam definisi kelas yang sama. Beberapa jenis struktur
data bisa dibuat dengan menggunakan model semacam ini.

 Mengaitkan Objek
 Tumpukan
 Antrian
 Pohon Biner
 Pohon Pengurutan Biner

Mengaitkan Objek
Posted Kam, 03/26/2009 - 18:47 by belajarprogram

Versi ramah cetak

Hampir semua objek memiliki variabel instansi. Jika variabel instansi bertipe suatu kelas atau
interface, maka variabel instansi itu bisa menyimpan referensi ke objek lain. Referensi disebut
juga pointer, karena referensi menunjuk pada suatu objek. (Variabel yang berisi referensi ke
suatu objek juga bisa berisi null alias tidak menunjuk ke mana-mana). Jika satu objek memiliki
referensi ke objek lain, objek itu disebut terkait satu sama lain. Struktur data kompleks bisa
dibuat dengan mengaitkan objek satu sama lain.

Jika suatu objek memiliki pointer ke objek lain dengan tipe yang sama, maka definisi kelasnya
bersifat rekursif. Rekursi jenis ini banyak terjadi, misalnya kelas Pegawai yang melambangkan
pegawai di suatu perusahaan. Semua orang kecuali bos tertinggi memiliki atasan, di mana
atasannya ini adalah juga pegawai perusahaan tersebut. Tentunya kelas Pegawai memiliki
variabel instansi dengan tipe Pegawai yang menunjuk pada atasan pegawai itu, sehingga :

class Pegawai {
// Objek untuk menyimpan data tentang seorang pegawai
String nama; // Nama pegawai
 
Pegawai atasan; // Atasan pegawai ini
.
. // (Metode dan variabel instansi lain.)
.
} // akhir kelas Pegawai

Jika pgw adalah variabel bertipe Pegawai, maka pgw.atasan adalah variabel lain yang juga
bertipe Pegawai. Jika pgw menunjuk pada bos tertinggi, maka pgw.atasan berisi null yang
artinya ia tidak memiliki atasan. Kita bisa mencetak nama atasan seorang pegawai, misalnya
dengan pernyataan Java berikut :

if ( pgw.atasan == null) {
System.out.println( pgw.nama " adalah bos tertinggi." );
}
else {
System.out.print( "Atasan dari " + pgw.nama + " ialah " );
System.out.println( pgw.atasan.nama );
}

Sekarang, misalnya kita ingin tahu berapa tingkat di atas seorang pegawai hingga sampai pada
bos tertinggi. Jika bisa melacak atasan dari atasannya, dan seterusnya, hingga sampai pada bos
tertinggi, kemudian menghitung berapa langkah yang diperlukan hingga sampai ke bos tertinggi
itu:

if ( pgw.atasan == null ) {
System.out.println( pgw.nama " adalah bos tertinggi." );
}
else {
Pegawai pointer; // Untuk menunjuk pada urutan bos.
pointer = pgw.supervisor;
if ( pointer.atasan == null) {
System.out.println( pgw.nama
+ " memiliki atasan langsung bos tertinggi." );
}
else {
int level = 0;
while ( pointer.atasan != null ) {
level++; // Level atasan
pointer = pointer.atasan;
}
System.out.println( "Ada " + level
+ " atasan antara " + pgw.nama
+ " dan bos tertinggi." );
}
}
Ketika perulangan while dieksekusi, pointer akan menunjuk pada atasan pgw, kemudian
atasannya lagi, dan seterusnya. Variabel level dinaikkan 1 setiap kali pointer menunjuk pada
atasan baru. Perulangan selesai ketika pointer.atasan berisi null yang artinya pointer telah
sampai pada bos tertinggi. Pada saat itu, level telah mencatat berapa level yang dibutuhkan dari
pgw ke bos tertinggi.

Dalam contoh ini, variabel atasan terlihat natural dan berfungsi dengan baik. Sebenarnya,
struktur data yang dibangun dengan mengaitkan objek satu sama lain sangat berguna, sehingga
sering digunakan sebagai topik pembahasan dalam ilmu komputer. Kita akan melihat beberapa
contohnya. Pada bagian ini dan berikutnya, kita akan melihat yang dinamakan list berantai
(linked list).

 
List berantai merupakan rantai objek yang bertipe sama, yang terkait oleh pointer dari satu objek
ke objek lain. Mirip dengan hirarki organisasi antara pgw hingga bos tertinggi pada contoh di
atas. Kita bisa juga memiliki siatuasi yang lebih kompleks di mana satu objek berisi pointer ke
beberapa objek. Kita akan lihat contohnya di bagian berikutnya.

Di bagian ini, list berantai akan dibuat dari objek yang bertipe Simpul yang didefinisikan sebagai
berikut :

class Simpul {
String item;
Simpul berikut;
}

Istilah simpul sering digunakan untuk menyebut salah satu objek di dalam struktur data berantai.
Objek dengan tipe Simpul bisa disambung seperti pada gambar di atas. Simpul terakhir dalam
list tersebut bisa ditentukan apabila variabel instansi berikut berisi null.

Meskipun Simpul pada contoh ini terlihat sederhana, kita bisa menggunakannya untuk
mengilustrasikan operasi umum pada list berantai. Operasi umumnya meliputi menghapus
simpul dari list, menyisipkan simpul baru ke dalam list, dan mencari String pada item di dalam
list. Kita akan lihat beberapa subrutin yang melakukan operasi ini.

Agar list berantai bisa digunakan dalam program, program tersebut perlu variabel untuk
menunjuk pada simpul pertama dari list. Variabel itu hanya perlu menunjuk pada simpul
pertama, karena simpul lainnya bisa dicari dari simpul tertama kemudian mengurutkan melalui
pointer ke simpul berikutnya.

Kita bisa membuat objek baru dengan misalnya bernama "ListString" yang memiliki variabel
instansi bernama "kepala". Variabel ini bertipe Simpul dan menyimpan referensi ke simpul
pertama dari list berantai. Jika listnya kosong, maka kepala berisi null.

public class ListString {


Simpul kepala;
.
.
. // metode dan variabel instansi lainnya
}

Misalnya kita ingin tahu apakah suatu string, itemDicari ada di salah satu simpul di dalam list.
Kita bisa membandingkan itemDicari dengan isi setiap simpul di dalam list. Caranya, kita akan
menggunakan variabel bertipe Simpul yang bernama pointer untuk digunakan sebagai
penunjuk ke simpul-simpul yang akan kita lihat. Kita hanya bisa mengakses list melalui variabel
kepala, jadi kita bisa mulai dengan mengisi pointer dengan isi kepala.

Simpul pointer = kepala; // Mulai dari simpul pertama.

Kita harus membuat variabel baru ini karena kita akan mengganti isinya pada saat melakukan
pencarian. Kita tidak bisa mengganti isi kepala, karena jika kita ganti, kita akan kehilangan
jejak list yang kita buat. Untuk pindah dari satu simpul ke simpul berikutnya, kita cukup
menggunakan perintah pointer = pointer.berikut;. Kita akan tahu bahwa kita telah sampai
pada akhir list jika pointer bernilai null.

Semuanya bisa kita tuangkan dalam metode instansi cari() pada kelas ListString sebagai
berikut :

public boolean cari(String itemDicari) {


// Kembalikan true jika itemDicari ada di dalam list
// false jika tidak ada dalam list.
 
Simpul pointer; // Pointer untuk menelusuri list
 
pointer = kepala;
// Mulai pencarian dari kepala list (kepala adalah variabel instansi)
 
while ( pointer != null ) {
// Lihat isi simpul satu per satu. Jika isinya sama dengan
// yang kita cari, kembalikan true, jika tidak
// teruskan pencarian di simpul berikutnya
if ( pointer.item.equals(itemDicari) )
return true;
pointer = pointer.berikut; // Pindah ke simpul berikutnya
}
 
// Di sini, kita telah sampai pada akhir list
// akan tetapi tidak ada item yang kita cari.
// Kembalikan false, yang artinya kita tidak menemukan item ini.
 
return false;
 
} // akhir cari()

Pola di atas akan sering digunakan nanti: Jika kepala adalah variabel yang menunjuk pada suatu
list berantai, maka untuk proses semua simpul dalam list, kita bisa lakukan dengan :

pointer = kepala;
while ( pointer != null ) {
.
. // proses simpul yang ditunjuk oleh pointer
.
pointer = pointer.berikut;
}

Mungkin saja listnya kosong, yaitu apabila isi kepala adalah null. Dalam contoh kode di atas,
jika kepala berisi null, maka badan perulangan while tidak akan dieksekusi sama sekali,
karena kondisi perulangan hanya bisa dijalankan apabila pointer bernilai null.

Menyisipkan item baru ke dalam list sedikit lebih sulit. Dalam kelas ListString, item pada
simpul dibuat dalam urutan menaik. Jika suatu item ditambahkan ke dalam list, item tersebut
harus ditempatkan pada posisi yang tepat sesuai urutannya. Artinya, kita harus menyisipkan item
baru ditengah-tengah list, di antara dua simpul yang sudah ada.

Supaya mudah, kita membutuhkan dua variabel dengan tipe Simpul, di mana masing-masing
menunjuk pada 2 posisi di mana item baru akan disisipkan di antaranya. Pada ilustrasi berikut,
variabel ini adalah sebelum dan pointer. Variabel lain, yaitu simpulBaru menyimpan referensi
ke simpul baru yang akan disisipkan. Untuk melakukan penyisipan, hubungan antara sebelum
dan pointer harus diputus, dan kait baru dari sebelum ke simpulBaru dan dari simpulBaru ke
pointer harus dibuat.
Perintah "sebelum.berikut = simpulBaru;" digunakan untuk membuat sebelum.berikut
menunjuk pada simpul baru. Dan perintah "simpulBaru.berikut = pointer" digunakan untuk
membuat simpulBaru.berikut menunjuk pada pointer. Akan tetapi, sebelum kita
menjalankan perintah ini, kita harus menempatkan posisi sebelum dan pointer pada tempat
yang benar terlebih dahulu (seperti pada ilustrasi di atas).

Kita akan mulai dari awal list, kemudian pindah ke simpul berikutnya selama isinya lebih kecil
dari item baru. Ketika kita memindahkan pointer dari satu tempat ke tempat berikutnya, hati-hati
bahwa kita bisa sampai di akhir list tanpa kita sadari. Artinya kita tidak bisa meneruskan lagi
apabila pointer sampai ke akhir list, yaitu ketika pointer.next bernilai null.

Jika sisipItem adalah item item yang akan disisipkan, maka kita asumsikan bahwa item ini harus
berada di dalam list. Kode berikut akan menempatkan posisi sebelum dan pointer dengan tepat:

Simpul pointer, sebelum;


sebelum = kepala; // Mulai di awal list
pointer = kepala.berikut;
while ( pointer != null && pointer.item.compareTo(sisipItem) < 0 ) {
sebelum = pointer; // bisa juga menggunakan "sebelum = sebelum.berikut"
pointer = pointer.berikut;
}

(Kode di atas menggunakan compareTo() dari kelas String untuk menguji apakah item di
dalam node bernilai kurang dari item yang akan disisipkan.)

Kode di atas boleh-boleh saja, akan tetapi asumsi kita untuk menyisipkan node baru di tengah-
tengah list tidak selamanya benar. Mungkin saja sisipItem lebih kecil dari item pertama.
Artinya, simpul baru harus disisipkan pada kepala list. Ini bisa dilakukan dengan instruksi
berikut :

simpulBaru.berikut = kepala; // Buat simpulBaru.next menunjuk kepala lama


kepala = simpulBaru; // Buat simpulBaru sebagai kepala list yang baru

Atau bisa saja listnya kosong. Artinya, simpulBaru menjadi simpul pertama dan satu-satunya di
dalam list. Ini bisa dilakukan dengan mengisi kepala = simpulBaru. Metode sisip() berikut
ini merangkum semua kemungkinan di atas :

public void sisip(String sisipItem) {


// Tambah sisipItem ke dalam list. Boleh menyisipkan
// kopi yang sama
 
Simpul simpulBaru; // Simpul baru yang berisi item baru
simpulBaru = new Simpul();
simpulBaru.item = sisipItem; // (N.B. isi simpulBaru.berikut masih
null)
 
if ( kepala == null ) {
// List masih kosong
// Buat kepala menunjuk ke simpulBaru
kepala = simpulBaru;
}
else if ( kepala.item.compareTo(sisipItem) >= 0 ) {
// Item baru kurang dari item pertama list
// Jadi item baru harus disisipkan sebelum kepala list
simpulBaru.berikut = kepala;
kepala = simpulBaru;
}
else {
// Item baru akan disisipkan di tengah-tengah list setelah
// item pertama. Cari posisi yang tepat dan sisipkan di sana
Simpul pointer; // Simpul untuk menelusuri list
Simpul sebelum; // Simpul yang menunjuk pada posisi sebelum pointer
sebelum = kepala; // Set sebelum ke kepala list dan pointer ke posisi
setelahnya
pointer = kepala.berikut;
while (pointer != null && pointer.item.compareTo(sisipItem) < 0) {
// Pindahkan sebelum dan pointer ke posisi berikutnya hingga
pointer
// sampai di akhir list atau sampai pada item yang isinya lebih
besar
// dari sisipItem. Setelah perulangan selesai, pointer menunjuk
// pada posisi di mana sisipItem akan disisipkan
sebelum = pointer;
pointer = pointer.berikut;
}
simpulBaru.berikut = pointer; // Sisipkan simpulBaru setelah
"sebelum"
sebelum.berikut = simpulBaru;
}
} // akhir sisip()
Jika Anda memperhatikan dengan seksama diskusi di atas, mungkin Anda akan ingat bahwa ada
satu kasus lagi yang tidak pernah disebutkan. Apa yang terjadi jika simpul baru harus disisipkan
di akhir list? Ini terjadi jika semua item di dalam list lebih kecil daripada item baru.

Sebenarnya, kasus ini sudah ditangani dengan benar oleh subrutin, yaitu di bagian akhir
pernyataan if . Jika sisipItem lebih besar dari semua item di dalam list, maka perulangan
while akan berhenti ketika pointer selesai menelusuri sampai pada akhir list hingga pointer
bernilai null. Akan tetapi, ketika ini terjadi, sebelum masih tetap menunjuk pada item terakhir
pada list. Perintah sebelum.berikut = simpulBaru menambahkan simpul baru di akhir list.
Karena isi pointer adalah null, maka perintah [code]simpulBaru.berikut = pointer
akan mengisi simpulBaru.berikut dengan null. null adalah nilai yang tepat untuk
menandakan akhir list.

Operasi untuk menghapus mirip dengan operasi menyisipkan item, meskupun sedikit lebih
mudah. Masih ada beberapa kasus khusus yang harus dipikirkan. Ketika simpul pertama akan
dihapus, maka isi kepala harus diubah ke simpul kedua. Karena kepala.berikut adalah simpul
berikutnya, maka ini bisa dilakukan dengan perintah kepala = kepala.berikut. (Sekali lagi,
perhatikan bahwa perintah ini juga berlaku jika kepala.berkut berisi null[code], yaitu
ketika hanya ada satu item di dalam list. Ketika satu-satunya item ini
dihapus, maka list bernilai [code]null yang artinya list sudah kosong.)

Jika simpul yang akan dihapus ada di tengah-tengah list, maka kita bisa membuat variabel
sebelum dan pointer di mana pointer menunjuk pada simpul yang akan dihapus, dan sebelum
menunjuk pada simpul sebelumnya. Setelah diposisikan dengan benar, perintah
"sebelum.berikut = pointer.berikut" akan menghapus simpul tersebut. Simpul yang
dihapus akan diambil oleh pemulung memori.

Berikut ini adalah kode lengkap dari metode hapus() :

public boolean hapus(String hapusItem) {


// Jika hapusItem ada dalam list, hapus.
// Kembalikan true jika string ditemukan dan dihapus.
// Jika string tidak ditemukan kembalikan false.
// (Jika ada beberapa item dengan isi yang sama, hanya
// hapus yang pertama)
 
if ( kepala == null ) {
// Jika list kosong, sudah pasti tidak ada string hapusItem
return false;
}
else if ( kepala.item.equals(hapusItem) ) {
// Jika hapusItem ada pada simpul pertama, hapus.
kepala = kepala.berikut;
return true;
}
else {
// Di sini, maka ada kemungkinan string terdapat
// di tengah-tengah list. Cari itemnya di dalam list.
Simpul pointer; // Simpul untuk menelusuri list
Simpul sebelum; // Selalu menunjuk pada simpul sebelum pointer
sebelum = kepala; // Mulai dari awal list
pointer = kepala.berikut;
while (pointer != null && pointer.item.compareTo(hapusItem) < 0) {
// Pindahkan sebelum dan pointer di dalam list hingga
// pointer sampai pada akhir list atau sampai pada item yang
// lebih besar atau sama dengan hapusItem. Ketika perulangan
// selesai, pointer menunjuk pada posisi di mana hapusItem
// seharusnya berada (jika ada)
sebelum = pointer;
pointer = pointer.berikut;
}
if ( pointer != null && pointer.item.equals(hapusItem) ) {
// Pointer menunjuk pada simpul yang akan dihapus
// Hapus dengan mengubah simpul sebelumnya
sebelum.berikut= pointer.berikut;
return true;
}
else {
// Item yang dicari tidak ada
return false;
}
}
} // akhir hapus()

Tumpukan
Posted Jum, 03/27/2009 - 23:36 by belajarprogram

Versi ramah cetak

List berantai adalah salah satu jenis struktur data, yang tersusun dari objek yang terkait satu sama
lain oleh pointer. Pada bagian sebelumnya, kita menggunakan list berantai untuk menyimpan
String terurut, dan kita juga mengimplementasikan operasi sisip, hapus dan cari pada list
tersebut.

Akan tetapi kita juga bisa menyimpan list String pada array atau ArrayList. Kita bisa juga
mengimplementasikan operasi sisip, hapus, dan cari. Implementasi operasi tersebut akan
berbeda, akan tetapi antar muka dan perilakunya akan tetap sama.

Istilah tipe data abstrak (abstract data type, atau ADT) adalah kumpulan nilai dan operasi yang
bisa dilakukan pada nilai tersebut, tanpa perlu mengetahui bagaimana nilai tersebut disimpan dan
bagaimana operasi tersebut diimplementasikan.

Suatu "list terurut yang berisi string" adalah contoh tipe data abstrak. Ada banyak cara untuk
mengimplementasikan tipe data abstrak yang sama, misalnya seperti disebut di atas, list terurut
berisi string bisa diimplementasikan dalam bentuk list berantai atau array.
Program yang menggunakan tipe data ini bisa menggunakannya tanpa mengetahui dengan detail
tentang implementasinya. Lebih jauh, implementasi TDA bisa diganti tanpa mempengaruhi
jalannya program secara keseluruhan. Dengan cara ini, program bisa lebih mudah untuk
dipelihara dan didebug. TDA adalah alat penting dalam rekayasa perancang lunak.

Pada bagian ini dan yang akan datang, kita akan lihat TDA lain, yaitu tumpukan dan antrian.
Tumpukan dan antrian sering diimplementasikan dalam bentuk list berantai, akan tetapi ini
bukan satu-satunya cara implementasi. Mari kita anggap bagian ini sebagai studi kasus dari
TDA.

Tumpukan (stack) terdiri dari kumpulan item yang disusun sedemikian rupa sehingga satu item
ditumpuk di atas item lainnya, mirip seperti tumpukan boks. Hanya item paling atas yang bisa
diakses pada suatu saat.

Item tersebut bisa diambil dari tumpukan dengan operasi yang disebut "ambil" (atau dalam
bahasa Inggris, istilah untuk mengeluarkan item dari tumpukan disebut "pop"). Item di bawah
hanya bisa diambil jika semua item di atasnya telah dikeluarkan dari tumpukan. Suatu item
hanya bisa ditambahkan di atas tumpukan dengan perintah "dorong" (atau "push").

Kita bisa membuat tumpukan dari berbagai macam data. Misalnya, jika itemnya bertipe int,
maka operasi dorong dan keluar bisa diimplementasikan dalam metode instansi

void dorong(int itemBaru) // Tambah itemBaru di atas tumpukan


 
int ambil() // Mengambil int paling atas pada tumpukan

Kita tidak bisa mengambil item dari tumpukan yang kosong, jadi kita juga perlu memberi tahu
apakah suatu tumpukan kosong atau tidak. Kita perlu operasi lain untuk mengujinya, yang
diimplementasikan dalam metode instansi

boolean isKosong() // Kembalikan true jika tumpukan kosong

Ilustrasi berikut menggambarkan tumpukan int, sebagai tipe data abstrak. TDA ini bisa
diimplementasikan dengan berbagai cara, akan tetapi gambar tumpukan di dalam imaginasi kita
akan tetap sama.
Pada implementasi dengan list berantai, tumpukan atas adalah simpul kepala dari list. Kita bisa
menambah dan mengurangi simpul pada kepala list berantai -- jauh lebih mudah daripada
menyisipkan atau menghapus simpul dari tengah-tengah list.

Berikut ini adalah kelas "tumpukan int" yang mengimplementasikan TDA menggunakan list
berantai. (Kelas ini menggunakan kelas bertingkat sebagai kelas simpul dari list berantai. Lihat
bagian sebelumnya tentang kelas bertingkat. Jika Anda masih belum paham atau merasa tidak
nyaman menggunakan kelas bertingkat, Anda bisa juga memisahkannya sebagai kelas terpisah.)

public class TumpukanInt {


 
private static class Simpul {
// Objek dengan tipe Simpul menyimpan
// satu item di dalam list berantai
int item;
Simpul berikut;
}
 
// Referensi ke simpul paling atas dari tumpukan
// jika atas == null, maka tumpukan tidak berisi
// apa-apa (kosong)
private Simpul atas;
 
public void dorong( int N ) {
// Letakkan N di tumpukan paling atas
Simpul atasBaru; // Simpul baru untuk menyimpan item baru
atasBaru = new Simpul();
atasBaru.item = N; // Simpan N di simpul baru
atasBaru.berikut = atas; // Simpul baru menunjuk pada atas lama
atas = atasBaru; // Simpul baru sekarang menjadi atas
}
 
public int ambil() {
// Ambil item paling atas dari dalam tumpukan
// dan kembalikan nilainya. Catatan bahwa rutin ini akan
// melempar NullPointerException jika kita mencoba untuk
// mengambil item dari tumpukan kosong
int itemAtas = atas.item; // Item yang akan diambil
atas = atas.berikut; // Item yang dulunya di posisi kedua sekarang
di atas
return itemAtas;
}
 
public boolean isKosong() {
// Kembalikan true jika tumpukan kosong.
// Kembalikan false jika ada satu atau lebih item di dalam tumpukan
return (atas == null);
}
 
} // akhir kelas TumpukanInt

Anda perlu memahami bagaimana operasi dorong dan ambil dilaksanakan. Mungkin sedikit
oret-oretan akan membantu. Lihat bahwa list berantai merupakan bagian private dari kelas
TumpukanInt. Program yang menggunakan kelas ini tidak perlu tahu bahwa list berantai
digunakan dalam implementasinya.

Sekarang, kita bisa juga mengimplementasikan tumpukan dalam bentuk array, bukan hanya list
berantai. Karena banyaknya item di dalam tumpukan bervariasi dan tidak bisa ditentukan, maka
kita perlu memiliki variabel lain yang melacak berapa banyak tempat dalam array yang sudah
digunakan.

Jika variabel ini kita namakan atas, maka item akan disimpan dalam tumpukan pada posisi 0,
1, ..., atas - 1. Item pada posisi 0 adalah item paling bawah dalam tumpukan, sedangkan item
atas - 1 adalah item paling atas.

Untuk mendorong item baru ke dalam tumpukan, kita bisa meletakkan item di posisi atas
kemudian nilai atas ditambahkan 1. Jika kita tidak ingin memberi limit banyaknya item di
dalam tumpukan, kita bisa menggunakan array dinamis yang telah dibahas sebelumnya.

Berikut ini adalah implementasi kelas TumpukanInt dengan menggunakan array dinamis:

public class TumpukanInt {


 
private int[] item = new int[10]; // Menyimpan item dalam tumpukan
 
private int atas = 0; // Banyaknya item dalam tumpukan
 
public void dorong( int N ) {
// Tambahkan N ke dalam tumpukan
if (atas == item.length) {
// Array sudah penuh, jadi buat array yang lebih besar dan
// kopi isi tumpukan sekarang ke dalam array baru
int[] arrayBary = new int[ 2*item.length ];
System.arraycopy(item, 0, arrayBary, 0, item.length);
item = arrayBaru;
}
item[atas] = N; // Letakkan N di tempat kosong berikutnya
atas++; // Jumlah item bertambah 1
}
 
public int ambil() {
// Mengambil item teratas dari tumpukan dan mengembalikannya
// Ingat bahwa rutin ini akan melempar pengecualian
// ArrayIndexOutOfBoundsException jika mencoba mengambil
// item dari tumpukan kosong
int itemAtas = item[top - 1] // Item teratas di dalam tumpukan
atas--; // Jumlah item dalam tumpukan berkurang 1
return itemAtas;
}
 
public boolean isKosong() {
// Kembalikan true jika tumpukan kosong
// Kembalikan false jika ada satu atau lebih item di dalam tumpukan
return (atas == 0);
}
 
} // akhir kelas TumpukanInt

Sekali lagi, implementasi tumpukan (dalam bentuk array) bersifat private. Kedua versi kelas
TumpukanInt bisa digunakan dalam suatu program. Jika suatu program menggunakan versi
pertama, maka kita bisa menggantinya dengan versi kedua tanpa mengubah isi program lain.
Akan tetapi, ada satu kasus di mana kedua kelas akan berbeda, yaitu jika mencoba mengambil
item dari tumpukan kosong, maka versi pertama akan melemparkan NullPointerException
sedangkan versi kedua akan melemparkan ArrayIndexOutOfBoundsException.

Mungkin akan lebih baik untuk mendefinisikan jenis pengecualian baru, misalnya
EmptyStackException di kedua versi. Dan sebetulnya TDA harusnya memberikan spesifikasi
apa yang harus dilakukan jika program mencoba mengambil item dari tumpukan kosong. Ini
yang sering dilupakan ketika seseorang membuat spesifikasi untuk interface, yang akhirnya
masalah lain akan muncul di kemudian hari.

Apa contoh kegunaan tumpukan dalam keadaan sehari-hari? Misalnya, lihat apa yang terjadi jika
suatu rutin memanggil subrutin. Rutin pertama akan dihentikan sementara ketika subrutin yang
dipanggil dieksekusi, dan akan diteruskan apabila subrutin yang dipanggil selesai dijalankan.

Sekarang, misalnya subrutin tersebut memanggil subrutin kedua, dan subrutin kedua memanggil
subrutin ketiga, dan seterusnya. Setiap subrutin akan berhenti untuk sementara ketika subrutin
berikutnya dipanggil. Komputer harus bisa melacak subrutin yang dihentikan. Bagaimana
caranya? Yaitu dengan menggunakan tumpukan.

Ketika subrutin dipanggil, catatan aktivasi (activation record) dibuat untuk subrutin tersebut.
Catatan aktivasi ini berisi informasi yang relevan tentang eksekusi dari subruti tersebut, misalnya
parameter dan variabel lokalnya. Catatan aktivasi ini ditempatkan dalam tunpukan. Catatan ini
akan dibuang ketika subrutin selesai dipanggil.

Jika subrutin ini memanggil subrutin lain, maka catatan aktivasi dari subrutin kedua akan
didorong ke dalam tumpukan, di atas catatan aktivasi subrutin pertama. Tumpukan akan semakin
besar jika semakin banyak subrutin yang dipanggil, dan semakin kecil jika subrutin-subrutin itu
selesai dijalankan.

Contoh lainnya, tumpukan digunakan untuk mengevaluasi ekspresi postfix (postfix expresssion).
Ekspresi matematika biasa seperti 2+(15-12)*17 disebut ekspresi infix. Dalam ekspresi infix,
operator berada di tengah nilai yang akan dihitung, misalnya "2 + 2". Dalam ekspresi postfix,
operator ada di akhir nilai, misalnya "2 2 +".

Ekspresi 2+(15-12)*17" dapat ditulis dalam bentuk postfix menjadi "2 15 12 - 17 * +". Di
sini operator "-" dilakukan pada dua nilai sebelumnya, yaitu "15" dan "12". Tanda * dilakukan
pada dua nilai sebelumnya, yaitu "15 12 -" dan "17". Dan operator "+" dilakukan pada 2 dan "15
12 - 17 *". Hasilnya akan persis sama dengan ekspresi infix awalnya.

Meskipun lebih mudah bagi manusia untuk melakukan perhitungan dengan ekspresi infix,
ekspresi postfix memiliki beberapa keuntungan. Satu hal, ekspresi postfix tidak memerlukan
tanda kurung atau aturan perhitungan (tanda kali harus dilakukan lebih dulu sebelum tambah
misalnya). Aturan penghitungan hanya ditentukan berdasarkan urutannya saja. Sehingga
algoritma yang menghitung ekspresi postfix dapat menjalankannya dengan lebih cepat dan tepat.

Sekarang misalnya kita akan menghitung ekspresi "2 15 12 - 17 * +" dari kiri ke kanan. Nilai
yang kita temui pertama adalah 2, tapi apa yang bisa kita lakukan dengan 2? Di sini kita belum
tahu operatornya, dan selain itu kita juga belum tahu nilai lainnya. Kita akan ingat nilai 2 ini
untuk sementara, yaitu dengan mendorongnya ke dalam tumpukan.

Berikutnya, kita akan melihat nilai 15, yang kita juga masukkan ke dalam tumpukan di atas nilai
2. Kemudian nilai 12 juga dimasukkan ke dalam tumpukan di atas 15.

Sekarang kita sampai pada operator "-". Operasi ini dilakukan pada dua nilai sebelumnya. Kita
telah menyimpan 2 nilai sebelumnya ke dalam tumpukan, yaitu 15 dan 12. Sekarang kita ambil 2
nilai tersebut dari dalam tumpukan, dan kita lakukan perhitungan 15 - 12 yaitu 3.

Nilai 3 ini kita simpan lagi ke dalam tumpukan. Ingat bahwa 15 dan 12 sudah diambil dari dalam
tumpukan, sehingga hanya nilai 2 yang ada di dalam tumpukan. Setelah nilai 3 dimasukkan ke
dalam tumpukan, maka 3 ada di atas 2 di dalam tumpukan.
Item berikutnya adalah 17, yang juga dimasukkan ke dalam tumpukan di atas nilai 3. Untuk
menghitung item berikutnya "*", kita ambil 2 nilai dari dalam tumpukan, yaitu 3 dan 17. Hasil
dari 3 * 17, yaitu 51 dimasukkan kembali ke dalam tumpukan (di atas 2 yang masih ada di
dalam tumpukan).

Item berikutnya adalah "+", yang akan mengambil 51 dan 2 dari dalam tumpukan, menghitung
hasilnya, yaitu 53, kemudian menyimpannya lagi ke dalam tumpukan. Sekarang kita sampai
pada akhir ekspresi. Nilai pada tumpukan itu adalah hasil perhitungan keseluruhan ekspresi. Kita
cukup mengambil nilainya dan melaporkan hasilnya, yaitu 53.

Algoritma untuk melakukan perhitungan ekspresi postfix adalah sebagai berikut :

Mulai dengan tumpukan kosong


untuk setiap item di dalam ekspresi:
jika item berupa bilangan:
Dorong item ke dalam tumpukan
jika item berupa operator
Ambil dua nilai dari tumpukan // bisa terjadi kesalahan
Lakukan perhitungan dua nilai dengan operator tersebut
Dorong hasil perhitungan ke dalam tumpukan
else
Ada kesalahan dalam ekspresi
Ambil nilai dari tumpukan
Jika tumpukan tidak kosong:
Ada kesalahan dalam ekspresi
else:
Nilai terakhir adalah hasil perhitungan

Kesalahan ekspresi dapat dideteksi dengan mudah. Misalnya, dalam ekspresi "2 3 + *", tidak
cukup nilai untuk menghitung operasi "*". Ini akan dideteksi oleh algoritma ketika mencoba
mengambil nilai kedua dari dalam tumpukan, karena pada saat itu tumpukan sudah kosong.

Kesalahan lain bisa juga muncul ketika menghitung ekspresi "2 3 4 +", di mana tidak cukup
operator untuk menghitung semua nilai. Ini akan dideteksi ketika 2 masih ada di dalam
tumpukan di akhir algoritma.

Ekspresi postfix sering digunakan secara internal oleh komputer. Dan sebenarnya, mesin virtual
Java adalah "mesin tumpukan", yang menggunakan tumpukan untuk melakukan perhitungan
yang telah kita diskusikan. Algoritma ini bisa diperluas untuk menangani variabel dan konstanta.
Ketika variabel ditemukan di dalam ekspresi, isi variabel ini didorong ke dalam tumpukan.

Algoritma ini juga bisa dikembangkan untuk operator yang membutuhkan kurang atau lebih dari
dua operator. Banyaknya nilai yang diambil dari dalam tumpukan bisa disesuaikan dengan
berapa banyak nilai yang dibutuhkan. Misalnya, operator "-" sebagai operator negasi, misalnya "-
x" hanya membutuhkan satu nilai.

Antrian
Posted Sab, 03/28/2009 - 23:23 by belajarprogram
Versi ramah cetak

Antrian (queue) adalah struktur data mirip dengan tumpukan, yaitu terdiri dari item dalam urutan
tertentu. Antrian memiliki dua ujung, yang disebut ujung depan dan ujung belakang. Item selalu
dimasukkan dari belakang antrian, dan selalu dikeluarkan dari depan antrian. Operasi
memasukkan dan mengeluarkan item dari dalam antrian disebut "masuk" dan "keluar" (dalam
bahasa Inggris disebut enqueue dan dequeue).

Suatu item yang ditambahkan di belakang antrian tidak bisa dihapus sebelum item di depannya
dihapus. Mirip seperti antrian pada kasir atau pada customer service di bank misalnya. Customer
akan dilayani dalam urutan ketika mereka datang.

Antrian bisa menampung item dengan jenis apa saja. Untuk antrian int, operasi masuk dan keluar
dapat diimplementasikan sebagai metode instansi dalam kelas "AntrianInt". Kita juga
membutuhkan metode instansi untuk menguji apakah antrian kosong atau tidak:

void masul(int N) // Tambah N di belakang antrian


 
int keluar() // Keluarkan antrian dari depan dan kembalikan isinya
 
boolean isKosong() // Kembalikan true jika antrian kosong

Antrian bisa diimplementasikan dalam bentuk list berantai atau array. Akan tetapi implementasi
yang efisien dalam bentuk array sedikit lebih sulit, sehingga akan kita abaikan dalam diskusi
kita.

Dalam implementas dalam bentuk list berantai, item bertama adalah item di depan antrian. Untuk
mengeluarkan item dari depan antrian, kita dapat lakukan seperti mengambil item dari atas
tumpukan.

Belakang antrian adalah akhir dari list. Unutk memasukkan item ke dalam antrian, kita harus
mengeset pointer di akhir simpul untuk menunjuk ke simpul baru yang berisi item yang akan kita
tambahkan. Kita bisa menggunakan perintah seperti "buntut.berikut = simpulBaru;", di
mana buntut adalah pointer ke simpul terakhir dari list.

Jika kepala adalah pointer ke simpul pertama, maka kita bisa mendapat pointer ke simpul
terakhir dengan menggunakan :

Simpul buntut; // Pointer ini akan menunjuk ke simpul terakhir


buntut = kepala; // Mulai dari simpul pertama
while (buntut.berikut != null) {
buntut = buntut.berikut;
}
// Di sini, buntut.berikut berisi null, artinya buntut adalah
// simpul terakhir di dalam list

Akan tetapi, tentunya akan sangat tidak efisien jika kita harus melakukan perulangan terus
menerus setiap kali kita memasukkan item baru ke dalam antrian. Dengan alasan efisiensi, kita
akan menyimpan pointer ke akhir simpul sebagai variabel instansi. Kita harus selalu ingat untuk
terus mengupdate isi variabel ini setiap kali simpul baru ditambahkan ke akhir list.

Dengan pengetahuan di atas, kita bisa membuat kelas "AntrianInt" dengan mudah sebagai
berikut :

public class AntrianInt {


 
private static class Simpul {
// Objek bertipe Simpul berisi item dalam bentuk
// list berantai
int item;
Simpul berikut;
}
 
// Menunjuk ke simpul pertama pada antrian
// Jika antrian kosong, maka kepala berisi null
private Simpul kepala = null;
 
private Simpul buntut = null; // Menunjuk ke simpul akhir pada antrian
 
void masuk( int N ) {
// Menambahkan N ke akhir antrian
Simpul buntutBaru = new Simpul(); // Simpul baru untuk menampung
item baru
buntutBaru.item = N;
if (kepala == null) {
// Antrian kosong, sehingga simpulBaru menjadi
// satu-satunya simpul di dalam list. Sehingga
// kepala dan buntut sama-sama menunjuk ke simpulBaru
kepala = buntutBaru;
buntut = buntutBaru;
}
else {
// Simpul baru menjadi buntut antrian
// (kepala tidak berpengaruh apa-apa)
buntut.berikut = buntutBaru;
buntut = buntutBaru;
}
}
 
int keluar() {
// Keluarkan item dari kepala antrian
// Bisa melempar NullPointerException.
int itemPertama = kepala.item;
kepala = kepala.berikut; // Sekarang item kedua menjadi kepala
if (kepala == null) {
// Sekarang antrian kosong. Simpul yang telah dihapus adalah
// kepala sekaligus buntut, karena simpul ini adalah satu-satunya
// yang ada di dalam antrian. Isi buntut dengan null.
buntut = null;
}
return itemPertama;
}
 
boolean isKosong() {
// Kembalikan true jika antrian kosong
return (kepala == null);
}
 
} // akhir kelas AntrianInt

Antrian digunakan dalam komputer (dan juga dalam kehidupan nyata) ketika hanya satu item
yang bisa diproses pada suatu saat, akan tetapi banyak item bisa menunggu untuk diproses,
misalnya :

 Dalam Java program yang memiliki banyak threads, thread yang ingin diolah dalam CPU
disimpan di dalam antrian. Ketika thread baru dimulai, thread ini ditambahkan ke dalam antrian.
Thread akan dihapus dari depan antrian, diolah oleh CPU, dan kemudian -- jika belum selesai --
diletakkan kembali di belakang antrian untuk menunggu giliran berikutnya.
 Event seperti ketikan tombol dan klik mouse disimpan dalam antrian yang disebut "antrian
event". Program akan menghapus item dari antrian item dan mengolahnya satu per satu.
Mungkin saja terjadi beberapa event diterima ketika satu event sedang diproses, akan tetapi
event akan diolah berdasarkan urutan kedatangannya
 ServerSocket, memiliki antrian di dalamnya yang berisi permintaan sambungan yang diterima
akan tetapi belum dilayani. Metode accept() pada kelas ServerSocket menerima
permintaan sambungan berikutnya dari depan antrian ini.

Antrian disebut mengikuti kebijakan FIFO (First In First Out, atau Pertama Masuk Pertama
Keluar). Atau dalam bahasa awam, pertama datang dan pertama dilayani. Di lain pihak,
tumpukan mengikuti prinsip LIFO (Last In First Out, Terakhir Masuk Pertama Keluar). Item
yang bisa keluar dari tumpukan adalah item terkakhir yang dimasukkan. Seperti antrian,
tumpukan juga bisa digunakan untuk menampung item yang sedang menunggu untuk diproses
(walaupun dalam aplikasi di mana antrian biasa digunakan, tumpukan adalah antrian yang tidak
adil).

Pohon Biner
Posted Min, 03/29/2009 - 14:51 by belajarprogram

Versi ramah cetak

Kita telah melihat di beberapa bagian sebelumnya bagaimana objek bisa dikaitkan satu sama lain
menjadi list berantai. Ketika suatu objek memiliki 2 pointer ke objek dengan tipe yang sama, kita
bisa membuat struktur data yang lebih kompleks dari list berantai. Dalam bagian ini kita akan
melihat salah satu struktur dasar dan paling berguna: pohon biner (binary tree).

Setiap objek dalam pohon biner memiliki dua pointer, yang biasa disebut kiri dan kanan. Selain
itu, tentunya simpul pada pohon memiliki data yang bisa bertipe apa saja. Misalnya, pohon biner
integer bisa dibuat dalam bentuk :

class SimpulPohon {
int item; // Data pada simpul ini
SimpulPohon kiri; // Pointer ke cabang sebelah kiri
SimpulPohon kanan; // Pointer ke cabang sebelah kanan
}
Pointer kiri dan kanan dalam SimpulPohon bisa beriis null atau menunjuk pada objek lain
dengan tipe SimpulPohon. Simpul yang menunjuk pada simul lain disebut induk (parent),
sedangkan yang ditunjuk disebut anak (child). Dalam gambar di atas, simpul 3 adalah induk dari
simpul 6, dan simpul 4 dan 5 adalah anak dari simpul 2.

Tidak semua struktur yang terdiri dari simpul pohon merupakan pohon biner. Pohon biner harus
memiliki sifat :

 Harus ada satu simpul di dalam pohon yang tidak memiliki induk. Simpul ini disebut simpul akar
(root).
 Simpul lain harus memiliki hanya satu induk
 Tidak boleh ada perulangan dalam pohon biner, artinya tidak boleh ada rantai pointer yang
dimulai dari satu simpul dan berakhir di simpul yang sama.

Simpul yang tidak memiliki anak disebut simpul daun (leaf). Simpul daun dapat dikenali karena
kedua pointer kiri dan kanannya berisi null. Dalam ilustrasi suatu pohon biner, biasanya simpul
akar terletak di atas dan simpul daun terletak di bawah -- tidak sama seperti pohon sungguhan.
Akan tetapi, kita bisa melihat cabang-cabang, seperti pohon, yang merupakan cikal bakal nama
pohon biner ini.

Misalnya, mari kita lihat suatu simpul pada pohon biner. Lihat simpul tersebut beserta seluruh
simpul turunannya (yaitu anak, anak dari anaknya, dan seterusnya). Simpul-simpul ini juga
membentuk pohon biner, yang disebut pohon cabang (subtree) dari pohon awalnya. Misalnya,
pada gambar di atas, simpul 2, 4, dan 5 membentuk pohon cabang. Pohon cabang ini disebut
pohon cabang sebelah kiri dari simpul akarnya. Hal yang sama, simpul 3 dan 6 adalah pohon
cabang sebelah kanan dari simpul akarnya. Salah satu atau kedua pohon cabang bisa kosong. Ini
adalah definisi rekursif. Jadi tidak heran apabila kita menerapkan subrutin rekursif untuk
mengolah struktur data pohon.

Mari kita lihat bagaimana caranya menghitung banyaknya simpul di dalam pohon biner. Sebagai
latihan, kita mungkin bisa membuat algoritma untuk menghitung simpul. Inti permasalahannya
adalah, bagaimana melacak simpul mana yang belum dihitung. Ini bukan hal sepele. Dan
mungkin kita tidak mungkin menyelesaikannya tanpa menggunakan tumpukan atau antrian.

Dengan rekursi, algoritmanya akan jauh lebih mudah. Suatu pohon bisa kosong, atau bisa terdiri
dari akar dan dua pohon cabang. Jika pohon kosong, maka banyaknya simpul adalah nol. (Ini
merupakan kasus dasar dari rekursi). Kemudian kita bisa menggunakan rekursi untuk
menghitung jumlah simpul pada masing-masing pohon cabang. Jumlahkan hasil dari kedua
cabang, kemudian tambah satu simpul akarnya. Ini adalah jumlah simpul di dalam pohon.

Dalam Java bisa kita tuliskan sebagai :

static int hitungSimpul( SimpulPohon akar ) {


// Hitung berapa simpul yang dimiliki suatu pohon
// biner, termasuk akarnya
if ( akar == null )
return 0; // Pohon kosong, tidak ada simpul di dalamnya
else {
int jumlah = 1; // Mulai dengan menghitung akarnya
 
// Tambahkan dengan simpul dari pohon cabang sebelah kiri
jumlah += hitungSimpul(akar.kiri);
 
// Tambahkan dengan simpul dari pohon cabang sebelah kanan
jumlah += hitungSimpul(akar.kanan);
return hitung; // Kembalikan jumlahnya
}
} // akhir hitungSimpul()

Juga, mari kita lihat bagaimana mencetak isi item di dalam pohon biner. Jika pohon kosong, kita
tidak melakukan apa-apa. Jika pohon tidak kosong, maka mungkin ia berisi akar dan dua pohon
cabangnya. Cetak item pada akarnya, dan gunakan rekursi untuk mencetak item di dalam pohon
cabangnya. Berikut ini adalah subrutin untuk mencetak semua item dalam satu baris cetakan.

static void preorderCetak( SimpulPohon akar ) {


// Cetak semua item di dalam pohon yang ditunjuk oleh akar.
// Item pada akar dicetak dahulu, kemudian item di sebelah kiri
// dan baru item di pohon cabang sebelah kanan
if ( akar != null ) { // (Jika null, kita tidak melakukan apa-apa.)
System.out.print( akar.item + " " ); // Print item akar
preorderCetak( akar.kiri ); // Print item di pohon cabang kiri
preorderCetak( akar.kanan ); // Print items di pohon cabang kanan
}
} // akhir preorderCetak()
Rutin ini disebut "preorderCetak" karena ia menelusuri pohon secara preorder. Dalam
penelusuran preorder, simpul akan diproses terlebih dahulu, kemudian pohon cabang sebelah kiri
ditelusuri, dan kemudian cabang sebelah kanan. Dalam penelusuran postorder, cabang kiri
ditelusuri, kemudian cabang kanan, baru kemudian simpul akar. Dan dalam penelusuran inorder,
cabang kiri dikunjungi dahulu, kemudian akar, dan kemudian cabang kanan.

Subrutin yang mencetak postorder dan inorder berbeda dengan preorder dalam urutan
pencetakannya di layar :

static void postorderCetak( SimpulPohon akar ) {


// Cetak semua item di dalam pohon yang ditunjuk oleh akar.
// Cabang pohon sebelah kiri dicetak dahulu, kemudian kanan,
// dan baru simpul akarnya
if ( akar != null ) { // (Jika null, kita tidak melakukan apa-apa.)
postorderCetak( akar.kiri ); // Print item di pohon cabang kiri
postorderCetak( akar.kanan ); // Print items di pohon cabang kanan
System.out.print( akar.item + " " ); // Print item akar
}
} // akhir postorderCetak()
 
static void inorderCetak( SimpulPohon akar ) {
// Cetak semua item di dalam pohon yang ditunjuk oleh akar.
// Cabang pohon cabang sebelah kiri dicetak dahulu,
// kemudian simpul akarnya, baru pohon cabang sebelah kanan
if ( akar != null ) { // (Jika null, kita tidak melakukan apa-apa.)
inorderCetak( akar.kiri ); // Print item di pohon cabang kiri
System.out.print( akar.item + " " ); // Print item akar
inorderCetak( akar.kanan ); // Print items di pohon cabang kanan
}
} // akhir inorderCetak()

Subrutin ini bisa dijalankan pada pohon biner yang diilustrasikan di awal bagian ini. Urutan item
ketika dicetak akan berbeda, di mana :

preorderCetak mencetak: 1 2 4 5 3 6
 
postorderCetak mencetak: 4 5 2 6 3 1
 
inorderCetak mencetak: 4 2 5 1 3 6

Dalam preorderCetak misalnya, itam pada akar pohon, yaitu 1, dicetak paling awal. Akan
tetapi urutan preorder juga dilakukan untuk setiap pohon cabangnya. Simpul akar pada pohon
cabang sebelah kiri, yaitu 2, dicetak terlebih dahulu sebelum pohon cabangnya 4 dan 5.
Sedangkan untuk cabang sebelah kanan, akarnya 3 akan dicetak sebelum 6. Penelusuran preorder
dilakukan pada semua cabang pohon. Urutan penelusuran yang lainnya bisa dianalisis dengan
cara yang sama.

Pohon Pengurutan Biner


Posted Min, 03/29/2009 - 15:35 by belajarprogram
Versi ramah cetak

Pada bagian sebelumnya kita membahas tentang list berantai dari string, di mana string dijaga
agar tetap dalam urutan menaik. Akan tetapi list berantai seperti ini bisa bekerja untuk jumlah
yang tidak terlalu banyak. Untuk jumlah item yang sangat banyak, list berantai kurang efisien.
Ketika kita menambahkan item ke dalam list, kita harus mencari dahulu posisi yang tepat di
mana item akan disisipkan. Untuk melakukan pencarian, kita harus melihat paling tidak separuh
dari seluruh list.

Jika string list diimplentasikan dalam bentuk array terurut, maka pencariannya bisa dilakukan
lebih cepat, karena pencarian biner bisa digunakan. Akan tetapi untuk menyisipkan item ke
dalam array terurut juga tidak efisien, karena kita harus memindahkan paling tidak setengah isi
array untuk memberi tempat untuk item baru yang akan disisipkan.

Pohon biner bisa digunakan untuk menyimpan string list terurut (atau item jenis lain), sehingga
pencarian dan penyisipan bisa dilakukan dengan mudah. Pohon biner ini disebut pohon
pencarian biner.

Pohon pencarian biner adalah pohon biner yang memiliki sifat :

 Untuk setiap simpul pada pohon, item pada simpul tersebut lebih besar dari semua item di
cabang kiri pohon
 Dan simpul tersebut, lebih besar atau sama dengan semua item di cabang kanan pohon

Berikut ini adalah contoh pohon pengurutan biner yang memiliki item bertipe String. (Dalam
gambar ini pointer berisi null tidak digambarkan, sedangkan pointer yang tidak null
dilambangkan dengan tanda panah)
Pohon pencarian biner memiliki sifat penting berikut : Penelusuran inorder akan mengolah item
dalam urutan menaik. Misalnya, penelusuran inorder digunakan untuk mencetak isi pohon di atas
dalam urutan alfabet. Penelusuran inorder menjamin bahwa semua item di cabang kiri pohon dari
elemen "judy" akan dicetak sebelum "judy", dan semua item di cabang kanan pohon akan dicetak
setelah "judy". Karena sifat pohon biner yang mengharuskan item di cabang kiri lebih kecil dari
item pada simpul, maka keluarannya akan sama dengan mengurutkan isi pohon secara alfabet
dalam urutan menaik.

Misalnya kita ingin mencari item di dalam pohon pencari biner. Pertama, bandingkan item
dengan isi simpul akarnya. Jika isinya sama, maka kita selesai. Jika item yang kita cari kurang
dari item pada simpul akar, kita harus mencari ke sebelah kiri pohon -- pohon sebelah kanan bisa
diabaikan karena isinya hanya item yang lebih besar dari simpul akarnya. Demikian juga jika
item yang kita cari lebih besar dari item pada simpul akar, maka kita akan mencari di sebelah
kanan pohon. Untuk semua kasus, kita bisa menggunakan prosedur yang sama di setiap cabang
pohon.

Bagaimana dengan memasukkan item baru ke dalam pohon. Mula-mula cari di posisi mana item
tersebut akan dimasukkan. Jika posisinya ditemukan, buat simpul baru dan tempelkan simpul
baru di tempat tersebut.

Pencarian dan penyisipan item adalah operasi yang efisien pada pohon pencarian biner, asalkan
pohon tersebut berada dalam kondisi seimbang (balanced). Suatu pohon biner berada dalam
kondisi seimbang jika jumlah simpul pada cabang kanan sama dengan jumlah simpul pada
cabang kiri. Tidak semua pohon biner akan menjadi pohon seimbang, akan tetapi jika pohon ini
dibuat secara acak, besar kemungkinan pohon tersebut akan menjadi seimbang.

Dalam pencarian dalam pohon pencarian biner, setiap pengujian yang kita lakukan akan
membuang sebagian cabang pohon. Jika pohon tersebut dalam keadaan seimbang, maka akan
semakin banyak elemen yang kita buang, dan dengan demikian pencarian akan dilakukan dengan
lebih cepat. Ini mirip sekali dengan algoritma pencarian biner pada bagian sebelumnya.

Mari kita lihat bagaimana mengimplementasikan pohon pencarian biner.

Simpul pada pohon biner diekspresikan dalam kelas SimpulPohon berikut ini, beserta
konstruktor untuk membuat simpul baru lebih mudah.

class SimpulPohon {
// Objek SimpulPohon adalah satu simpul pada
// pohon biner string
 
String item; // Data pada simpul ini
SimpulPohon kiri; // Pointer ke cabang kiri
SimpulPohon kanan; // Pointer ke cabang kanan
 
SimpulPohon(String str) {
// Konstruktor. Membuat simpul berisi str
item = str;
}
} // akhir kelas SimpulPohon
Variabel statik dengan tipe SimpulPohon menunjuk pada pohon pencarian biner:

// Pointer ke simpul akar pohon


// Ketika pohon kosong, akar berisi null
static SimpulPohon akar;

Subrutin rekursif bernama pohonBerisi digunakan untuk mencari item di dalam pohon. Subruin
berikut melakukan pencarian pada pohon biner seperti didiskusikan di atas.

static boolean pohonBerisi( SimpulPohon simpul, String item ) {


// Kembalikan true jika item ditemukan dalam pohon
if ( simpul == null ) {
// Pohon kosong, jadi sudah pasti tidak ada item ini
// di dalamnya
return false;
}
else if ( item.equals(simpul.item) ) {
// Item ini ditemukan di simpul akar
return true;
}
else if ( item.compareTo(simpul.item) < 0 ) {
// Jika item lebih kecil dari simpul, maka mungkin ada di
// cabang kiri pohon. Kembalikan hasil pencarian di
// cabang kiri pohon
return pohonBerisi( simpul.kiri, item );
}
else {
// Jika item sama atau lebih besar dari simpul, maka
// mungkin ada di cabang kanan pohon. Kembalikan hasil
// pencarian di cabang kanan pohon
return pohonBerisi( simpul.kanan, item );
}
} // akhir pohonBerisi()

Ketika subrutin ini dipanggil, parameter pertama adalah variabel anggota statik akar yang
menunjuk pada akar seluruh pohonh pencarian biner.

Perlu dicatat bahwa rekursi bukan sesuatu yang penting dalam mengimplementasikan subrutin
ini. Algoritma pohon pencarian biner yang tidak rekursif mengikuti aturan berikut : Turun ke
bawah hingga kita menemukan item atau hingga mencapai null. Kita bisa menggunakan
perulangan while, sehingga implementasinya menjadi :

static boolean pohonBerisiNR( SimpulPohon akar, String item ) {


// Kembalikan true jika item ada di dalam pohon biner.
SimpulPohon pointer; // Pointer untuk menelusuri pohon
pointer = akar; // Mulai di akar simpul
while (true) {
if (pointer == null) {
// Kita sudah sampai pada akhir pohon, dan item belum
// ditemukan
return false;
}
else if ( item.equals(pointer.item) ) {
// Kita sudah menemukan item
return true;
}
else if ( item.compareTo(pointer.item) < 0 ) {
// Jika item lebih kecil, kemungkinan ada di cabang kiri
// Teruskan penelusuran di cabang kiri pohon
pointer = pointer.kiri;
}
else {
// Jika item lebih besar, kemungkinan ada di cabang kanan
// Teruskan penelusuran di cabang kanan pohon
pointer = pointer.kanan;
}
} // akhir while
} // akhir pohonBerisiNR();

Subrutin untuk menyisipkan item baru ke dalam pohon mirip dengan rutin pencari non-rekursif
di atas. Selain itu rutin penyisipan harus bisa menguji apakah pohon kosong atau tidak. Jika
pohon kosong, maka akar menunjuk pada simpul baru.

akar = new simpulPohon( itemBaru );

Akan tetapi, berarti akar tidak bisa diberikan sebagai parameter subrutin, karena kita tidak bisa
mengubah nilai yang disimpan dalam parameter aktual. (Ini bisa dilakukan dalam bahasa
pemrograman lain). Ada cari lainnya, akan tetapi cara lebih mudah adalah menggunakan rutin
penyisipan non-rekursif yang mengakses variabel anggota akar secara langsung.

Perbedaan antara mencari dan menyisipkan item adalah kita harus berhati-hati untuk tidak jatuh
dari pohon. ARtinya, kita harus selesai melakukan pencarian sebelum pointer bernilai null
karena mencapai akhir pohon. Jika kita sampai pada tempat kosong, di situlah kita menempatkan
simpul baru kita.

static void sisipPohon(String itemBaru) {


// Tambahkan item ke dalam pohon pencarian biner, di mana
// variabel "akar" berisi. (Catatan kita tidak bisa menggunakan
// akar sebagai parameter, karena kita harus mengubah isi
// variabel ini.)
if ( akar == null ) {
// Jika pohon kosong, set akar ke simpul baru
// yang berisi itemBaru
akar = new SimpulPohon( itemBaru );
return;
}
SimpulPohon pointer; // Untuk menelusuri pohon
pointer = akar; // Mulai dari akar
while (true) {
if ( newItem.compareTo(pointer.item) < 0 ) {
// Karena itemBaru kurang dari item dalam pohon
// maka ia harus berada di cabang kiri pohon.
// Jika ada ruang kosong di pointer.kiri maka simpul baru
// bisa ditambah di sini. Jika tidak turun satu tingkat lagi ke
kiri
if ( pointer.kiri == null ) {
pointer.kiri = new SimpulPohon( itemBaru );
return; // itemBaru sudah ditambahkan ke dalam pohon
}
else
pointer = pointer.kiri;
}
else {
// Karena itemBaru lebih besar dari item dalam pohon
// maka ia harus berada di cabang kanan pohon.
// Jika ada ruang kosong di pointer.kanan maka simpul baru
// bisa ditambah di sini. Jika tidak turun satu tingkat lagi ke
kanan
if ( pointer.kanan == null ) {
pointer.kanan = new SimpulPohon( itemBaru );
return; // itemBaru sudah ditambahkan ke dalam pohon
}
else
pointer = pointer.kanan;
}
} // akhir while
} // akhir sisipPohon()

Bab IX - Pemrograman Generik dan Kelas Koleksi


Posted Min, 03/29/2009 - 22:29 by belajarprogram

Versi ramah cetak

Bagaimana caranya menghindari "reinventing the wheel", atau membuat kembali sesuatu yang
sudah ditemukan? Banyak struktur data dan algoritma, seperti yang sudah dibahas pada bab
sebelumnya telah dipelajari, diprogram, dan diprogram ulang oleh mahasiswa ilmu komputer
dalam beberapa generasi. Ini adalah kesempatan belajar yang sangat baik.

Sayangnya, algoritma dan data stuktur ini juga diprogram dan diprogram ulang oleh profesional
komputer. Mereka menghabiskan waktu yang tidak perlu untuk memrogram ulang sesuatu yang
sudah ada, bukannya membuat sesuatu yang lebih inovatif dan kreatif.

Programmer yang perlu menggunakan list atau pohon biner, seharusnya tidak perlu lagi
membuat data struktur ini dari awal. Struktur data ini sudah banyak dimengerti dan diprogram
ribuan kali sebelumnya. Masalahnya adalah bagaimana agar struktur data yang tangguh tersedia
dan siap digunakan oleh programmer. Di bagian ini kita akan melihat bagaimana Java
menyelesaikan masalah ini.

 Pemrograman Generik
 Pemrograman Generik pada Java
 List
 Set (Himpunan)
 Kelas Map
 Tabel Hash
Pemrograman Generik
Posted Min, 03/29/2009 - 22:43 by belajarprogram

Versi ramah cetak

Pemrograman generik adalah penulisan kode yang bisa digunakan oleh berbagai macam tipe
data. Kita telah menemukan istilahnya pada bagian sebelumnya tentang array dinamis integer.
Kode yang ditulis di sana untuk array dinamis integer hanya bisa bekerja untuk tipe data int.
Akan tetapi kode array dinamis untuk double, String, atau tipe data lainnya hampir sama. Akan
sangat tidak nyaman apabila kita harus mengkopi kodenya berulang-ulang untuk tipe data yang
berbeda-beda.

Seperti disebutkan sebelumnya, Java mencoba menyelesaikan masalah ini dengan membuat
kelas ArrayList. Kelas ini pada dasarnya merupakan array dinamis dengan tipe Object. Karena
semua kelas merupakan kelas turunan dari Object, maka objek yang bertipe kelas apapun bisa
disimpan dalam ArrayList.

Ini adalah contoh pemrograman generik : kode untuk kelas ArrayList cukup ditulis satu kali,
tetapi bisa digunakan untuk objek dengan tipe data yang berbeda-beda (akan tetapi, tidak bisa
digunakan untuk tipe data primitif, seperti int atau double.)

Kelas ArrayList hanyalah satu dari beberapa kelas dan interface yang merupakan pemrograman
generik pada Java. Kita akan lihat beberapa kelas lain dan bagaimana kelas-kelas ini digunakan.
Semua kelas yang didiskusikan pada bagian ini merupakan bagian dari paket java.util dan kita
perlu menambahkan pernyataan import di awal program untuk bisa menggunakannya. (Sebelum
kita menggunakan perintah import java.util.*; di semua program, kita harus tahu bahwa
beberapa kelas di dalam java.util memiliki nama yang sama pada pake lain. Misalnya,
java.util.List dan java.awt.List adalah kelas yang bernama sama dengan paket yang
berbeda).

Adalah sesuatu hal yang tidak mudah untuk mendesain pustaka untuk pemrograman generik.
Solusi yang disediakan Java memiliki banyak fitur bagus, akan tetapi bukan berarti cara ini
adalah cara satu-satunya. Sudah pasti bukan yang terbaik, akan tetapi dalam konteks desain Java
secara keseluruhan, mungkin lebih cocok disebut optimal. Untuk dapat memberikan gambaran
seperti apa pemrograman generik secara umum, mungkin akan lebih baik untuk melihat sekilas
pemrograman generik di bahasa pemrograman lain.

Pemrograman Generik pada Bahasa Pemrograman Lain


Posted Sen, 03/30/2009 - 21:23 by belajarprogram

Versi ramah cetak

Pemrograman Generik pada Smalltalk


Smalltalk adalah salah satu bahasa pemrograman berorientasi objek pertama. Bahasa ini masih
digunakan hingga kini. Meskipun tidak menjadi sepopuler Java atau C++, bahasa ini adalah
sumber ide yang diadopsi banyak bahasa pemrograman. Pada Smalltalk, pada dasarnya semua
pemorgraman adalah generik, karena dua sifat bahasa ini.

Pertama, variabel pada Smalltalk tidak memiliki tipe. Suatu nilai memiliki tipe, seperti integer
atau string, tetapi variabel tidak memiliki nilai. Suatu variabel bisa menampung jenis data apa
saja. Parameter juga tidak memiliki tipe, sehingga subrutin bisa digunakan pada parameter apa
saja. Demikian juga dengan struktur data bisa menampung data apa saja. Misalnya, sekali kita
mendefinisikan struktur data pohon biner pada Smalltalk, kita bisa menggunakannya untuk
integer, string, tanggal, atau data apa saja. Kita tidak perlu menulis kode baru untuk masing-
masing tipe data.

Kedua, semua nilai adalah objek, dan semua operasi pada objek dilakukan dengan metode dalam
kelas. Hal ini juga berlaku bahkan untuk tipe data primitif seperti integer. Ketika operator "+"
digunakan untuk menjumlah integer, operasi ini dilakukan dengan memanggil metode pada kelas
integer. Ketika kita membuat kelas baru, kita bisa membuat operator "+" sendiri kemudian kita
bisa menjumlahkan dua objek dengan tipe kelas tersebut dengan menggunakan "a + b" seperti
kita menjumlahkan angka seperti biasa.

Sekarang misalnya kita membuat subrutin baru yang menggunakan operator "+" untuk
menjumlahkan masing-masing item di dalam list. Subtuin ini bisa digunakan untuk list integer,
tapi juga bisa digunakan ke tipe data apapun yang mendefinisikan "+". Demikian juga dengan
subrutin yang menggunakan operator "<" untuk mengurutkan list juga bisa digunakan untuk list
yang mengandung tipe data apapun yang memiliki definisi "<". Kita tidak perlu menulis subrutin
pengurutan untuk masing-masing tipe data.

Jika kedua fitur ini kita gabungkan, kita bisa memiliki bahasa di mana struktur data dan
algoritmanya akan bekerja untuk jenis tipe data apapun (yang masuk akal), yaitu jika operasi
yang sesuai telah didefinisikan. Inilah yang merupakan pemrograman generik yang
sesungguhnya.

Mungkin ini terdengar sangat baik, dan Anda mungkin bertanya-tanya kenapa tidak semua
bahasa pemrograman bekerja seperti ini. Kebebasan pemrograman seperti ini akan memudahkan
kita membuat program, akan tetapi akan lebih sulit untuk membuat program yang benar dan
tangguh.

Sekali kita membuat struktur data yang bisa menampung tipe data apa saja, akan sulit untuk
menjamin ia bisa menampung tipe data yang kita inginkan. Jika kita ingin suatu subrutin
mengurutkan tipe data apapun, maka akan sangat sulit untuk menjamin bahwa subrutin ini hanya
digunakan untuk data di mana operator "<" telah didefinisikan. Lebih khusus, kompiler tidak
bisa memastikannya. Masalah ini akan muncul di saat program dijalankan ketika kita mencoba
untuk menjalankan operasi tertentu pada suatu tipe data yang belum ada, kemudian program
akan crash.

Pemrograman Generik pada C++


Tidak seperti Smalltalk, C++ adalah bahasa pemrograman dengan tipe kuat, bahkan lebih kuat
dari Java. Setiap variabel memiliki tipe, dan hanya bisa menampung tipe data itu saja. Artinya
pemrograman generik seperti pada Smalltalk tidak mungkin diterapkan.

Lebih Jauh, C++ tidak memiliki sesuatu yang mirip dengan kelas Object pada Java. Artinya,
tidak ada kelas yang merupakan kelas super dari semua kelas. Artinya C++ tidak bisa
menggunakan pemrograman generik seperti Java.

Akan tetapi, C++ memiliki sistem pemrograman geneik yang canggih dan fleksibel, yaitu yang
disebut template. Dalam C++, kita tidak membuat subrutin pengurutan yang berbeda untuk
setiap tipe data. Akan tetapi kita bisa mmebuat template subrutin. Template ini bukan subrutin;
akan tetapi mirip seperti pabrik pembuat subrutin. Kita lihat contoh berikutnya, karena sintaks
C++ mirip dengan Java :

template<class TipeItem>
void urut( TipeItem A[], int banyak ) {
// Urut banyak item dalam array A, ke dalam urutan menaik
// Algoritma yang digunakan adalah pengurutan pilihan
for (int i = banyak-1; i > 0; i--) {
int posisi_maks = 0;
for (int j = 1; j <= banyak; j++)
if ( A[j] > A[posisi_maks] )
posisi_maks = j;
TipeItem temp = A[banyak];
A[banyak] = A[posisi_maks];
A[posisi_maks] = temp;
}
}

Dalam kode di atas, kita mendefinisikan template subrutin. Jika kita menghapus baris pertama,
yaitu template<class TipeItem>", dan mengganti kata "TipeItem" dengan "int", pada semua
isi template, maka kita bisa mendapatkan subrutin untuk mengurut array int. (Meskipun kita tulis
seperti "class TipeItem", kita bisa menggantinya dengan tipe apapun, termasuk tipe primitif).
Jika kita mengganti "TipeItem" dengan string, maka kita bisa mendapatkan subrutin untuk
mengurut array string. Ini yang sebenarnya dilakukan oleh compiler.

Jika program kita menyebut "urut(list,10)" di mana list adalah array int, maka kompiler
menggunakan template ini untuk membuat subrutin untuk mengurut array int. Jika kita sebut
"urut(kartu,10)" di mana kartu adalah array objek bertipe Kartu, maka kompiler akan
membuat subrutin untuk mengurutkan array Kartu.

Template di atas menggunakan operator ">" untuk membandingkan nilai. Jika operator ini
didefinisikan untuk nilai bertipe Kartu, maka kompiler akan menggunakan template dengan
sukses. Jika ">" tidak didefinisikan untuk kelas Kartu, maka kompiler akan gagal, akan tetapi ini
akan terjadi pada saat program dikompilasi bukan seperi Smalltalk di mana program akan crash
pada saat dijalankan.

C++ juga memiliki template untuk membuat kelas. Jika kita menulis template untuk pohon biner,
kita bisa menggunakan template itu untuk membuat kelas pohon biner int, pohon biner string,
pohon biner tanggal, dan seterusnya -- semua dari satu template. Versi paling baru C++ memiliki
template bawaan yang cukup komplit yang disebut dengan Pustaka Template Standar (Standard
Template Library atau STL). STL sendiri cukup kompleks, dan bahkan beberapa orang
mengatakan sangat amat kompleks. Akan tetapi ini juga fitur paling menarik dari C++
.

Pemrograman Generik pada Java


Posted Sen, 03/30/2009 - 22:13 by belajarprogram

Versi ramah cetak

Seperti pada C++, Java adalah bahasa bertipe kuat. Akan tetapi, pemrograman generik pada Java
lebih dekat dengan Smalltalk daripada C++. Seperti telah dijelaskan sebelumnya, pemrograman
generik pada Java berdasarkan pada kelas Object yang merupakan kelas super dari semua kelas.
Hingga tingkat tertentu, ini membuat Java mirip dengan Smalltalk : Struktur data yang didesain
untuk menampung Object bisa digunakan untuk menyimpan data kelas apapun. Kita tidak perlu
membuat template atau fitur pada bahasa pemrograman lain untuk mendukung pemrograman
generik.

Tentunya, tipe primitif, seperti integer, bukan objek pada Java, dan karenanya tidak bisa
disimpan dalam tipe data generik. Dan sebenarnya, tidak ada cara untuk melakukan
pemrograman generik dengan tipe data primitif pada Java. Pendekatan Smalltalk tidak bisa
diterapkan pada Java kecuali untuk objek, dan pendekatan C++ tidak tersedia pada Java.

Lebih jauh, subrutin generik lebih bermasalah pada Java daripada Smalltalk atau C++. Pada
Smalltak, subrutin dapat dipanggil dengan parameter bertipe apapun, dan akan bekerja asalkan
operator yang digunakan pada subrutin didefinisikan pada parameternya.

Pada Java, parameter suatu subrutin harus bertipe tertentu. Dan subrutin hanya bisa
menggunakan operasi untuk tipe itu saja. Subrutin dengan parameter Object bisa digunakan
untuk objek tipe apa saja, akan tetapi subrutin hanya bisa menggunakan operasi pada kelas
Object saja, dan sebenarnya hanya sedikit operasi pada kelas Object! Misalnya tidak ada
operasi pembanding pada kelas Object, jadi kita tidak bisa membuat algoritma pengurutan
generik. Kita akan lihat bagaimana Java menyelesaikan masalah ini.

Karena masalah seperti ini, beberapa orang menyatakan bahwa Java tidak mendukung
pemrograman generik secara keseluruhan. Beberapa orang lain tidak setuju. Akan tetapi, tetap
saja ini tidak menghambat Java untuk digunakan secara luas.

 Koleksi dan Map


 Algoritma Generik
 Iterator
 Kesamaan dan Perbandingan
 Kelas Pembungkus
Koleksi dan Map
Posted Sen, 03/30/2009 - 22:15 by belajarprogram

Versi ramah cetak

Struktur data generik pada Java dapat dibagi menjadi dua kategori : koleksi dan map. Koleksi
kurang lebih mirip seperti kumpulan objek-objek. Map menghubungkan objek di satu kumpulan
dan objek di kumpulan lain seperti kamus yang menghubungkan definisi dengan kata atau buku
telepon menghubungkan nama dan nomor telepon. Map mirip dengan apa yang kita sebut "list
asosiasi" pada bagian sebelumnya.

Ada dua jenis koleksi : list dan himpunan (set). List adalah kumpulan objek di mana item-
itemnya diatur secara berurutan. List memiliki item pertama, item kedua, dan seterusnya. Untuk
item di dalam list, kecuali item terakhir, akan ada item yang ada di belakangnya.

Himpunan (set) adalah kumpulan objek di mana hanya ada satu objek yang bisa ada di dalam
suatu himpunan.

Lihat bahwa istilah "koleksi", "list", "himpunan", dan "map" tidak menyatakan bagaimana data
disimpan. List bisa diimplementasikan dalam bentuk array, list berantai, atau map yang
menghubungkan elemen list dengan angka 0, 1, 2, ....

Sebetulnya istilah-istilah ini dibuat pada Java bukan dalam bentuk kelas tapi dalam bentuk
interface. Interface Collection, List, Set dan Map mendefinisikan operasi dasar dari struktur
data tersebut, tapi tidak menjelaskan bagaimana struktur data dan operasinya diimplementasikan.

Struktur data dan operasinya akan ditulis pada kelas yang mengimplementasikan interface
tersebut. Bahkan ketika kita menggunakan kelas tersebut, kita mungkin tidak tahu bagaimana
kelas tersebut diimplementasikan, kecuali kita melihat langsung pada kode sumbernya. Struktur
data generik pada Java adalah tipe data abstrak (abstract data type). Mereka memiliki definisi
operasi yang bisa dilakukan, dan bukan bagaimana data diatur dalam memori komputer.

Kita akan lihat kelas list, set dan map pada bagian berikut. Tapi sebelum kita sampai pada bagian
itu, kita akan melihat dahulu beberapa konsep tentang operasi umum yang tersedia pada semua
koleksi.

Algoritma Generik
Posted Sen, 03/30/2009 - 22:21 by belajarprogram

Versi ramah cetak

Interface Collection memiliki metode untuk melakukan beberapa operasi dasar pada koleksi.
Karena "koleksi" adalah konsep yang sangat umum, maka operasi yang bisa dilakukan oleh
semua koleksi juga sesuatu yang sangat umum. Misalnyakol adalah objek yang
mengimplementasi interface Collection. Berikut ini adalah operasi yang bisa dilakukan.
 kol.size() -- mengembalikan int yang berisi banyaknya objek dalam suatu koleksi
 kol.isEmpty() -- mengembalikan boolean true jika koleksi kosong, atau ukurannya sama dengan
0
 kol.clear() -- menghapus semua objek dalam koleksi
 kol.contains(objek) -- mengembalikan nilai boolean jika objek ada dalam koleksi
 kol.add(objek) -- menambah objek ke dalam koleksi. Parameternya bisa berupa Object apa
saja. Beberapa koleksi bisa berisi nilai null, sementara yang lain tidak. Misalnya menambahkan
objek ke dalam Set tidak berpengaruh apa-apa jika objek tersebut sudah ada di dalamnya.
 kol.remove(objek) -- membuang objek dari dalam koleksi, jika ada, dan mengembalikan nilai
boolean yang menyatakan apakah objek tersebut ada atau tidak di dalam koleksi
 kol.containsAll(kol2) -- mengembalikan nilai boolean jika semua objek dalam kol2 ada di dalam
koleksi kol. Parameternya bisa berupa Collection apa saja.
 kol.addAll(col2) -- menambahkan semua objek yang ada dalam koleksi kol2 ke dalam kol
 kol.removeAll(kol2) -- menghapus semua objek di kol yang ada pada kol2
 kol.retainAll(kol2) -- menghapus semua objek pada kol yang tidak ada pada kol2. Hanya akan
mempertahankan objek yang ada pada kol2
 kol.toArray() -- mengembalikan array bertipe Object[] yang isinya semua item di dalam
koleksi. Nilai yang dikembalikan bisa di-tipe cast ke dalam tipe array lain, jika perlu. Misalnya,
jika kita tahu bahwa semua item di dalam kol bertipe String, maka
(String[])kol.toArray() akan mengembalikan array String yang berisi semua string di
dalam koleksi.

Karena semua metode adalah turunan dari interface Collection, maka metode ini harus
didefinisikan pada semua objek yang mengimplementasikan interface ini. Akan tetapi ada
masalah yang timbul. Misalnya ukuran suatu Collection tidak bisa diganti setelah dibuat.
Metode yang menambah atau membuang objek tidak bisa digunakan untuk koleksi jenis ini.
Meskipun mungkin legal untuk memanggil metode ini, pengecualian akan dilemparkan ketika
program dijalankan. Jenis pengecualiannya bernama UnsupportedOperationException.

Ada juga masalah efisiensi. Meskipun suatu operasi didefinisikan untuk beberapa jenis koleksi,
tentunya unjuk kerjanya tidak sama untuk semua kelas. Bahkan untuk metode sesederhana
size() bisa sangat berbeda dari satu jenis koleksi ke jenis koleksi lainnya.

Untuk beberapa jenis koleksi, waktu pengolahan sebanding dengan jumlah item di dalam
koleksi. Koleksi lain mungkin memiliki variabel instansi yang melacak jumlah item di dalam
koleksi, sehingga menjalankan size() sama dengan mengambil nilai variabel instansi ini.
Artinya operasinya hanya dilakukan satu langkah saja, tidak peduli berapa banyak item yang ada
di dalam koleksi.

Ketika kita menggunakan koleksi, alangkah lebih baiknya untuk mengetahui seberapa efisien
suatu operasi dilakukan untuk jenis koleksi tertentu. Kita harus bisa memilih koleksi yang cocok
untuk masalah yang kita hadapi. Kita akan lihat lebih detail di bagian berikutnya.

Iterator
Posted Sen, 03/30/2009 - 22:25 by belajarprogram
Versi ramah cetak

Interface Collection mendefinisikan beberapa algoritma generik, akan tetapi mungkin kita
ingin membuat algoritma generik kita sendiri. Misalnya kita ingin membuat suatu subrutin yang
mencetak setiap item di dalam koleksi. Untuk bisa melakukan ini secara generik, kita harus
mencari akal bagaimana caranya untuk mengakses setiap item satu per satu.

Kita telah lihat sebelumnya bagaimana caranya untuk data struktur tertentu : Misalnya untuk
array, kita bisa menggunakan perulangan for dari item pertama hingga terakhir. Untuk list
berantai, kita bisa menggunakan perulangan while dari item pertama hingga kita menemukan
null. Untuk pohon biner kita bisa menggunakan subrutin rekursif dengan penelusuran infix.

Koleksi bisa dibuat dalam berbagai bentuk. Dengan keragaman bentuk ini dan bermacam-macam
cara untuk menelusurinya, bagaimana kita bisa membuat metode generik yang berlaku untuk
semua kenis koleksi? Masalah ini bisa diselesaikan dengan iterator.

Iterator adalah objek yang digunakan untuk menelusuri koleksi. Koleksi dengan jenis yang
berbeda memiliki jenis iterator yang berbeda pula, akan tetapi semua iterator digunakan dengan
cara yang sama. Algoritma yang menggunakan iterator untuk menelusuri koleksi bisa dibuat
generik, karena teknik yang sama bisa digunakan untuk beragam jenis koleksi.

Konsep iterator mungkin agak aneh untuk seseorang yang baru menemui konsep pemrgoraman
generik, akan tetapi Anda harus mengerti bahwa konsep ini bisa digunakan untuk menyelesaikan
masalah sulit dengan cara yang anggun.

Interface Collection memiliki metode yang bisa digunakan untuk mengambil iterator dalam
koleksi apapun. Jika kol adalah suatu koleksi, maka kol.iterator() mengembalikan iterator
yang bisa digunakan untuk menelusuri koleksi tersebut.

Bayangkan iterator seperti pointer generik yang dimulai dari awal koleksi dan bisa berpindah
dari satu item ke item lain. Iterator didefinisikan oleh interface yang bernama Iterator.
Interface ini hanya memiliki 3 metode. Jika iter merupakan variabel bertipe Iterator, maka :

 iter.next() -- mengembalikan item berikutnya, dan memindahkan iterator ke item


berikutnya. Nilai keluarannya bertipe Object. Ingat bahwa kita tidak bisa melihat suatu item
tanpa memindahkan iterator ke item berikutnya. Jika metode ini dipanggil apabila tidak ada
item lagi yang tersisa, ia akan melempar NoSuchElementException.
 iter.hasNext() -- mengembalikan nilai boolean yang memberi tahu apakah ada item
berikutnya yang bisa diproses. Kita harus mengetesnya sebelum memanggil iter.next()
 iter.remove() -- jika kita gunakan perintah ini setelah memanggil iter.next(), maka ia
akan menghapus item yang baru saja kita lihat. Akan melempar pengecualian
UnsupportedOperationException jika koleksi tidak bisa menghapus item.

Dengan menggunakan iterator, kita bisa menulis kode untuk mencetak semua item dalam koleksi
apapun. Misalnya kol bertipe Collection. Maka kita bisa menggunakan :
Iterator iter = kol.iterator();
while ( iter.hasNext() ) {
Object item = iter.next();
System.out.println(item);
}

Bentuk yang sama bisa digunakan untuk pemrosesan jenis apapun. Misalnya, subrutin berikut ini
akan menghapus semua nilai null dari koleksi apapun (selama koleksi itu mengizinkan
penghapusan elemen) :

void removeNullValues( Collection coll ) {


Iterator iter = kol.iterator():
while ( iter.hasNext() ) {
Object item = iter.next();
if (item == null)
iter.remove();
}
}

Koleksi bisa menampung objek tipe apa saja, sehingga nilai keluaran iter.next() bertipe
Object. Sekarang, tidak ada yang bisa kita lakukan dengan variabel bertipe Object. Dalam
situasi praktis, koleksi digunakan untuk menyimpan objek yang bertipe kelas tertentu, kemudian
objek dari koleksi itu di-tipe cast ke kelas tersebut sebelum digunakan.

Misalnya, kita menggunakan kelas BentukGeometri. Misalnya kelas ini memiliki metode
gambar() untuk menggambar suatu gambar. Maka kita bisa membuat metode generik untuk
menggambar semua gambar dalam koleksi BentukGeometri seperti :

void gambarSemuaGambar( Collection koleksiGambar ) {


// Kondisi Awal: Semua item dalam koleksiGambar tidak berisi null
// dan bertipe kelas BentukGeometri
Iterator iter = koleksiGambar.iterator();
while ( iter.hasNext() ) {
BentukGeometri gbr = (BentukGeometri)iter.next();
gbr.gambar();
}
}

Kondisi awal dari metode tersebut menyatakan bahwa metode tersebut akan gagal apabila item
di dalam koleksi tidak bertipe BentukGeometri. Jika item ini ditemukan, maka tipe-cast
"(BentukGeometri)iter.next()" akan melempar pengecualian ClassCastException.

Meskipun dalam Java kita tidak bisa memiliki "Koleksi Bentuk Geometri", dan hanya bisa
memiliki "Koleksi Object", dalam prakteknya ini bukan masalah besar. Jika hanya perlu ingat
objek jenis apa yang kita simpan dalam koleksi kita.

Kesamaan dan Perbandingan


Posted Kam, 04/02/2009 - 22:38 by belajarprogram
Versi ramah cetak

Diskusi kita tentang metode pada interface Collection sebelumnya mengasumsikan bahwa dua
objek dianggap "sama". Misalnya metode kol.contains(objek) dan kol.remove(objek)
mencari item dalam koleksi yang sama dengan objek. Akan tetapi, kesamaan bukan sesuatu
yang mudah.

Teknik yang paling umum untuk menguji kesamaan (yaitu menggunakan operator ==) sering
kali tidak bisa digunakan untuk objek. Operator == yang digunakan pada objek hanya
membandingkan apakah objek tersebut memiliki alamat memori yang sama. Biasanya, kita ingin
supaya kesamaan berarti isi objeknya sama (bukan alamat memorinya).

Dua nilai String dianggap sama jika keduanya memiliki urutan karakter yang sama. Persoalan
di mana karakter tersebut disimpan di dalam memori tentunya tidak relevan. Dua nilai bertipe
Date dianggap sama jika isinya adalah waktu yang sama.

Kelas Object memiliki metode bernilai boolean yaitu equals(Object) untuk menguji apakah
satu objek berisi sama dengan objek lain.

Di dalam koleksi, dua objek obj1 dan obj2 dianggap sama jika keduanya bernilai null atau jika
keduanya bernilai tidak nul dan obj1.equals(obj2) bernilai true.

Dalam kelas Object, obj1.equals(obj2) didefinisikan sebagai obj1 == obj2. Akan tetapi
pada hampir semua kelas turunan Object, definisi ini tidak masuk akal, dan biasanya
dibebanlebihkan (overload).

Kelas String misalnya, membebanlebihkan equals() sehingga untuk str.equals(obj)


bernilai sama jika urutan karakter obj sama dengan urutan karakter str.

Jika kita menulis kelas sendiri, kita mungkin ingin mendefinisikan metode equals() sendiri
pada kelas tersebut, sehingga metode kesamaan bisa berjalan sesuai dengan yang kita inginkan.
Misalnya kelas Kartu akan bekerja dengan benar jika digunakan dalam koleksi bisa dibuat
seperti :

public class Kartu { // Kelas untuk kartu mainan


int lambang; // Nomor 0 hingga 3 untuk lambangnya :
// wajik, diamon, keriting atau hati.
int angka; // Angka 1 hingga 13
 
public boolean equals(Object obj) {
if (obj == null || ! (obj instanceof Kartu) ) {
// obj tidak sama dengan Kartu ini jika obj
// tidak bertipe Kartu, atau isinya null
return false;
}
else {
Kartu lain = (Kartu)obj; // Type-cast obj ke Kartu
if (lambang == lain.lambang && angka == lain.angka) {
// Kartu lain berlambang dan berangka sama dengan
// kartu ini, artinya kedua kartu sama
return true;
}
else
return false;
}
}
... // metode dan konstruktor lain
}

Tanpa metode equals() dalam kelas ini, metode contains() dan remove() dalam interface
Collection tidak akan bekerja dengan baik untuk kelas Kartu.

Masalah yang sama akan muncul ketika item dalam koleksi akan diurutkan. Pengurutan artinya
mengatur urutan item dalam aturan tertentu. Masalahnya, tidak ada aturan "menaik" dalam objek.
Sebelum objek bisa diurutkan, metode tertentu harus dibuat untuk membandingkan objek. Objek
yang akan dibandingkan harus mengimplementasikan interface java.lang.Comparable.
Interface ini mendefinisikan satu metode, yaitu :

public int compareTo(Object obj)

Nilai yang dikembalikan obj1.compareTo(obj2) bernilai nol jika kedua objek berisi sama (atau
jika obj1.equals(obj2) bernilai benar). Keluarannya bernilai negatif jika obj1 lebih kecil dari
obj2, atau jika diurutkan dalam urutan menaik obj1 akan muncul sebelum obj2. Keluarannya
bernilai positif jika obj1 lebih besar dari obj2 atau jika diurutkan dalam urutan menaik obj1
muncul setelah obj2.

Kelas String mengimplementasikan interface Comparable dan memiliki metode compareTo


dengan cara seperti di atas. Jika kita ingin membuat kelas sendiri dan ingin mengurut objek pada
kelas itu, kita juga harus mengimplementasikan objek itu dengan cara yang sama. Misalnya :

class NamaLengkap implements Comparable {


// Melambangkan nama lengkap yang terdiri dari
// nama depan dan nama belakang
String namaDepan, namaBelakang;
 
public boolean equals(Object obj) {
if (obj == null || ! (obj instanceof NamaLengkap)) {
return false;
}
else {
NamaLengkap lain = (NamaLengkap)obj;
return namaDepan.equals(lain.namaDepan)
&& namaBelakang.equals(lain.namaBelakang);
}
}
 
public void compareTo(Object obj) {
NamaLengkap lain = (NamaLengkap)obj;
// Menyebabkan error jika obj tidak bertipe NamaLengkap
if ( namaBelakang.compareTo(lain.namaBelakang) < 0 ) {
// Jika namaBelakang lebih kecil dari namaBelakang objek lain
// maka NamaLengkap ini muncul sebelum yang lain
// Kembalikan nilai negatif
return -1;
}
if ( namaBelakang.compareTo(lain.namaBelakang) > 0 ) {
// Jika namaBelakang lebih besar dari namaBelakang objek lain
// maka NamaLengkap ini muncul setelah yang lain
// Kembalikan nilai positif
return 1;
}
else {
// Nama belakangnya sama, sekarang bandingkan
// nama depannya
return namaDepan.compareTo(lain.namaDepan);
}
}
... // metode dan konstruktor lain
}

Ada cara lain untuk membandingkan objek pada Java, yaitu dengan membuat objek lain untuk
melakukan perbandingan. Objek tersebut harus mengimplementasikan java.util.Comparator
yang memiliki metode :

public int compare(Object obj1, Object obj2)

Metode ini membandingkan dua objek dan mengembalikan nilai negatif, nol, atau positif,
tergantung apakah obj1 muncul lebih dulu, sama, atau setelah obj2. Komparator ini berfungsi
untuk membandingkan objek yang tidak memiliki interface Comparable atau untuk melakukan
metode pembanding yang berbeda untuk objek yang bertipe sama.

Kita akan lihat bagaimana Comparable dan Comparator digunakan dalam koleksi dan map.

‹Iterator ke atas Kelas Pembungkus›

 Kirim komentar

Komentar
error di perbandingan or
by chubi (tidak terverifikasi) - 06/22/2010 - 15:36

ka saya mo tanya sayakan lagi buat program penghitungan yah..

trus saya ketikkin coding

if (txtjumlah.getText()!=""||txtjumlah.getText()!="0"){
masa dia warning katanya disuruh pake string == or !=

emang operator perbandingan yang saya pake itu salah ya ka...

tolong bimbingannya

 balas

Kalau string gunakan metode


by belajarprogram - 08/04/2010 - 14:43

Kalau string gunakan metode equals untuk membandingkan.

Jadi kode di atas seharusnya

if (txtjumlah.getText().equals("") || txtjumlah.getText().equals("0")){ ... }

 balas

Tanya Eror
by Anonim (tidak terverifikasi) - 04/06/2009 - 10:18

Dear All just share aja , gw udh install java , trus udh gitu gw baru belajar java yg sangat
sederhana bgt
ini code nya :

public class Test {

public static void main(String[] args) {


System.out.println("Hello World!");
}

kira2 ada yg salah ga yah coding nya , coz gw udh bolak balik salah , trus ada keterangan eror
nya syntak eror di
System.out.println

Gimana yah cara nya bisa ngebetulin , padahal ini coding sederhana bgt

Tx yah buat perhatian nya ^_^

 balas

kayanya ga da yang salah deh


by Anonim (tidak terverifikasi) - 07/28/2010 - 12:49
kayanya ga da yang salah deh ma codingnya

bahkan 100% Sip ...

mungkin coding ini yang banyak Errornya :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.Timer;
import java.util.*;
import java.text.*;

public class menu extends JFrame implements ActionListener{


    private JDesktopPane desktop=new JDesktopPane(); //@deklarasi JDesktop
    private JMenuBar mBar=new JMenuBar(); //@deklarasi MenuBar
    private JLabel lbJam=new JLabel(); //@deklarasi Label untuk Jam pada JMenuBar
    private JMenu mMaster=new JMenu("File_Master"), //@deklarasi JMenu
            mPemesanan=new JMenu("Pemesanan_Barang"),
            mPenerimaan=new JMenu("Penerimaan_Barang"),
            mRetur=new JMenu("Retur_Pembelian"),
            mLaporan=new JMenu("Laporan"),
            mHelp=new JMenu("Help_?");
    private JMenuItem miBarang=new JMenuItem("Entry_Master_Barang"), //@deklarasi
JMenuItem
            miSuplier=new JMenuItem("Entry_Master_Suplier"),
            miPrice=new JMenuItem("Entry_Price_List"),
            miEPO=new JMenuItem("Entry_Purchase_Order"),
            miCPO=new JMenuItem("Cetak_Purchase_Order"),
            miETP=new JMenuItem("Entry_Tanda_Penerimaan"),
            miCTP=new JMenuItem("Cetak_Tanda_Penerimaan"),
            miERP=new JMenuItem("Entry_Retur_Pembelian"),
            miCRP=new JMenuItem("Cetak_Retur_Pembelian"),
            miDS=new JMenuItem("Daftar_Suplier"),
            miDPH=new JMenuItem("Daftar_Perbandingan_Harga"),
            miLPO=new JMenuItem("Laporan_Purchase_Order_(PO)"),
            miLPnB=new JMenuItem("Laporan_Penerimaan_Barang"),
            miLRP=new JMenuItem("Laporan_Retur_Pembelian"),
            miLPmB=new JMenuItem("Laporan_Pembelian_Barang"),
            miLAP=new JMenuItem("Laporan_Analisa_Pembelian"),
            miAbout=new JMenuItem("About"),
            miExit=new JMenuItem("Exit_Aplikasi");
           
    /** @jika ingin menambahkan ImageIcon pada JMenuItem=new JMenuItem("Data Obat",new
ImageIcon("path/image"));
     *
     * @mengambil tanggal aktif dari komputer & mengatur format tanggal
     */
    private Date tgl=new Date();
    private SimpleDateFormat sdf=new SimpleDateFormat("dd MMM
yyyy",Locale.getDefault());
    private String tanggal=sdf.format(tgl); //@untuk format tanggal
    //@deklarasi komponen panel & objek label untuk statusbar
    private JPanel stBar=new JPanel();
    private JLabel lb1=new JLabel(" "+"By.RadenMas RamaHandi",JLabel.LEFT),lb2=new
JLabel(" "+tanggal+" ",JLabel.RIGHT);
   
    /**
     * method menu() menggunakan constructor
     * String data ....
     */
    public menu(String data){
        super("Menu @Example");
        setSize(1020,650);
        setLocation((Toolkit.getDefaultToolkit().getScreenSize().width-getWidth())/2,
(Toolkit.getDefaultToolkit().getScreenSize().height-getHeight())/2);
        //@memberikan listener & mengeksekusi fungsi keluar saat toombol di klck
        addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent we){
                exit();
            }
        });
        //@mengatur tbl Alt pada menu fulldown
        mMaster.setMnemonic('F');
        mPemesanan.setMnemonic('P');
        mPenerimaan.setMnemonic('P');
        mRetur.setMnemonic('R');
        mLaporan.setMnemonic('L');
        mHelp.setMnemonic('H');
        //@mengatur penggunaan shortcut pada menu fulldown
       
miBarang.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B,Event.CTRL_MASK));
       
miSuplier.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,Event.CTRL_MASK));
        miPrice.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,Event.CTRL_MASK));
        miAbout.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,Event.CTRL_MASK));
        miExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E,Event.CTRL_MASK));
        //@mengatur menu fulldown agar dapat di click
        miBarang.addActionListener(this);
        miSuplier.addActionListener(this);
        miPrice.addActionListener(this);
        miEPO.addActionListener(this);
        miCPO.addActionListener(this);
        miETP.addActionListener(this);
        miCTP.addActionListener(this);
        miERP.addActionListener(this);
        miCRP.addActionListener(this);
        miDS.addActionListener(this);
        miDPH.addActionListener(this);
        miLPO.addActionListener(this);
        miLPnB.addActionListener(this);
        miLRP.addActionListener(this);
        miLPmB.addActionListener(this);
        miLAP.addActionListener(this);
        miAbout.addActionListener(this);
        miExit.addActionListener(this);
        //@menambahkan sub menu ke masing2 menu baris
        mMaster.add(miBarang);
        mMaster.add(miSuplier);
        mMaster.add(miPrice);
        mMaster.addSeparator();
        mMaster.add(miExit);
        mPemesanan.add(miEPO);
        mPemesanan.add(miCPO);
        mPenerimaan.add(miETP);
        mPenerimaan.add(miCTP);
        mRetur.add(miERP);
        mRetur.add(miCRP);
        mLaporan.add(miDS);
        mLaporan.add(miDPH);
        mLaporan.add(miLPO);
        mLaporan.add(miLPnB);
        mLaporan.add(miLRP);
        mLaporan.add(miLPmB);
        mLaporan.add(miLAP);
        mHelp.add(miAbout);
        //@mengatur object barmenu
        setJMenuBar(mBar);
        //@menambahkan object menu baris ke menubar
        mBar.add(mMaster);
        mBar.add(mPemesanan);
        mBar.add(mPenerimaan);
        mBar.add(mRetur);
        mBar.add(mLaporan);
        mBar.add(mHelp);
        lbJam.setForeground(Color.pink);
        mBar.add(lbJam);       
        //@mengatur objek baris status
        stBar.setLayout(new BorderLayout());
        stBar.setBackground(Color.darkGray);
        stBar.setFont(new Font("Arial",Font.BOLD,9));
        //@menambahkan objek label ke dalam baris status
        lb1.setForeground(Color.red);
        stBar.add(lb1, BorderLayout.WEST);
        lb2.setForeground(Color.yellow);
        stBar.add(lb2, BorderLayout.EAST);
        //@mengatur warna latar objek desktop
        desktop.setBackground(Color.black);
        //@menambahkan isi kontainer dengan objek toolbar, desktop dan statusbar dengan layout
border
        getContentPane().add(desktop, BorderLayout.CENTER);
        getContentPane().add(stBar, BorderLayout.SOUTH);
        if(data.equals("a")){
            miBarang.setEnabled(true);
        }
        else
            if(data.equals("b")){
            miExit.setEnabled(false);
            miBarang.setEnabled(false);
            miSuplier.setEnabled(false);
            miPrice.setEnabled(false);
            miEPO.setEnabled(false);
            miCPO.setEnabled(false);
            miETP.setEnabled(false);
            miCTP.setEnabled(false);
            miERP.setEnabled(false);
            miCRP.setEnabled(false);
            miAbout.setEnabled(false);
            }
        //@set jam agar dapat tampil pada form menu
        setJam();
        //@menampilkan menu utama kelayar monitor.
        show();       
    }
   
    /**
     * method @meriksa objeck(menupopup atau menupop) yang
     * sebelumnya mendapat Listener"addActionListener" ............
     */
    public void actionPerformed(ActionEvent ae){
        Object obj = ae.getSource();
        if(obj==miBarang){
            barang barang=new barang();
            desktop.add(barang);
            barang.show();
        }
        if(obj==miSuplier){
            suplier suplier=new suplier();
            desktop.add(suplier);
            suplier.show();
        }
        if(obj==miPrice){
            price price=new price();
            desktop.add(price);
            price.show();
        }
        if(obj==miEPO){
            purchase purchase=new purchase();
            desktop.add(purchase);
            purchase.show();
        }
        if(obj==miCPO){
            CPO cpo=new CPO();
            desktop.add(cpo);
            cpo.show();
        }
        if(obj==miETP){
            penerimaan penerimaan=new penerimaan();
            desktop.add(penerimaan);
            penerimaan.show();
        }
        if(obj==miCTP){
            CTP ctp=new CTP();
            desktop.add(ctp);
            ctp.show();
        }
        if(obj==miERP){
            retur retur=new retur();
            desktop.add(retur);
            retur.show();
        }
        if(obj==miCRP){
            CRP crp=new CRP();
            desktop.add(crp);
            crp.show();
        }
        if(obj==miDS){
            dafsup dafsup=new dafsup();
            desktop.add(dafsup);
            dafsup.show();
        }
        if(obj==miDPH){
            dafperha dafperha=new dafperha();
            desktop.add(dafperha);
            dafperha.show();
        }
        if(obj==miLPO){
            lapuro lapuro=new lapuro();
            desktop.add(lapuro);
            lapuro.show();
        }
        if(obj==miLPnB){
            lapenba lapenba=new lapenba();
            desktop.add(lapenba);
            lapenba.show();
        }
        if(obj==miLRP){
            larepem larepem=new larepem();
            desktop.add(larepem);
            larepem.show();
        }
        if(obj==miLPmB){
            lapemba lapemba=new lapemba();
            desktop.add(lapemba);
            lapemba.show();
        }
        if(obj==miLAP){
            lapanpem lapanpem=new lapanpem();
            desktop.add(lapanpem);
            lapanpem.show();
        }
        if(obj == miAbout){
            about miAbout=new about();
            desktop.add(miAbout);
            miAbout.show();
        }
        if(obj==miExit){
            exit();
        }
    }
   
    /**
     * method @keluar dari System
     */
    private void exit(){
        try{
            int rep=JOptionPane.showConfirmDialog(this,"By.RadenMas RamaHandi\nMoo Keluar
dari Aplikasi ini Y/N ?","kadalistn", JOptionPane.YES_NO_OPTION,
JOptionPane.PLAIN_MESSAGE);
            if(rep==JOptionPane.YES_OPTION){
                setVisible(false);  //@Menyembunyikan Frame.
                dispose();             //@Membersihkan Resource dari system memori
                System.out.println("\n\nThanks For All ... \n\nBy kadalistn@yahoo.com\n  
jl.caringin1no.44@gmail.com\n   mas.handi@yahoo.co.id\n\n\n   Bey bey ...\n\n");
                System.exit(0);
            }
            else{
            }
            setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);   //Membebaskan
aplikasi dari memori
        }
        catch(Exception e){
        }
    }
   
    /**
     * method atau fungsi @mengatur waktu dari System ...
     */
    public void setJam(){
        ActionListener taskPerformer = new ActionListener(){
            public void actionPerformed(ActionEvent evt){
                String nol_jam = "", nol_menit = "", nol_detik = "";
                Date dateTime = new Date();
                int nilai_jam = dateTime.getHours();
                int nilai_menit = dateTime.getMinutes();
                int nilai_detik = dateTime.getSeconds();
                if(nilai_jam <= 9) nol_jam = "0";
                if(nilai_menit <= 9) nol_menit = "0";
                if(nilai_detik <= 9) nol_detik = "0";
                String jam = nol_jam + Integer.toString(nilai_jam);
                String menit = nol_menit + Integer.toString(nilai_menit);
                String detik = nol_detik + Integer.toString(nilai_detik);
                lbJam.setText("  "+"  ---@Time:( "+jam + ":" + menit + ":" + detik + " ):emiT@---");
            }
        };
        new Timer(1000, taskPerformer).start();
    }
   
}
 balas

...
by Anonim (tidak terverifikasi) - 07/28/2010 - 12:43

kaya nye sich codingnye ga da yang salah tuh

bahkan 100% ga da Error ; mungki klo coding ini bayak yang Error :

/*
 * @RadenMas
 * source code untuk form Menu
 * dengan menggunakan JDesktopPane, JMenuBar, JMenu, JMenuItem & JPanel
 *
 * contact :
 * kadalistn@yahoo.com
 * jl.caringin1no.44@gmail.com
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.Timer;
import java.util.*;
import java.text.*;

public class menu extends JFrame implements ActionListener{


    private JDesktopPane desktop=new JDesktopPane(); //@deklarasi JDesktop
    private JMenuBar mBar=new JMenuBar(); //@deklarasi MenuBar
    private JLabel lbJam=new JLabel(); //@deklarasi Label untuk Jam pada JMenuBar
    private JMenu mMaster=new JMenu("File_Master"), //@deklarasi JMenu
            mPemesanan=new JMenu("Pemesanan_Barang"),
            mPenerimaan=new JMenu("Penerimaan_Barang"),
            mRetur=new JMenu("Retur_Pembelian"),
            mLaporan=new JMenu("Laporan"),
            mHelp=new JMenu("Help_?");
    private JMenuItem miBarang=new JMenuItem("Entry_Master_Barang"), //@deklarasi
JMenuItem
            miSuplier=new JMenuItem("Entry_Master_Suplier"),
            miPrice=new JMenuItem("Entry_Price_List"),
            miEPO=new JMenuItem("Entry_Purchase_Order"),
            miCPO=new JMenuItem("Cetak_Purchase_Order"),
            miETP=new JMenuItem("Entry_Tanda_Penerimaan"),
            miCTP=new JMenuItem("Cetak_Tanda_Penerimaan"),
            miERP=new JMenuItem("Entry_Retur_Pembelian"),
            miCRP=new JMenuItem("Cetak_Retur_Pembelian"),
            miDS=new JMenuItem("Daftar_Suplier"),
            miDPH=new JMenuItem("Daftar_Perbandingan_Harga"),
            miLPO=new JMenuItem("Laporan_Purchase_Order_(PO)"),
            miLPnB=new JMenuItem("Laporan_Penerimaan_Barang"),
            miLRP=new JMenuItem("Laporan_Retur_Pembelian"),
            miLPmB=new JMenuItem("Laporan_Pembelian_Barang"),
            miLAP=new JMenuItem("Laporan_Analisa_Pembelian"),
            miAbout=new JMenuItem("About"),
            miExit=new JMenuItem("Exit_Aplikasi");
           
    /** @jika ingin menambahkan ImageIcon pada JMenuItem=new JMenuItem("Data Obat",new
ImageIcon("path/image"));
     *
     * @mengambil tanggal aktif dari komputer & mengatur format tanggal
     */
    private Date tgl=new Date();
    private SimpleDateFormat sdf=new SimpleDateFormat("dd MMM
yyyy",Locale.getDefault());
    private String tanggal=sdf.format(tgl); //@untuk format tanggal
    //@deklarasi komponen panel & objek label untuk statusbar
    private JPanel stBar=new JPanel();
    private JLabel lb1=new JLabel(" "+"By.RadenMas RamaHandi",JLabel.LEFT),lb2=new
JLabel(" "+tanggal+" ",JLabel.RIGHT);
   
    /**
     * method menu() menggunakan constructor
     * String data ....
     */
    public menu(String data){
        super("Menu @Example");
        setSize(1020,650);
        setLocation((Toolkit.getDefaultToolkit().getScreenSize().width-getWidth())/2,
(Toolkit.getDefaultToolkit().getScreenSize().height-getHeight())/2);
        //@memberikan listener & mengeksekusi fungsi keluar saat toombol di klck
        addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent we){
                exit();
            }
        });
        //@mengatur tbl Alt pada menu fulldown
        mMaster.setMnemonic('F');
        mPemesanan.setMnemonic('P');
        mPenerimaan.setMnemonic('P');
        mRetur.setMnemonic('R');
        mLaporan.setMnemonic('L');
        mHelp.setMnemonic('H');
        //@mengatur penggunaan shortcut pada menu fulldown
       
miBarang.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B,Event.CTRL_MASK));
       
miSuplier.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,Event.CTRL_MASK));
        miPrice.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P,Event.CTRL_MASK));
        miAbout.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,Event.CTRL_MASK));
        miExit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E,Event.CTRL_MASK));
        //@mengatur menu fulldown agar dapat di click
        miBarang.addActionListener(this);
        miSuplier.addActionListener(this);
        miPrice.addActionListener(this);
        miEPO.addActionListener(this);
        miCPO.addActionListener(this);
        miETP.addActionListener(this);
        miCTP.addActionListener(this);
        miERP.addActionListener(this);
        miCRP.addActionListener(this);
        miDS.addActionListener(this);
        miDPH.addActionListener(this);
        miLPO.addActionListener(this);
        miLPnB.addActionListener(this);
        miLRP.addActionListener(this);
        miLPmB.addActionListener(this);
        miLAP.addActionListener(this);
        miAbout.addActionListener(this);
        miExit.addActionListener(this);
        //@menambahkan sub menu ke masing2 menu baris
        mMaster.add(miBarang);
        mMaster.add(miSuplier);
        mMaster.add(miPrice);
        mMaster.addSeparator();
        mMaster.add(miExit);
        mPemesanan.add(miEPO);
        mPemesanan.add(miCPO);
        mPenerimaan.add(miETP);
        mPenerimaan.add(miCTP);
        mRetur.add(miERP);
        mRetur.add(miCRP);
        mLaporan.add(miDS);
        mLaporan.add(miDPH);
        mLaporan.add(miLPO);
        mLaporan.add(miLPnB);
        mLaporan.add(miLRP);
        mLaporan.add(miLPmB);
        mLaporan.add(miLAP);
        mHelp.add(miAbout);
        //@mengatur object barmenu
        setJMenuBar(mBar);
        //@menambahkan object menu baris ke menubar
        mBar.add(mMaster);
        mBar.add(mPemesanan);
        mBar.add(mPenerimaan);
        mBar.add(mRetur);
        mBar.add(mLaporan);
        mBar.add(mHelp);
        lbJam.setForeground(Color.pink);
        mBar.add(lbJam);       
        //@mengatur objek baris status
        stBar.setLayout(new BorderLayout());
        stBar.setBackground(Color.darkGray);
        stBar.setFont(new Font("Arial",Font.BOLD,9));
        //@menambahkan objek label ke dalam baris status
        lb1.setForeground(Color.red);
        stBar.add(lb1, BorderLayout.WEST);
        lb2.setForeground(Color.yellow);
        stBar.add(lb2, BorderLayout.EAST);
        //@mengatur warna latar objek desktop
        desktop.setBackground(Color.black);
        //@menambahkan isi kontainer dengan objek toolbar, desktop dan statusbar dengan layout
border
        getContentPane().add(desktop, BorderLayout.CENTER);
        getContentPane().add(stBar, BorderLayout.SOUTH);
        if(data.equals("a")){
            miBarang.setEnabled(true);
        }
        else
            if(data.equals("b")){
            miExit.setEnabled(false);
            miBarang.setEnabled(false);
            miSuplier.setEnabled(false);
            miPrice.setEnabled(false);
            miEPO.setEnabled(false);
            miCPO.setEnabled(false);
            miETP.setEnabled(false);
            miCTP.setEnabled(false);
            miERP.setEnabled(false);
            miCRP.setEnabled(false);
            miAbout.setEnabled(false);
            }
        //@set jam agar dapat tampil pada form menu
        setJam();
        //@menampilkan menu utama kelayar monitor.
        show();       
    }
   
    /**
     * method @meriksa objeck(menupopup atau menupop) yang
     * sebelumnya mendapat Listener"addActionListener" ............
     */
    public void actionPerformed(ActionEvent ae){
        Object obj = ae.getSource();
        if(obj==miBarang){
            barang barang=new barang();
            desktop.add(barang);
            barang.show();
        }
        if(obj==miSuplier){
            suplier suplier=new suplier();
            desktop.add(suplier);
            suplier.show();
        }
        if(obj==miPrice){
            price price=new price();
            desktop.add(price);
            price.show();
        }
        if(obj==miEPO){
            purchase purchase=new purchase();
            desktop.add(purchase);
            purchase.show();
        }
        if(obj==miCPO){
            CPO cpo=new CPO();
            desktop.add(cpo);
            cpo.show();
        }
        if(obj==miETP){
            penerimaan penerimaan=new penerimaan();
            desktop.add(penerimaan);
            penerimaan.show();
        }
        if(obj==miCTP){
            CTP ctp=new CTP();
            desktop.add(ctp);
            ctp.show();
        }
        if(obj==miERP){
            retur retur=new retur();
            desktop.add(retur);
            retur.show();
        }
        if(obj==miCRP){
            CRP crp=new CRP();
            desktop.add(crp);
            crp.show();
        }
        if(obj==miDS){
            dafsup dafsup=new dafsup();
            desktop.add(dafsup);
            dafsup.show();
        }
        if(obj==miDPH){
            dafperha dafperha=new dafperha();
            desktop.add(dafperha);
            dafperha.show();
        }
        if(obj==miLPO){
            lapuro lapuro=new lapuro();
            desktop.add(lapuro);
            lapuro.show();
        }
        if(obj==miLPnB){
            lapenba lapenba=new lapenba();
            desktop.add(lapenba);
            lapenba.show();
        }
        if(obj==miLRP){
            larepem larepem=new larepem();
            desktop.add(larepem);
            larepem.show();
        }
        if(obj==miLPmB){
            lapemba lapemba=new lapemba();
            desktop.add(lapemba);
            lapemba.show();
        }
        if(obj==miLAP){
            lapanpem lapanpem=new lapanpem();
            desktop.add(lapanpem);
            lapanpem.show();
        }
        if(obj == miAbout){
            about miAbout=new about();
            desktop.add(miAbout);
            miAbout.show();
        }
        if(obj==miExit){
            exit();
        }
    }
   
    /**
     * method @keluar dari System
     */
    private void exit(){
        try{
            int rep=JOptionPane.showConfirmDialog(this,"By.RadenMas RamaHandi\nMoo Keluar
dari Aplikasi ini Y/N ?","kadalistn", JOptionPane.YES_NO_OPTION,
JOptionPane.PLAIN_MESSAGE);
            if(rep==JOptionPane.YES_OPTION){
                setVisible(false);  //@Menyembunyikan Frame.
                dispose();             //@Membersihkan Resource dari system memori
                System.out.println("\n\nThanks For All ... \n\nBy kadalistn@yahoo.com\n  
jl.caringin1no.44@gmail.com\n   mas.handi@yahoo.co.id\n\n\n   Bey bey ...\n\n");
                System.exit(0);
            }
            else{
            }
            setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);   //Membebaskan
aplikasi dari memori
        }
        catch(Exception e){
        }
    }
   
    /**
     * method atau fungsi @mengatur waktu dari System ...
     */
    public void setJam(){
        ActionListener taskPerformer = new ActionListener(){
            public void actionPerformed(ActionEvent evt){
                String nol_jam = "", nol_menit = "", nol_detik = "";
                Date dateTime = new Date();
                int nilai_jam = dateTime.getHours();
                int nilai_menit = dateTime.getMinutes();
                int nilai_detik = dateTime.getSeconds();
                if(nilai_jam <= 9) nol_jam = "0";
                if(nilai_menit <= 9) nol_menit = "0";
                if(nilai_detik <= 9) nol_detik = "0";
                String jam = nol_jam + Integer.toString(nilai_jam);
                String menit = nol_menit + Integer.toString(nilai_menit);
                String detik = nol_detik + Integer.toString(nilai_detik);
                lbJam.setText("  "+"  ---@Time:( "+jam + ":" + menit + ":" + detik + " ):emiT@---");
            }
        };
        new Timer(1000, taskPerformer).start();
    }
   
}

Tanpa keterangan errornya,


by belajarprogram - 04/06/2009 - 21:03

Tanpa keterangan errornya, kita ngga tahu apa yang terjadi.

Mungkin lebih baik jika menggunakan IDE seperti Eclipse atau Netbeans. Untuk Eclipse,
program seperti di atas bisa dibuat dengan mudah. Lihat di sini untuk langkah demi langkah
silakan dilihat di sini

http://java.lyracc.com/artikel/java-untuk-pemula/menjalankan-eclipse-unt...

Kelas Pembungkus
Posted Sen, 04/06/2009 - 21:05 by belajarprogram

Versi ramah cetak

Seperti disebutkan sebelumnya, pemrograman generik pada Java tidak berlaku untuk tipe
primitif. Kita akan bahas masalah ini sebelum kita beranjak pada bagian berikutnya.

Kita tidak bisa menyimpan integer pada struktur data generik yang didesain untuk menyimpan
Object. Di lain pihak, tidak ada yang menghentikan kita untuk membuat objek yang hanya berisi
integer dan menggunakan objek itu untuk ditempatkan pada struktur data.

Dalam kasus sederhana, kita akan membuat kelas yang tidak berisi apa-apa kecuali sebuah
integer :

public class KontainerInt {


public int nilai;
}

Sebenarnya, Java telah memiliki kelas seperti ini. Objek yang bertipe java.lang.Integer berisi
sebuah int saja. Kelas ini disebut kelas pembungkus (wrapper) untuk int. Nilai int bisa
dimasukkan dalam konstruktor, misalnya
Integer bil = new Integer(17);

membuat objek Integer yang membungkus angka 17. Objek Integer bisa digunakan untuk
struktur data generik dan dalam situasi lain jika objek dibutuhkan. Nilai int tersebut disimpan
dalam variabel instansi private final dari objek Integer.

Jika bil variabel yang menunjuk pada objek bertipe Integer, maka kita akan tahu berapa
bilangan yang disimpan dalam objek ini dengan memanggil metode instansi bil.intValue().
Kita tidak bisa mengganti angka tersebut. Kita sebut objek Integer sebagai objek <span
style="color: #ff0000;">immutable</span> (objek yang tak mungkin berubah, yaitu lawan
kata dari mutable atau dapat bermutasi). Artinya, setelah dibuat, kita tidak bisa mengubahnya.
(Sama seperti objek bertipe String adalah objek immutable).

Ada kelas pembungkus untuk semua tipe primitif. Semua objek dari tipe ini adalah objek
immutable. Kelas pembungkus untuk tipe double adalah java.lang.Double. Nilai di dalam
objek bertipe Double bisa diambil dengan metode instansi doubleValue().

Kelas pembungkus memiliki beberapa metode yang berguna. Beberapa digunakan untuk
mendukung pemrograman generik. Misalnya, kelas pembungkus mendefinisikan metode
equals(Object) dan compareTo(Object) dengan benar.

Metode lain dalam kelas pembungkus adalah fungsi bantu untuk bekerja dengan tipe primitif.
Misalnya, kita temukan sebelumnya metode Integer.parseInt(String) dan
Double.parseDouble(String). Fungsi ini digunakan untuk mengubah string seperti "42" atau
"2.3421213" ke dalam angka yang sesuai.

List
Posted Sen, 04/06/2009 - 21:08 by belajarprogram

Versi ramah cetak

Ada dua cara paling umum untuk membuat list : sebagai array dinamis dan sebagai list berantai.
Kita telah membahas keduanya sebelumnya (di sini dan di sini). Keduanya tersedia dalam bentuk
generik dalam kelas java.util.ArrayList dan java.util.LinkedList.

ArrayList adalah urutan objek yang disimpan dalam bentuk array yang ukurannya bisa
membesar jika item baru ditambahkan. Sedangkan LinkedList adalah urutan objek yang
disimpan dalam simpul yang terhubung dengan pointer seperti rantai. Kedua kelas ini
mengimplementasikan interface java.util.List, yang memiliki operasi yang sama untuk
semua jenis list.

Kedua list tersebut mendukung operasi list dasar. Tipe data abstrak didefinisikan dalam bentuk
operasi yang bisa dilakukannya, bukan bagaimana data disusun. Lalu kenapa kita memiliki 2
kelas? Mengapa bukan satu kelas List saja dengan satu jenis struktur data?
Masalahnya, tidak ada satupun struktur data list yang bisa melakukan semua operasi list secara
efisien. Untuk operasi tertentu, list berantai lebih efisien daripada array. Untuk operasi lainnya,
array lebih efisien. Tergantung daripada bagaimana list tersebut digunakan. Kita harus bisa
memilih bentuk mana yang paling cocok dengan melihat operasi apa yang sering digunakan.

Secara garis besar, kelas LinkedList lebih efisien untuk aplikasi di mana item-itemnya lebih
sering ditambah atau dibuang dari dalam list, terutama dari depan atau dari tengah list. Dalam
array, operasi tersebut memerlukan waktu yang cukup besar, karena untuk setiap penyisipan atau
pengurangan item, item harus digeser untuk membuat tempat kosong baru ditengah list. Pada list
berantai, simpul bisa diputus di tengah-tengah untuk menambahkan item baru, yaitu dengan
mengubah pointernya saja.

Kelas ArrayList lebih efisien digunakan jika akses random (random access) dibutuhkan oleh
aplikasi. Akses random maksudnya mengakses item ke-n di tengah-tengah list dan pindah dari
satu item ke item lain yang letaknya mungkin berjauhan.

Operasi yang bisa dilakukan dengan efisien oleh kedua kelas tersebut adalah mengurutkan dan
menambah item di akhir list.

Semua list mengimplementasikan metode dalam Collection, termasuk size(), isEmpty,


add(Object), remove(Object), dan clear().

Metode add(Object) digunakan untuk menambah objek di akhir list. Metode remove(Object)
dilakukan dengan mencari itemnya dahulu, yang tidak efisien dilakukan pada list berantai karena
pada list berantai item dibandingkan satu per satu dari awal list hingga item ditemukan.

Interface List menambah beberapa metode untuk mengakses item pada list tergantung dari
urutannya dalam list. Untuk objek list bertipe List, metode-metode yang tersedia adalah :

 list.get(indeks) -- mengembalikan Object di posisi indeks dalam list, di mana indeks


dimulai dari 0, 1, 2, .... hingga list.size() - 1. Parameter indeks harus ada dalam rentang
ini, jika tidak maka pengecualian IndexOutOfBoundsException akan dilemparkan.
 list.set(indeks, obj) -- menyimpan obj di dalam list pada posisi indeks, dan mengganti
isi objek yang sudah ada di posisi tersebut. Metode ini tidak mengubah jumlah elemen di dalam
list atau memindahkan elemen lain.
 list.add(indeks, obj) -- menyisipkan objek obj di dalam list pada posisi indeks. Jumlah
item di dalam list akan bertambah satu, dan item setelah posisi indeks akan digeser ke
belakang. Nilai indeks harus berada pada rentang 0 hingga list.size().
 list.remove(indeks) -- menghapus objek pada posisi indeks. Item setelah posisi ini akan
digeser maju untuk mengisi kekosongan objek pada posisi tersebut setelah item dihapus.
 list.indexOf(obj) -- mencari objek obj di dalam list dan mengembalikan indeksnya pada
list, jika ada. Jika objek yang dicari tidak ada maka nilai -1 akan dikembalikan. Jika obj ada lebih
dari satu dalam list, hanya indeks pertama yang dikembalikan.

Metode-metode ini didefinisikan pada kelas ArrayList dan LinkedList, meskipun metode-
metode ini hanya efisien pada ArrayList. Kelas LinkedList memiliki beberapa metode
tambahan yang tidak ada pada ArrayList. Jika linkedlist adalah objek bertipe LinkedList,
maka

 linkedlist.getFirst() -- mengembalikan Object pada posisi pertama di dalam list. List


tidak diubah sama sekali.
 linkedlist.getLast() -- mengembalikan Object pada posisi terakhir di dalam list. List
tidak diubah sama sekali.
 linkedlist.removeFirst() -- menghapus Objek pada posisi pertama di dalam list. Object
yang dihapus akan dikembalikan sebagai nilai keluaran.
 linkedlist.removeLast() -- menghapus Objek pada posisi terakhir di dalam list. Object
yang dihapus akan dikembalikan sebagai nilai keluaran.
 linkedlist.addFirst(obj) -- menambah obj pada posisi pertama di dalam list.
 linkedlist.addLast(obj) -- menambah obj pada posisi terakhir di dalam list. (Sama persis
dengan linkedlist.add(obj))

Metode-metode di atas sepertinya dibuat sehingga LinkedList mudah digunakan sebagai


tumpukan atau antrian (lihat bagian sebelumnya dan bagian ini). Misalnya kita bisa
menggunakan LinkedList sebagai antrian dengan menambah item di akhir list (menggunakan
metode addLast()) dan menghapus item dari awal list (menggunakan metode removeFirst()).

Jika list adalah objek bertipe List maka metode list.iterator() yang didefinisikan pada
interface Collection, akan mengembalikan Iterator yang bisa digunakan untuk menelusuri
list tersebut dari awal hingga akhir.

Akan tetapi, untuk List ada tipe Iterator khusus yang bernama ListIterator yang memiliki
kemampuan tambahan. Metode list.listIterator() mengembalikan objek bertipe
ListIterator dari list.

ListIterator memiliki metode Iterator biasa, seperti hasNext() dan next(), tetapi juga
hasPrevious() dan previous sehingga kita bisa melakukan penelusuran mundur.

Untuk mengerti lebih dalam, mungkin ada baiknya jika iterator diibaratkan sebagai iterator yang
menunjuk pada posisi di antara dua elemen, atau di akhir atau di depan list. Dalam diagram
berikut, item dalam list digambarkan sebagai kotak, dan panah menunjukkan posisi dari iterator :

Jika iter adalah suatu ListIterator, maka

 iter.next() memindahkan iterator satu tempat ke kanan dan mengembalikan item yang baru
dilewatinya.
 Metode iter.previous() memindahkan iterator ke kiri dan mengambalikan item yang
dilewatinya.
 Metode iter.remove() menghapus item dari dalam list. Item yang dihapus adalah item yang
baru saja dilewati oleh iter.next() atau iter.previous().
 iter.add(Object) akan menambah Object ke dalam list pada posisi iterator sekarang.
Artinya bisa berada di tengah-tengah dua item, di awal list atau di akhir list.

(Untuk pengetahuan, list yang digunakan oleh kelas LinkedList adalah list berantai ganda
(doubly linked list). Artinya, setiap simpul pada list memiliki dua pointer, yaitu satu yang
menunjuk pada simpul setelahnya dan satu lagi menunjuk pada simpul sebelumnya. Sehingga
metode next() dan previous() bisa diimplementasikan dengan efisien. Dan juga, metode
addLast() dan getLast() menjadi efisien karena kelas LinkedList juga memiliki variabel
instansi yang menunjuk pada simpul terakhir di dalam list.)

Sebagai contoh untuk menggunakan ListIterator, misalnya kita ingin menjaga agar suatu list
selalu terurut dalam urutan menaik. Ketika kita menambah item di dalam list, kita bisa
menggunakan ListIterator untuk menemukan posisi yang tepat di dalam list untuk
meletakkan item baru itu.

Idenya adalah memulai dari awal list, kemudian memindahkan iterator melalui semua item yang
lebih kecil dari item yang ingin sisipkan. Pada posisi tersebut, metode add() dari iterator itu bisa
digunakan untuk menyisipkan item pada posisi yang tepat.

Untuk menentukan bahwa item baru tersebut lebih besar dari item di dalam list, maka kita
asumsikan bahwa item dalam list sudah mengimplementasikan interface Comparable dan
memiliki metode compareTo(). (Interface ini didiskusikan pada bagian sebelumnya). Berikut ini
adalah metode untuk melakukannya.

static void sisipTerurut(List list, Comparable itemBaru) {


 
// Kondisi awal : Item dalam ist diurut dalam urutan menaik
// menurut metode compareTo.
// itemBaru.compareTo(item) harus didefinisikan untuk
// setiap item di dalam list.
//
// Kondisi akhir : itemBaru yang sudah ditambahkan
// ada pada posisi yang benar, sehingga list
// masih dalam keadaan terurut menaik
 
ListIterator iter = list.listIterator();
 
// Pindahkan iterator sehingga menunjuk pada posisi yang tepat
// Jika itemBaru lebih besar dari semua item di dalam list, maka
// perulangan while akan berhenti ketika iter.hasNext() bernilai
// false, yaitu ketika iterator sampai pada akhir list.
 
while (iter.hasNext()) {
Object item = iter.next();
if (itemBaru.compareTo(item) <= 0) {
// itemBaru harus ada SEBELUM item pada iter
// Pindahkan iterator satu tempat sehingga
// menunjuk pada posisi penyisipan yang benar,
// dan pada akhir perulangan.
iter.previous();
break;
}
}
 
iter.add(itemBaru);
 
} // akhir sisipTerurut()

Karena parameter pada metode ini bertipe List, maka metode ini bisa digunakan pada
ArrayList maupun LinkedList, dan kira-kira akan berjalan dengan tingkat efisiensi yang sama
untuk kedua jenis list. Mungkin akan lebih mudah untuk menulis metode di atas dengan
menggunakan indeks seperti pada array, dan dengan menggunakan metode get(indeks) dan
add(indeks,obj). Akan tetapi metode ini akan berjalan sangat lambat untuk LinkedList
karena get(indeks) pada LinkedList berjalan tidak efisien.

Pengurutan List
Posted Sen, 04/06/2009 - 21:09 by belajarprogram

Versi ramah cetak

Mengurutkan list adalah operasi yang cukup umum dilakukan, dan seharusnya ada metode untuk
mengurut list di dalam interface List. Kenyataannya tidak ada.

Akan tetapi metode untuk mengurut List tersedia sebagai metode statik dalam kelas
java.util.Collections. Kelas ini memiliki berbagai metode statik yang digunakan untuk
membantu kelas-kelas koleksi :

 Collections.sort(list) digunakan untuk mengurut list dalam urutan menaik. Item di


dalam list harus mengimplementasikan interface Comparable, misalnya pada String.
 Collections.sort(list,komparator), digunakan untuk mengurut list menggunakan
komparator (pembanding) sendiri yang diberikan di dalam metode. Komparator adalah objek
yang memiliki metode compare() yang digunakan untuk membandingkan dua objek. Kita akan
lihat contohnya nanti.
 Collections.shuffle(list) digunakan untuk mengacak list.
 Collections.reverse(list) digunakan untuk membalik urutan elemen di dalam list,
sehingga elemen terakhir menjadi elemen pertama dan sebaliknya.

Karena metode pengurutan yang cukup efisien sudah diberikan untuk List, kita tidak perlu
membuat metode pengurutan sendiri. Tentunya kita akan bertanya apakah ada metode
pengurutan untuk array biasa. Jawabannya adalah ya.

Pengurutan array juga tersedia dalam metode statik dalam kelas java.util.Arrays.
 Arrays.sort(A) digunakan untuk mengurut array A, asalkan tipe dasar A adalah tipe dasar primitif
(kecuali boolean) atau jika A adalah array Object yang mengimplementasikan interface
Comparable.
 Arrays.sort(A, indeksAwal, indeksAkhir) digunakan untuk mengurut sebagian array saja. Ini
penting karena array kadang hanya terisi sebagian. Perintah ini mengurut array dari elemen
A[indeksAwal], A[indeksAwal + 1], ... hingga A[indeksAkhir - 1] dalam urutan
menaik. Array.sort(A, 0, N) bisa digunakan untuk mengurut N elemen pertama di array A.

Java tidak mendukung pemrograman generik untuk tipe primitif. Untuk mengimplementasikan
perintah Arrays.sort(A), kelas Arrays memiliki 8 metode : satu metode untuk array Object
dan masing-masing satu metode untuk tipe primitif byte, short, int, long, float, double, dan
char.

Set (Himpunan)
Posted Sel, 04/07/2009 - 20:31 by belajarprogram

Versi ramah cetak

Himpunan (set) adalah kumpulan Object yang mana tidak boleh ada dua dari objek yang sama
di dalam satu himpunan. Objek obj1 dan obj2 adalah objek yang sama jika
obj1.equals(obj2) menghasilkan nilai true (lihat bagian sebelumnya untuk penjelasan tentang
ini).

Set mengimplementasikan metode umum pada Collection dengan sedikit modifikasi sehingga
tidak memiliki objek yang sama di dalamnya. Misalnya, jika set adalah objek bertipe Set maka
set.add(obj) tidak melakukan apa-apa jika obj sudah ada di dalam set.

Java memiliki dua kelas yang mengimplementasikan interface Set, yaitu java.util.TreeSet
dan java.util.HashSet.

Selain sebagai Set, objek bertipe TreeSet memiliki sifat di mana elemen-elemennya terurut
dalam urutan menaik. Iterator dari suatu TreeSet akan mengunjungi elemen dalam set
tersebut dalam urutan menaik.

TreeSet tidak bisa menyimpan semua objek, karena objek yang disimpan harus bisa diurutkan.
Atau dengan kata iain, objek yang disimpan dalam TreeSet harus mengimplementasikan
interface Comparable dan obj1.compareTo(obj2) harus bisa membandingkan 2 objek obj1
dan obj2 dengan baik. Atau cara lainnya adalah dengan menggunakan Comparator yang bisa
dimasukkan sebagai parameter dalam konstruktor ketika TreeSet dibuat. Di sini Comparator
digunakan untuk membandingkan objek yang akan dimasukkan di dalam set.

Pada implementasi TreeSet, elemen di dalamnya disimpan dalam bentuk yang mirip dengan
pohon pengurutan biner (lihat bagian sebelumnya). Pohon yang digunakan bersifat seimbang
(balanced) yang artinya semua simpul daunnya berjarak sama dari akar pohonnya. Dengan
menggunakan pohon seimbang, kita bisa memastikan bahwa kita bisa mencapai semua simpul
daunnya dengan secepat mungkin. Menambah dan mengurangi simpulnya juga bisa dilakukan
dengan cepat.

Karena TreeSet mengurutkan elemen-elemennya dan menjamin tidak ada duplikasi objek,
TreeSet sangat berguna untuk beberapa aplikasi. Misalnya, kita akan membuat program untuk
menghitung semua kata dalam suatu artikel dan menampilkan semua kata yang ditemukan. List
kata-kata dalam artikel itu harus diurutkan, kemudian kata-kata yang sama dihapus. Dengan
menggunakan TreeSet, program tersebut dapat dibuat dengan sangat mudah, menjadi :

TreeSet kata = new TreeSet();


 
while masih ada data dari input :
kt = kata berikutnya dari input
kata.add(kt);
 
Iterator iter = kata.iterator();
while (iter.hasNext()):
Tampikan iter.next() ke layar.

Contoh lainnya, misalnya kol adalah koleksi String (atau tipe lain yang mengimplementasikan
compareTo()). Kita bisa menggunakan TreeSet untuk mengurutkan item dari kol dan
menghapus duplikasi dengan :

TreeSet set = new TreeSet();


set.addAll(kol);

Perintah baris kedua di atas menambah semua elemen dari kol ke dalam set. Karena berbentuk
Set, maka duplikasi akan dihapus. Karena berbentuk TreeSet maka semua elemennya akan
terurut. Jika kita ingin data tersebut disimpan dalam struktur data lain, kita bisa mengubahnya
dengan mudah. Misalnya, untuk membuat ArrayList dari TreeSet, bisa kita tulis dengan :

TreeSet set = new TreeSet();


set.addAll(kol);
ArrayList list = new ArrayList();
list.addAll(set);

Sebetulnya, kelas koleksi Java memiliki konstruktor yang bisa mengambil parameter berbentuk
Collection. Semua item dalam Collection ditambahkan ke dalam koleksi baru ketika dibuat.
Jadi new TreeSet(kol) membuat TreeSet yang memiliki elemen yang sama seperti koleksi
kol.

Atau kita bisa menyingkat keempat baris kode di atas dalam satu baris kode :

ArrayList list = new ArrayList( new TreeSet(kol) );

Hasilnya adalah list terurut dengan elemen dari kol tanpa duplikasi. Ini adalah contoh dari
keampuhan pemrograman generik.
(Sepertinya tidak ada struktur data list dengan duplikasi pada Java, atau TreeSet yang
membolehkan duplikasi. Pada bahasa pemrograman C++ struktur data ini disebut multiset. Pada
bahasa Smalltalk, struktur data seperti ini disebut bag (kantong). Pada Java, untuk saat ini, tidak
ada struktur data seperti ini.)

HashSet mengimplementasikan tabel hash yang akan kita bahas di bagian berikutnya. Operasi
penambahan, pencarian, dan penghapusan dilakukan dengan sangat efisien pada tabel hash,
bahkan lebih cepat lagi dari TreeSet. Elemen pada HashSet tidak disimpan dalam urutan
tertentu.

Iterator dari HashSet akan mengunjungi elemen-elemen pada HashSet dalam urutan yang
sepertinya acak dan mungkin berubah jika elemen baru ditambahkan.

Karena elemen pada HashSet tidak diurutkan, maka semua objek (termasuk yang tidak
mengimplementasikan interface Comparable) bisa dimasukkan dalam HashSet. Kita bisa
menggunakan HashSet jika elemen yang kita akan masukkan tidak bisa dibandingkan, atau
urutannya tidak penting, atau jika kecepatan lebih dipentingkan.

Kelas Map
Posted Sel, 04/07/2009 - 20:31 by belajarprogram

Versi ramah cetak

Suatu array yang berisi N elemen bisa juga dilihat sebagai asosiasi (pemetaan) antara elemennya
dengan bilangan 0, 1, ..., N-1 yang merupakan indeksnya. Jika i adalah salah satu bilangan ini,
maka kita bisa mengambil elemen yang dipetakan oleh bilangan i, dan juga kita bisa meletakkan
elemen baru pada posisi ke-i.

Suatu peta (map) adalah generalisasi dari array. Seperti array, map juga memiliki operasi untuk
mengambil dan meletakkan elemen. Akan tetapi pada map, operasi ini tidak dilakukan pada
bilangan 0, 1, ... N-1, akan tetapi pada sembarang Object.

Beberapa bahasa pemrograman menggunakan istilah array asosiatif (associative array) karena
kesamaan perintah dengan array biasa. Pada bahasa pemrograman tersebut, kita bisa menuliskan
A["joko"] yang digunakan untuk memetakan "joko" pada suatu elemen di dalam array.

Java tidak menggunakan perintah yang sama pada map, akan tetapi idenya serupa : Map adalah
seperti array yang indeksnya adalah objek sembarang, bukan integer. Pada map, objek yang
digunakan sebagai "indeks" disebut kunci (key). Objek yang ditunjuk oleh indeks tersebut
disebut nilai (value).

Satu kunci hanya boleh menunjuk pada satu nilai, akan tetapi satu nilai bisa ditunjuk oleh
beberapa kunci.
Dalam Java, map didefinisikan dalam interface java.util.Map, yang memiliki beberapa metode
untuk bekerja dengan map. Jika map adalah variabel dengan tipe Map, maka berikut ini adalah
beberapa metodenya :

 map.get(kunci) -- mengembalikan Object yang ditunjuk oleh kunci. Jika map tidak
memiliki nilai yang ditunjuk oleh kunci, maka nilai null akan dikembalikan. Tapi ingat juga
bahwa mungkin saja kuncinya ada akan tetapi memang menunjuk pada nilai null.
Menggunakan "map.get(kunci)" sama dengan perintah "A[kunci]" pada array A. (Akan
tetapi pada map tidak ada pengecualian IndexOutOfBoundsException)
 map.put(kunci, nilai) -- Mengisi map dengan pasangan kunci dan nilai. Kedua-dua
kunci dan nilai bisa berupa objek apa saja. Jika map tersebut telah memiliki kunci maka
nilai yang ditunjuk akan diganti dengan yang baru diberikan. Perintah ini mirip dengan
"A[kunci] = nilai" pada array.
 map.putAll(map2) -- jika map2 adalah map lain, maka perintah ini akan mengkopi semua isi
pada map2 ke dalam map.
 map.remove(kunci) -- Jika map memiliki kunci yang menunjuk pada suatu nilai, perintah ini
akan menghapus kunci beserta nilai yang ditunjuknya, atau dengan kata lain menghapus
pasangan kunci dan nilai pada map sekaligus.
 map.containsKey(kunci) -- mengembalikan nilai boolean true jika map memiliki kunci
yang merujuk pada suatu nilai
 map.containsValue(nilai) -- mengembalikan nilai boolean true jika map memiliki nilai
yang ditunjuk oleh kunci apapun.
 map.size() -- mengembalikan int yang berisi jumlah pasangan asosiasi pada map.
 map.isEmpty() -- mengembalikan boolean true jika map tidak berisi pasangan asosiasi apa-
apa.
 map.clear() -- menghapus semua pasangan asosiasi dalam map.

Metode put dan get jelas merupakan metode yang paling sering digunakan dalam map. Dalam
banyak aplikasi, metode ini mungkin hanya metode ini yang kita butuhkan. Artinya,
menggunakan map sama mudahnya dengan menggunakan array biasa.

Java memiliki dua kelas yang mengimplementasikan interface Map, yaitu : TreeMap dan
HashMap.

Dalam TreeMap, pasangan kunci/nilai disimpan secara berurutan dalam pohon terurut, yaitu
diurut berdasarkan kuncinya. Supaya bisa bekerja dengan benar, maka hanya objek yang bisa
dibandingkan saja yang bisa digunakan sebagai kunci. Artinya kelas kunci harus berupa kelas
yang mengimplementasikan interface Comparable, atau Comparator harus diberikan pada
konstruktornya pada saat TreeMap dibuat.

HashMap tidak menyimpan pasangan kunci/nilai dalam urutan tertentu, sehingga tidak ada
batasan objek apa yang bisa disimpan di dalamnya. Hampir semua operasi dapat berjalan lebih
cepat pada HashMap dibandingkan dengan TreeMap.
Secara umum, lebih baik menggunakan HashMap kecuali kita butuh struktur data dalam urutan
tertentu yang hanya bisa dilakukan dengan TreeMap. Atau dengan kata lain, jika kita hanya
menggunakan perintah put dan get, gunakan HashMap.

Misalnya progrma direktori telefon, yaitu pada kelas BukuTelepon yang memiliki pasangan
nama/nomor telepon. Kelas ini memiliki operasi tambahEntri(nama, nomor) dan
ambilNomor(nama), di mana nama dan nomor bertipe String.

Dalam aplikasi pemrograman sebenarnya, kita tidak perlu lagi membuat kelas baru untuk
mengimplementasikan BukuTelepon tersebut, artinya kita bisa langsung menggunakan Map.
Akan tetapi menggunakan Map mungkin memiliki sedikit kerugian, karena kita dipaksa harus
menggunakan Object bukan String.

Jika ini masalahnya, maka kita bisa membuat kelas baru yang menggunakan Map dalam
implementasinya, seperti berikut :

import java.util.HashMap;
 
public class BukuTelepon {
 
// Menyimpan data telepon
private HashMap info = new HashMap();
 
public void tambahEntri(String nama, String nomor) {
// Menyimpan nomor telepon pada nama yang sesuai
info.put(nama,nomor);
}
 
public String ambilNomor(String nama) {
// Mengambil nomor telepon dari nama
// Kembalikan null jika tidak ada nomor telepon untuk nama tsb
return (String)info.get(nama);
}
 
} // akhir kelas BukuTelepon

Dalam metode ambilNomor di atas, nilai kembalian dari info.get(nama) di-type-cast ke dalam
String. Karena kembalian dari metode get() bertipe Object maka type cast menjadi penting
sebelum nilainya bisa digunakan.

Dengan "membungkus" Map di dalam kelas BukuTelepon, kita menyembunyikan type-cast


dalam implementasinya sehingga interaksi kelas ini dengan kelas lain yang menggunakannya
menjadi lebih natural.

Tampilan, subset, dan submap


Posted Sel, 04/07/2009 - 22:24 by belajarprogram

Versi ramah cetak


Map sebenarnya bukan merupakan Collection, artinya map tidak mengimplementasikan semua
operasi yang didefinisikan pada interface Collection, karena map tidak memiliki iterator. Akan
tetapi, Java memiliki cara lain untuk melakukan penelusuran item pada map.

Jika map adalah variabel bertipe Map, maka metode

map.keySet()

akan mengembalikan semua objek kunci pada map. Karena di dalam map tidak ada kunci yang
sama, maka hasilnya akan dikembalikan dalam bentuk Set. Hasil yang dikembalikan oleh
map.keySet() disebut tampilan (view) dari objek-objek yang disimpan di dalam map.

"Tampilan" yang dikembalikan metode ini berhubungan langsung dengan map aslinya, artinya
jika kita menghapus elemen dari dalam tampilan ini, maka kunci beserta nilai yang ditunjuk di
dalam map akan juga dihapus. Tampilan tidak bisa digunakan untuk menambah data, karena
fungsinya hanya sebagai tampilan. Karena map.keySet() tidak membuat set baru, maka
perintah ini akan cukup efisien untuk digunakan pada map yang sangat besar sekalipun.

Kita bisa menggunakan iterator untuk melakukan penelusuran isi Set. Kita bisa juga
menggunakan iterator untuk kunci dari map, kemudian menelusurinya, misalnya :

Set kunci = map.keySet(); // Set kunci dari map


Iterator kunciIter = kunci.iterator();
System.out.println("Map ini memiliki asosiasi sebagai berikut:");
while (kunciIter.hasNext()) {
Object knc = kunciIter.next(); // Ambil kunci berikut
Object nilai = map.get(knc); // Ambil nilai yang ditunjuk oleh kunci
System.out.println( " (" + knc + "," + nilai + ")" );
}

Jika map adalah suatu TreeMap, maka set kuncinya adalah set yang terurut, dan iteratornya akan
mengunjungi kunci-kuncinya dalam urutan menaik.

Interface Map memiliki 2 jenis tampilan lain. Jika map adalah variabel bertipe Map, maka metode :

map.values()

mengembalikan Collection yang berisi semua nilai yang disimpan dalam map. Nilai
kembaliannya bukan Set karena suatu map bisa berisi nilai yang sama. Metode

map.entrySet()

mengembalikan Set yang berisi asosiasi (kunci dan nilainya) di dalam map. Informasi dalam
kelas ini sama dengan informasi dalam map itu sendiri, akan tetapi Set yang dikembalikan
menampilkan jenis informasi yang berbeda. Setiap elemen dalam set ini adalah objek bertipe
Map.Entry (Kelas ini adalah kelas statik bertingkat, sehingga namanya memiliki tanda titik.
Akan tetapi tetap bisa digunakan sebagaimana kelas-kelas lainnya).
Objek Map.Entry berisi hanya satu pasangan kunci dan nilai, dan memiliki metode getKey()
dan getValue() untuk mengambil kunci dan nilainya. Ada juga metode setValue(nilai)
untuk mengisi nilainya. Kita bisa menggunakan set ini untuk mencetak semua pasangan kunci
dan nilainya, yang lebih efisien daripada menggunakan kunci kemudian mengambil kembali
isinya dari dalam map seperti contoh di atas.

Sehingga kita bisa membuat fungsi yang sama dengan di atas dengan lebih efisien, yaitu

Set entri = map.entrySet();


Iterator entriIter = entri.iterator();
System.out.println("Map ini berisi asosiasi sebagai berikut:");
while (entriIter.hasNext()) {
Map.Entry pasangan = (Map.Entry)entriIter.next();
Object kunci = pasangan .getKey(); // Ambil kunci dari pasangan
Object nilai = pasangan .getValue(); // Ambil nilainya
System.out.println( " (" + kunci + "," + nilai + ")" );
}

Map bukan satu-satunya tempat di mana tampilan bisa diambil. Misalnya, interface List
memiliki sublist yang untuk melihat sebagian isi list. Metode

List subList(int indeksAwal, int indeksAkhir)

mengembalikan sebagian list yang terdiri dari elemen pada posisi antara indeksAwal hingga
indeksAkhir (termasuk indeksAwal tapi tidak termasuk indeksAkhir.) Tampilan ini
memungkinkan kita untuk melakukan operasi apapun seperti pada list biasa, akan tetapi sublist
bukan list terpisah. Perubahan yang dilakukan pada sublist akan juga mempengaruhi list aslinya.

Begitu juga dengan set, kita bisa membuat tampilan yang merupakan subset dari suatu set. Jika
set adalah suatu TreeSet, maka set.subSet(dariElemen, hinggaElemen) mengembalikan
[code]Set yang berisi elemen-elemen set antara dariElemen hingga hinggaElemen (termasuk
dariElemen tapi tidak termasuk hinggaElemen).

Misalnya, jika kata adalah suatu TreeSet di mana semua elemennya adalah String berisi huruf
kecil, maka kata.subSet("m", "n") akan berisi semua elemen pada kata yang dimulai dari
huruf m. Subset ini adalah tampilan yang merupakan bagian dari set aslinya. Artinya membuat
subset tidak mengkopi elemen, dan perubahan pada subset (misalnya penambahan dan
pengurangan elemen) juga mempengaruhi set aslinya.

Tampilan set.headSet(hinggaElemen) berisi semua elemen dari set yang kurang


dari [code]hinggaElemen, dan set.tailSet(dariElemen) adalah tampilan yang berisi
semua elemen yang lebih besar atau sama dengan dariElemen.

Kelas TreeMap memiliki tiga tampilan submap. Submap mirip dengan subset. Submat adalah Map
yang berisi subset dari kunci dan nilai pada Map aslinya. Jika map suatu variabel bertipe TreeMap,
maka map.subMap(dariKunci, hinggaKunci) mengembalikan tampilan yang berisi semua
pasangan kunci/nilai dari map yang kuncinya ada di antara dariKunci dan hinggaKunci
(termasuk dariKunci tapi tidak termasuk hinggaKunci).
Ada juga tampilan map.headMap(hinggaKunci) dan map.tailMap(dariKunci) seperti aturan
pada subset.

Misalnya, bukuHitam adalah suatu TreeMap di mana kuncinya adalah nama dan nilainya adalah
nomor telepon. Kita bisa mencetak semua entri pada bukuHitam yang namanya dimulai dengan
"M" seperti berikut :

Map ems = bukuHitam.subMap("M","N");


 
// Submap ini berisi semua elemen di mana kuncinya lebih
// besar dari "M" dan kurang dari (tapi tidak termasuk) "N"
if (ems.isEmpty())
System.out.println("Tidak ada elemen yang dimulai dengan M.");
else {
Iterator iter = ems.entrySet().iterator();
// Iterator ini akan menelusuri entri pada submap ems
while (iter.hasNext()) {
// Get the next entry and print its key and value.
Map.Entry entri = iter.next();
System.out.println( entri.getKey() + ": " + entri.getValue() );
}
}

Subset dan submap mungkin menjadi cara terbaik untuk melakukan pencarian, sehingga kita bisa
mencari elemen pada rentang nilai tertentu, bukan hanya pencarian satu nilai saja. Misalnya pada
database disimpan jadwal yang disimpan dalam bentuk TreeMap di mana kuncinya adalah waktu,
dan misalnya kita ingin mencari semua item yang terjadwal 1 Maret 2009. Kita hanya perlu
membuat submap yang berisi semua kunci antara 00:00 1 Maret 2009 hingga 00:00 2 Maret
2009 kemudian mencetak isi submap tersebut. Tipe pencarian seperti ini disebut pencarian
rentang (subrange query).

Tabel Hash
Posted Sel, 04/07/2009 - 22:28 by belajarprogram

Versi ramah cetak

HashSet dan HashMap diimplementasikan dengan struktur data yang disebut tabel hash. Kita
tidak perlu mengerti tabel hash untuk menggunakan HashSet atau HashMap, akan tetapi
programmer harus kenal dengan tabel hash dan cara kerjanya.

Tabel hash merupakan solusi elegan untuk menyelesaikan masalah pencarian. Tabel hash, seperti
HashMap, menyimpan pasangan kunci/nilai. Jika kita mengetahui kuncinya, maka kita bisa
mencari nilainya di dalam tabel. Jika tabel hash digunakan untuk mengimplementasikan set,
maka semua nilainya berisi null. Kita masih harus mencari kuncinya di dalam tabel.

Dalam semua algoritma pencarian, untuk mencari suatu item, kita harus mencari item yang tidak
kita inginkan. Untuk mencari suatu item di dalam list tidak terurut, maka kita harus mengecek
isinya satu per satu hingga item yang kita cari ditemukan. Dalam pohon pencarian biner, kita
harus mulai dari akar dan turun ke bawah hingga item yang dicari ditemukan.

Jika kita mencari pasangan kunci/nilai dalam tabel hash, kita bisa langsung ke tempat di mana
item tersebut berada. Kita tidak perlu mencari item lainnya (Sebenarnya tidak sepenuhnya benar,
tapi kira-kira seperti ini). Lokasi di mana pasangan kunci/nilai ini berada dihitung dari kuncinya:
Kita hanya melihat kuncinya, dan kita bisa pergi ke lokasi di mana nilai tersebut disimpan secara
langsung.

Bagaimana caranya? Jika kuncinya adalah integer antara 0 hingga 99, kita bisa menyimpan
pasangan kunci/nilai dalam array A yang berisi 100 elemen. Pasangan kunci/nilai dengan kunci
N bisa disimpan dalam A[N]. Kunci ini akan membawa kita langsung ke pasangan kunci/nilai.

Masalahnya, ada banyak kemungkinan untuk suatu jenis kunci. Misalnya, jika kuncinya bertipe
int, maka kita perlu 4 milyar lokasi untuk menyimpan semua kuncinya dalam array -- tentunya
pemborosan memori yang sia-sia jika kita hanya ingin menyimpan katakan ribuan item saja. Jika
kuncinya berupa string dengan panjang yang tidak tentu, maka jumlah kemungkinan kuncinya
tidak terbatas, sehingga kita tidak mungkin menggunakan array untuk menyimpan semua
kemungkinan kuncinya.

Walau bagaimanapun, tabel hash menyimpan datanya dalam array. Indeks tidak sama dengan
kunci, akan tetapi indeks dihitung dari kunci. Indeks array dari hasil perhitungan kunci disebut
kode hash untuk kunci tersebut. Fungsi tertentu akan menghitung kode hash, yang disebut fungsi
hash. Untuk mencari kunci di dalam tabel hash, kita hanya pelu menghitung kode hash kunci
tersebut, kemudian langsung pergi ke lokasi array di ditunjuk oleh kode hash tersebut. Jika kode
hashnya 17, lihat langsung pada array nomor 17.

Sekarang, karena hanya ada lebih sedikit lokasi array dibandingkan kemungkinan kuncinya,
maka sangat mungkin kita memiliki situasi di mana satu lokasi array digunakan dua atau lebih
kunci. Hal ini disebut tabrakan (collision). Tabrakan bukan kesalahan. Kita tidak bisa menolak
suatu kunci karena memiliki kode hash yang sama dengan kunci lain. Tabel hash harus bisa
menangani tabrakan dengan cara yang baik.

Dalam tabel hash yang digunakan pada Java, setiap lokasi array sebetulnya adalah suatu list
berantai yang berisi pasangan kunci/nilai (atau mungkin juga list kosong). Jika dua item
memiliki kode hash yang sama, maka kedua item tersebut akan ada pada list yang sama.
Strukturnya bisa digambarkan sebagai berikut.
Pada gambar di atas, hanya ada satu item dengan kode hash 0, tidak ada item dengan kode hash
1, dua item dengan kode hash 2, dan seterusnya. Pada tabel hash yang dirancang dengan benar,
hampir semua list berantai berisi nol atau satu elemen saja, dengan rata-rata panjang list kurang
dari 1. Meskipun kode hash dari suatu kunci mungkin tidak membawa kita langsung pada kunci
yang kita mau, akan tetapi tidak akan lebih dari satu atau dua item yang harus kita cari sebelum
kita sampai pada item yang kita inginkan.

Agar bekerja dengan benar, jumlah item dalam tabel hash harus kurang dari besarnya array. Pada
Java, katika jumlah item melebihi 75% ukuran array, maka array tersebut akan diganti dengan
array yang lebih besar dan semua item pada array yang lama dipindahkan ke array baru.

Kelas Object memiliki metode bernama hashCode() yang mengembalikan nilai bertipe int.
Ketika objek obj disimpan dalam tabel yang berukuran N, maka kode hash antara 0 hingga N-1
diperlukan. Kode hash ini bisa dihitung dengan menggunakan Math.abs(obj.hashCode()) %
N, yaitu sisa pembagian dari nilai mutlak obj.hashCode() dengan N. (Nilai mutlak diperlukan
karena obj.hashCode() bisa bernilai negatif, dan kita tidak ingin nilai negatif sebagai indeks
array kita).

Supaya hash bisa bekerja dengan benar, dua objek yang sama menurut metode equals()
seharusnya memiliki kode hash yang sama. Dalam kelas Object metode equals() dan
hashCode() dihitung berdasarkan lokasi memori di mana objek tersebut disimpan. Akan tetapi
seperti disebutkan sebelumnya, banyak kelas yang memiliki metode equals() sendiri.

Jika suatu kelas memiliki metode equals() sendiri, dan jika objek tersebut akan digunakan
sebagai kunci pada tabel hash, maka kelas tersebut juga harus mendefinisikan metode
hashCode().
Misalnya dalam kelas String, metode equals() didefinisi ulang sehingga dua objek String
dianggap sama jika urutan karakter dalam String tersebut sama. Metode hashCOde() pada kelas
String itu juga didefinisi ulang sehingga kode hash dari string dihitung berdasarkan karakter di
dalam String, bukan lokasi memorinya.

Untuk kelas standar Java, kita bisa berharap bahwa metode equals() dan hashCode sudah
dibuat dengan benar, akan tetapi untuk kelas yang kita buat sendiri kita mungkin harus membuat
fungsi hash sendiri.

Bab X - Pengenalan Input/Output (I/O)


Posted Kam, 04/09/2009 - 18:22 by belajarprogram

Versi ramah cetak

Program komputer bisa berguna jika ia bisa berinteraksi dengan dunia lain. Interaksi di sini
maksudnya input/output atau I/O. Pada bab ini, kita akan melihat input output pada file dan
koneksi jaringan (network). Pada Java, input/output pada file dan jaringan dilakukan berdasarkan
aliran (stream), di mana semua objek dapat melakukan perintah I/O yang sama. Standar output
(System.out) dan standar input (System.in) adalah contoh aliran.

Untuk bekerja dengan file dan jaringan, kita membutuhkan pengetahuan tentang pengecualian,
yang telah dibahas sebelumnya. Banyak subrutin yang digunakan untuk bekerja dengan I/O
melemparkan pengecualian yang wajib ditangani. Artinya subrutin tersebut harus dipanggil di
dalam pernyataan try ... catch sehingga pengecualian yang terjadi bisa ditangani dengan
baik.

 Stream, Reader, dan Writer


 File
 Jaringan (network)
 Pemrograman Serentak (Concurrency)

Stream, Reader, dan Writer


Posted Kam, 04/09/2009 - 18:24 by belajarprogram

Versi ramah cetak

Tanpa bisa berinteraksi dengan dunia lain, suatu program tidak ada gunanya. Interaksi suatu
program dengan dunia lain sering disebut input/output atau I/O. Sejak dulu, salah satu tantangan
terbesar untuk mendesain bahasa pemrograman baru adalah mempersiapkan fasilitas untuk
melakukan input dan output. Komputer bisa terhubung dengan beragam jenis input dan output
dari berbagai perangkat. Jika bahasa pemrograman harus dibuat secara khusus untuk setiap jenis
perangkat, maka kompleksitasnya akan tak lagi bisa ditangani.
Salah satu kemajuan terbesar dalam sejarah pemrograman adalah adanya konsep (atau abstraksi)
untuk memodelkan perangkat I/O. Dalam Java, abstraksi ini disebut dengan aliran (stream).
Bagian ini akan memperkenalkan tentang aliran, akan tetapi tidak menjelaskan dengan komplit.
Untuk lebih lengkapnya, silakan lihat dokumen resmi Java.

Ketika berhubungan dengan input/output, kita harus ingat bahwa ada dua kategori data secara
umum : data yang dibuat oleh mesin, dan data yang bisa dibaca manusia. Data yang dibuat mesin
ditulis dengan model yang sama dengan bagaimana data tersebut disimpan di dalam komputer,
yaitu rangkaian nol dan satu. Data yang bisa dibaca manusia adalah data dalam bentuk rangkaian
huruf. Ketika kita membaca suatu bilangan 3.13159, kita membacanya sebagai rangkaian huruf
yang kita terjemahkan sebagai angka. Angka ini akan ditulis dalam komputer sebagai rangkaian
bit yang kita tidak mengerti.

Untuk menghadapi kedua jenis data ini, Java memiliki dua kategori besar untuk aliran : aliran
byte untuk data mesin (byte stream), dan aliran karakter (character stream) untuk data yang bisa
dibaca manusia. Ada banyak kelas yang diturunkan dari kedua kategori ini.

Setiap objek yang mengeluarkan data ke aliran byte masuk sebagai kelas turunan dari kelas
abstrak OutputStream. Objek yang membaca data dari aliran byte diturunkan dari kelas abstrak
InputStream. Jika kita menulis angka ke suatu OutputStream, kita tidak akan bisa membaca
data tersebut karena ditulis dalam bahasa mesin. Akan tetapi data tersebut bisa dibaca kembali
oleh InputStream. Proses baca tulis data akan menjadi sangat efisien, karena tidak ada
penerjemahan yang harus dilakukan : bit yang digunakan untuk menyimpan data di dalam
memori komputer hanya dikopi dari dan ke aliran tersebut.

Untuk membaca dan menulis data karakter yang bisa dimengerti manusia, kelas utamanya adalah
Reader dan Writer. Semua kelas aliran karakter merupakan kelas turunan dari salah satu dari
kelas abstrak ini. Jika suatu angka akan ditulis dalam aliran Writer, komputer harus bisa
menerjemahkannya ke dalam rangkaian karakter yang bisa dibaca maunsia.

Membaca angka dari aliran Reader menjadi variabel numerik juga harus diterjemahkan, dari
deretan karakter menjadi rangkaian bit yang dimengerti komputer. (Meskipun untuk data yang
terdiri dari karakter, seperti dari editor teks, masih akan ada beberapa terjemahan yang
dilakukan. Karakter disimpan dalam komputer dalam nilai Unicode 16-bit. Bagi orang yang
menggunakan alfabet biasa, data karakter biasanya disimpan dalam file dalam kode ASCII, yang
hanya menggunakan 8-bit. Kelas Reader dan Writer akan menangani perubahan dari 16-bit ke
8-bit dan sebaliknya, dan juga menangani alfabet lain yang digunakan negara lain.)

Adalah hal yang mudah untuk menentukan apakah kita harus menggunakan aliran byte atau
aliran karakter. Jika kita ingin data yang kita baca/tulis untuk bisa dibaca manusia, maka kita
gunakan aliran karakter. Jika tidak, gunakan aliran byte. System.in dan System.out sebenarnya
adalah aliran byte dan bukan aliran karakter, karenanya bisa menangani input selain alfabet,
misalnya tombol enter, tanda panah, escape, dsb.

Kelas aliran standar yang akan dibahas berikutnya didefinisikan dalam paket java.io beserta
beberapa kelas bantu lainnya. Kita harus mengimpor kelas-kelas tersebut dari paket ini jika kita
ingin menggunakannya dalam program kita. Artinya dengan menggunakan "import
java.io.*" di awal kode sumber kita.

Aliran tidak digunakan dalam GUI, karena GUI memiliki aliran I/O tersendiri. Akan tetapi kelas-
kelas ini digunakan juga untuk file atau komunikasi dalam jaringan. Atau bisa juga digunakan
untuk komunikasi antar thread yang sedang bekerja secara bersamaan. Dan juga ada kelas aliran
yang digunakan untuk membaca dan menulis data dari dan ke memori komputer.

 Operasi pada Aliran (Stream)


 Berbagai Jenis InputStream dan OutputStream

Operasi pada Aliran (Stream)


Posted Kam, 04/09/2009 - 21:03 by belajarprogram

Versi ramah cetak

Kelas dasar I/O Reader, Writer, InputStream dan OutputStream hanya menyediakan operasi
I/O sangat dasar. Misalnya, kelas InputStream memiliki metode instansi

public int read() throws IOException

untuk membaca satu byte data dari aliran input. Jika sampai pada akhir dari aliran input , metode
read() akan mengembalikan nilai -1. Jika ada kesalahan yang terjadi pada saat pengambilan
input, maka pengecualian IOException akan dilemparkan. Karena IOException adalah kelas
pengecualian yang harus ditangani, artinya kita harus menggunakan metode read() di dalam
penyataan try atau mengeset subrutin untuk throws IOException. (Lihat kembali pembahasan
tentang pengecualian di bab sebelumnya)

Kelas InputStream juga memiliki metode untuk membaca beberapa byte data dalam satu
langkah ke dalam array byte. Akan tetapi InputStream tidak memiliki metode untuk membaca
jenis data lain, seperti int atau double dari aliran. Ini bukan masalah karena dalam prakteknya
kita tidak akan menggunakan objek bertipe InputStream secara langsung. Yang akan kita
gunakan adalah kelas turunan dari InputStream yang memiliki beberapa metode input yang
lebih beragam daripada InputStream itu sendiri.

Begitu juga dengan kelas OutputStream memiliki metode output primitif untuk menulis satu
byte data ke aliran output, yaitu metode

public void write(int b) throws IOException

Tapi, kita hampir pasti akan menggunakan kelas turunannya yang mampu menangani operasi
yang lebih kompleks.

Kelas Reader dan Writer memiliki operasi dasar yang hampir sama, yaitu read dan write, akan
tetapi kelas ini berorientasi karakter (karena digunakan untuk membaca dan menulis data yang
bisa dibaca manusia). Artinya operasi baca tulis akan mengambil dan menulis nilai char bukan
byte. Dalam prakteknya kita akan menggunakan kelas turunan dari kelas-kelas dasar ini.

Salah satu hal menarik dari paket I/O pada Java adalah kemungkinan untuk menambah
kompleksitas suatu aliran dengan membungkus aliran tersebut dalam objek aliran lain. Objek
pembungkus ini juga berupa aliran, sehingga kita juga bisa melakukan baca tulis dari objek yang
sama dengan tambahan kemampuan dalam objek pembungkusnya.

Misalnya, PrintWriter adalah kelas turunan dari Writer yang memiliki metode tambahan
untuk menulis tipe data Java dalam karakter yang bisa dibaca manusial. Jika kita memiliki objek
bertipe Writer atau turunannya, dan kita ingin menggunakan metode pada PrintWriter untuk
menulis data, maka kita bisa membungkus objek Writer dalam objek PrintWriter.

Contoh jika baskomKarakter bertipe Writer, maka kita bisa membuat

PrintWriter printableBaskomKarakter = new PrintWriter(baskomKarakter);

Ketika kita menulis data ke printableBaskomKarakter dengan menggunakan metode pada


PrintWriter yang lebih canggih, maka data tersebut akan ditempatkan di tempat yang sama
dengan apabila kita menulis langsung pada baskomKarakter. Artinya kita hanya perlu membuat
antar muka yang lebih baik untuk aliran output yang sama. Atau dengan kata lain misalnya kita
bisa menggunakan PrintWriter untuk menulis file atau mengirim data pada jaringan.

Untuk lengkapnya, metode pada kelas PrintWriter memiliki metode sebagai berikut :

// Metode untuk menulis data dalam


// bentuk yang bisa dibaca manusia
public void print(String s)
public void print(char c)
public void print(int i)
public void print(long l)
public void print(float f)
public void print(double d)
public void print(boolean b)
 
// Menulis baris baru ke aliran
public void println()
 
// Metode ini sama dengan di atas
// akan tetapi keluarannya selalu
// ditambah dengan baris baru
public void println(String s)
public void println(char c)
public void println(int i)
public void println(long l)
public void println(float f)
public void println(double d
public void println(boolean b)
Catatan bahwa metode-metode di atas tidak pernah melempar pengecualian IOException. Akan
tetapi, kelas PrintWriter memiliki metode

public boolean checkError()

yang akan mengembalikan true jika ada kesalahan yang terjadi ketika menulis ke dalam aliran.
Kelas PrintWriter menangkap pengecualian IOException secara internal, dan mengeset nilai
tertentu di dalam kelas ini jika kesalahan telah terjadi. Sehingga kita bisa menggunakan metode
pada PrintWriter tanpa khawatir harus menangkap pengecualian yang mungkin terjadi. Akan
tetapi, jika kita ingin membuat progam yang tangguh tentunya kita harus selalu memanggil
checkError() untuk melihat apakah kesalahan telah terjadi ketika kita menggunakan salah satu
metode pada PrintWriter.

Ketika kita menggunakan metode PrintWriter untuk menulis data ke aliran, data tersebut
diubah menjadi rangkaian karakter yang bisa dibaca oleh manusia. Bagaimana caranya jika kita
ingin membuat data dalam bentuk bahasa mesin?

Paket java.io memiliki kelas aliran byte, yaitu DataOutputStream yang bisa digunakan untuk
menulis suatu data ke dalam aliran dalam format biner. DataOutputStream berhubungan erat
dengan OutputStream seperti hubungan antara PrintWriter dan Writer.

Artinya, OutputStream hanya berisi metode dasar untuk menulis byte, sedangkan
DataOutputStream memiliki metode writeDouble(double x) untuk menulis nilai double,
writeInt(int x) untuk menulis nilai int, dan seterusnya. Dan juga kita bisa membungkus
objek bertipe OutputStream atau turunannya ke dalam aliran DataOutputStream sehingga kita
bisa menggunakan metode yang lebih kompleks.

Misalnya, jika baskomByte adalah variabel bertipe OutputStream, maka

DataOutputStream baskomData = new DataOutputStream(baskomByte);

untuk membungkus baskomByte dalam baskomData.

Untuk mengambil data dari aliran, java.io memiliki kelas DataInputStream. Kita bisa
membungkus objek bertipe InputStream atau turunannya ke dalam objek bertipe
DataInputStream. Metode di dalam DataInputStream untuk membaca data biner bisa
menggunakan readDouble(), readInt() dan seterusnya. Data yang ditulis oleh
DataOutputStream dijamin untuk bisa dibaca kembali oleh DataInputStream, meskipun data
kita tulis pada satu komputer dan data dibaca pada komputer jenis lain dengan sistem operasi
berbeda. Kompatibilitas data biner pada Java adalah salah satu keunggulan Java untuk bisa
dijalakan pada beragam platform.

Salah satu fakta yang menyedihkan tentang Java adalah ternyata Java tidak memiliki kelas untuk
membaca data dalam bentuk yang bisa dibaca oleh manusia. Dalam hal ini Java tidak memiliki
kelas kebalikan dari PrintWriter sebagaimana DataOutputStream dan DataInputStream.
Akan tetapi kita tetap bisa membuat kelas ini sendiri dan menggunakannya dengan cara yang
persis sama dengan kelas-kelas di atas.

Kelas PrintWriter, DataInputStream, dan DataOutputStream memungkinkan kita untuk


melakukan input dan output semua tipe data primitif pada Java. Pertanyaannya bagaimana kita
melakukan baca tulis suatu objek?

Mungkin secara tradisional kita akan membuat fungsi sendiri untuk memformat objek kita
menjadi bentuk tertentu, misalnya urutan tipe primitif dalam bentuk biner atau karakter
kemudian disimpan dalam file atau dikirim melalui jaringan. Proses ini disebut serialisasi
(serializing) objek.

Pada inputnya, kita harus bisa membaca data yang diserialisasi ini sesuai dengan format yang
digunakan pada saat objek ini diserialisasi. Untuk objek kecil, pekerjaan semacam ini mungkin
bukan masalah besar. Akan tetapi untuk ukuran objek yang besar, hal ini tidak mudah.

Akan tetapi Java memiliki cara untuk melakukan input dan output isi objek secara otomatis,
yaitu dengan menggunakan ObjectInputStream dan ObjectOutputStream. Kelas-kelas ini
adalah kelas turunan dari InputStream dan OutputStream yang bisa digunakan untuk membaca
dan menulis objek yang sudah diserialisasi.

ObjectInputStream dan ObjectOutputStream adalah kelas yang bisa dibungkus oleh kelas
InputStream dan OutputStream lain. Artinya kita bisa melakukan input dan output objek pada
aliran byte apa saja.

Metde untuk objek I/O adalah readObject() yang tersedia pada ObjectInputStream dan
writeObject(Object obj) yang tersedia dalam ObjectOutputStream. Keduanya bisa
melemparkan IOException. Ingat bahwa readObject() mengembalikan nilai bertipe Object
yang artinya harus di-type cast ke tipe sesungguhnya.

ObjectInputStream dan ObjectOutputStream hanya bekerja untuk objek yang


mengimplementasikan interface yang bernama Serializable. Lbih jauh semua variabel instansi
pada objek harus bisa diserialisasi, karena interface Serializable tidak mempunyai metode
apa-apa. Interface ini ada hanya sebagai penanda untuk kompiler supaya kompiler tahu bahwa
objek ini digunakan untuk baca tulis ke suatu media.

Yang perlu kita lakukan adalah menambahkan "implements Serializable" pada definisi
kelas. Banyak kelas standar Java yang telah dideklarasikan untuk bisa diserialisasi, termasuk
semua komponen kelas Swing dan AWT. Artinya komponen GUI pun bisa disimpan dan dibaca
dari dalam perangkat I/O menggunakan ObjectInputStream dan ObjectOutputStream.
Berbagai Jenis InputStream dan OutputStream
Posted Min, 04/12/2009 - 22:16 by belajarprogram

Versi ramah cetak

InputStream

Beberapa kelas turunan dari InputStream dapat dirangkum dalam tabel di bawah ini :

Argumen yang dibutuhkan untuk


Kelas  Kegunaan 
membuat objek

Menggunakan buffer pada memori Buffer yang akan digunakan sebagai


ByteArrayInputStream
sebagai aliran input aliran input

Suatu String (di dalamnya


StringBufferInputStream
Mengubah string menjadi
sebenarnya menggunakan
InputStream
StringBuffer)

String yang berupa nama suatu


Untuk membaca informasi dari
FileInputStream file, atau objek bertipe File atau
dalam file
FileDescriptor

Menghasilkan data yang ditulis oleh


PipedOutputStream.
PipedInputStream Mengimplementasi konsep "piping". Objek PipedOutputStream
Bisa digunakan untuk multi-
threading

Dua atau lebih objek bertipe


Menggabungkan dua atau lebih InputStream atau kontainer
SequenceInputStream InputStream menjadi satu bertipe Enumeration yang berisi
InputStream InputStream yang akan
digabungkan

Kelas abstrak yang merupakan


interface dari beberapa kelas bantu
FilterInputStream  
untuk menggunakan InputStream
lain

FilterInputStream adalah lapisan di atas InputStream yang berguna untuk memberi landasan
pada kelas-kelas dekorator di atas. Kenapa dekorator? Karena kelas-kelas ini hanya memberikan
fungsionalitas tambahan, akan tetapi tidak mengubah bagaimana I/O itu sendiri bekerja. Seperti
disebutkan sebelumnya, bahwa kelas dasar InputStream dan OutputStream hanya memiliki
metode-metode paling sederhana. Kelas-kelas ini memperbanyak metode baca/tulis untuk
kemudahan pemrograman.

Kelas FilterInputStream sendiri terdiri dari beberapa jenis, yang bisa dirangkum dalam tabel
berikut ini :

Argumen yang
Kelas Kegunaan dibutuhkan untuk
membuat objek

Digunakan bersama-sama dengan


DataOutputStream sehingga kita bisa menulis
DataInputStream InputStream
tipe data primitif, kemudian membacanya kembali
tanpa harus diformat sendiri

Digunakan untuk menghindari pembacaan InputStream dengan


langsung dari media secara fisik setiap kali kemungkinan
BufferedInputStream
perintah read() diberikan. Atau dengan kata lain menentukan besar
"gunakan buffer" untuk baca tulis buffer sendiri

Mencatat nomor baris dalam InputStream. Kita


LineNumberInputStream bisa menggunakan perintah getLineNumber() InputStream
dan setLineNumber(int)

Memiliki satu byte buffer sehingga kita bisa


PushBackInputStream meletakkan kembali karakter yang sudah diambil InputStream
(dibaca)

OutputStream

Beberapa kelas turunan dari OutputStream dapat dirangkum dalam tabel di bawah ini :

Argumen yang dibutuhkan


Kelas  Kegunaan 
untuk membuat objek

Membuat buffer dalam memori. Semua Opsional untuk memberikan


ByteArrayOutputStream data yang kita kirim akan disimpan di besar buffer yang akan
memori ini. disiapkan

String yang berupa nama


FileOutputStream Untuk menulis informasi ke dalam file suatu file, atau objek bertipe
File atau FileDescriptor
Informasi yang kita kirim di aliran output ini
akan berakhir pada objek bertipe
PipedOutputStream PipedInputStream. Mengimplementasi Objek PipedInputStream
konsep "piping". Bisa digunakan untuk
multi-threading

Kelas abstrak yang merupakan interface


FilterOutputStream dari beberapa kelas bantu untuk  
menggunakan OutputStream lain.

Kelas FilterOutputStream sendiri terdiri dari beberapa jenis, yang bisa dirangkum dalam tabel
berikut ini :

Argumen yang dibutuhkan


Kelas Kegunaan
untuk membuat objek

Digunakan bersama-sama dengan


DataInputStream sehingga kita bisa menulis
DataOutputStream OutputStream
tipe data primitif, kemudian membacanya
kembali tanpa harus diformat sendiri

Untuk mengeluarkan output yang sudah OutputStream dengan


diformat. DataOutputStream hanya tambahan opsi boolean
menangani bagaimana data disimpan sehingga untuk memerintahkan
PrintStream
bisa diambil kembali. PrintStream lebih buffer akan dikosongkan
berkonsentrasi pada "tampilan", sehingga data (flush) setiap kali baris baru
yang ditulis bisa dibaca dengan baik. ditulis.

Digunakan untuk menghindari penulisan


langsung dari media secara fisik setiap kali
perintah write() diberikan. Atau dengan kata OutputStream dengan
BufferedOutputStream lain "gunakan buffer" untuk baca tulis. Kita bisa kemungkinan menentukan
menggunakan perintah flush() untuk besar buffer sendiri
mengosongkan buffer dan mengirimkan
hasilnya ke media fisik.

File
Posted Min, 04/12/2009 - 16:13 by belajarprogram

Versi ramah cetak


Data dan program pada memori komputer hanya bisa bertahan selama komputer itu nyala. Untuk
tempat penyimpanan yang lebih lama, komputer menggunakan file, yaitu kumpulan data yang
disimpan dalam hard disk, disket atau CD-ROM, USB stick, dan lain-lain. File disusun dalam
direktori (atau sering juga disebut folder). Direktori bisa terdiri dari direktori lain atau file lain.
Nama direktori dan file digunakan untuk mencari suatu file dalam komputer.

Program dapat membaca data dari file yang sudah ada. Program juga bisa membuat file baru atau
menulis data ke dalam file yang sudah ada. Dalam Java, input dan output seperti ini bisa
menggunakan aliran (stream). Data karakter yang bisa dibaca manusial dapat dibaca dari file
dengan menggunakan objek dari kelas FileReader yang merupakan kelas turunan Reader. Data
bisa ditulis dalam bentuk yang bisa dibaca manusia dengan menggunakan FileWriter yang
merupakan kelas turunan dari Writer.

Untuk membaca atau menyimpan suatu file dalam format mesin, kelas I/O-nya adalah
FileInputStream dan FileOutputStream. Semua kelas ini didefinisikan dalam paket java.io.

Perlu dicatat bahwa applet yang didownload dari suatu jaringan pada umumnya tidak bisa
mengakses file karena pertimbangan keamanan. Kita bisa mendownload dan menjalankan applet,
yaitu dengan mengunjungi halaman web pada browser kita. Jika applet tersebut bisa digunakan
untuk mengakses file pada komputer kita, maka orang bisa membuat applet untuk menghapus
semua file dalam komputer yang mendownloadnya.

Untuk mencegah hal seperti itu, ada beberapa hal di mana applet yang didownload tidak bisa
lakukan. Mengakses file adalah salah satu hal yang dilarang. Akan tetapi program desktop bisa
memiliki akses ke file kita seperti program-program lainnya. Program desktop bisa melakukan
akses file yang dijelaskan pada bagian ini.

Kelas FileReader memiliki konstruktor yang mengambil nama file sebagai parameternya,
kemudian membuat aliran input yang bisa digunakan untuk membaca file tersebut. Konstruktor
ini akan melemparkan pengecualian bertipe FileNotFoundException jika file tersebut tidak
ditemukan.

Jenis pengecualian seperti ini membutuhkan penanganan wajib, sehingga kita harus memanggil
konstruktor di dalam pernyataan try atau menambahkan pernyataan throw di kepala subrutin
yang menjalankan konstruktor tersebut. Milsanya, anggap kita memiliki file bernama
"data.txt", dan kita ingin membuat program untuk membaca data pada file tersebut. Kita bisa
menggunakan pernyataan berikut untuk membaca aliran input dari file tersebut :

// (Mendeklarasikan variabel sebelum pernyataan try


// jika tidak, maka variabel tersebut hanya bisa
// dilihat di dalam blok try, dan kita tidak bisa
// menggunakannya lagi di bagian program lain
FileReader data;
 
try {
// buat aliran input
data = new FileReader("data.txt");
}
catch (FileNotFoundException e) {
... // lakukan sesuatu untuk menangani kesalahan
}

Kelas FileNotFoundException merupakan kelas turunan dari IOException, sehingga kita bisa
menangkap IOException pada pernyataan try...catch di atas. Secara umum, hampir semua
kesalahan yang terjadi pada saat operasi input/output dapat ditangkap dengan pernyataan catch
yang menangani IOException.

Begitu kita berhasil membuat FileReader, kita bisa mulai membacanya. Tapi karena
FileReader hanya memiliki metode input primitif dari standar kelas Reader, kita mungkin akan
perlu membungkusnya dalam objek lain, misalnya BufferedReader atau kelas pembungkus lain.
Untuk membuat BufferedReader untuk membaca file bernama "data.dat", kita bisa gunakan :

TextReader data;
try {
data = new BufferedReader(new FileReader("data.dat"));
}
catch (FileNotFoundException e) {
... // tangani pengecualian
}

BufferedReader memiliki metode bantu untuk mengambil data per baris dengan perintah
readline(). Sehingga apabila satu data ditulis dalam urutan per baris, kita bisa gunakan
perintah Double.parseDouble(string) atau Integer.parseInt(string) untuk mengubahnya menjadi
double atau int.

Untuk menyimpan data tidaklah lebih sulit dari ini. Kita bisa membuat objek bertipe
FileWriter. Dan kemudian kita mungkin ingin membungkus aliran output ini dalam objek
PrintWriter. Misalnya, kita ingin menyimpan data ke file yang bernama "hasil.dat", kita bisa
menggunakan :

PrintWriter result;
 
try {
keluaran = new PrintWriter(new FileWriter("hasil.dat"));
}
catch (IOException e) {
... // tangani pengecualian
}

Jika tidak ada file bernama "hasil.dat", maka file baru akan dibuat. Jika file sudah ada, maka
isinya akan dihapus dan diganti dengan data yang ditulis oleh program kita. Pengecualian
IOException bisa terjadi jika, misalnya, file tersebut sedang dibaca oleh program lain, sehingga
sistem operasi menolak program kita untuk menulisnya pada saat yang sama.
Setelah kita selesai menggunakan file, sebaiknya anda menutup file tersebut, atau mengatakan
kepada sistem operasi bahwa kita telah selesai menggunakan file itu (Jika kita lupa, sistem
operasi akan menutup file secara otomatis setelah program selesai dijalankan atau objek aliran
file diambil oleh pemulung memori, akan tetapi akan sangat baik jika kita menutup file secara
manual untuk menghindari kemungkinan lainnya).

Kita bisa menutup file dengan menggunakan metode close() pada aliran tersebut. Setelah file
telah ditutup, maka kita tidak mungkin lagi membaca atau menulis data dari atau ke file tersebut.
Kita harus membukanya kembali. (Perlu dicatat bahwa penutupan file juga bisa melemparkan
pengecualian IOException yang wajib ditangani, akan tetapi PrintWriter menangani
pengecualian tersebut secara otomatis sehingga kita tidak perlu menanganinya lagi).

Sebagai contoh komplit, berikut ini adalah program yang akan membaca angka dari file bernama
"data.dat", dan kemudian menuliskannya kembali dalam urutan terbalik ke dalam file yang
bernama "hasil.dat". Dalam file tersebut hanya akan ada satu angka untuk setiap barisnya dan
diasumsikan tidak ada lebih dari 1000 angka sekaligus. Penanganan pengecualian digunakan
untuk mengecek apakah ada masalah di tengah operasi. Meskipun mungkin tidak begitu berguna
untuk aplikasi sungguhan, akan tetapi program ini mendemonstrasikan bagaimana menggunakan
operasi baca tulis sederhana pada file.

package balikfile;
 
import java.io.*;
 
public class BalikFile {
 
/**
* @param args
*/
public static void main(String[] args) {
BufferedReader data; // Aliran input karakter untuk membaca data
PrintWriter hasil; // Aliran output karakter untuk menulis data
 
// Array untuk menampung semua angka dari dalam file
double[] angka = new double[1000];
 
int banyakAngka; // Banyaknya angka yg disimpan dlm array
 
try { // Buat aliran input
data = new BufferedReader(new FileReader("data.dat"));
}
catch (FileNotFoundException e) {
System.out.println("Tidak bisa menemukan data.dat!");
return; // akhiri program
}
 
try { // Membuat aliran output
hasil = new PrintWriter(new FileWriter("hasil.dat"));
}
catch (IOException e) {
System.out.println("Tidak bisa membuka hasil.dat!");
System.out.println(e.toString());
try {
data.close(); // Tutup file input
}
catch (IOException f) {
System.out.println("Tidak bisa menutup data.dat");
}
return; // End the program.
}
 
String baris = null; // variabel untuk menyimpan satu baris teks
 
try {
// Baca data dari file input
banyakAngka = 0;
while ((baris = data.readLine()) != null) { // baca hingga
habis
angka[banyakAngka] = Double.parseDouble(baris);
banyakAngka++;
}
 
// Tulis hasilnya dalam urutan terbalik
for (int i = banyakAngka-1; i >= 0; i--)
hasil.println(angka[i]);
 
System.out.println("Selesai!");
 
}
catch (IOException e) {
// Ada masalah dengan pembacaan/penulisan file
System.out.println("Kesalahan baca/tulis");
}
catch (NumberFormatException e) {
// Ada masalah dengan format angka dalam file
System.out.println("Kesalahan format: " + e.getMessage());
}
catch (IndexOutOfBoundsException e) {
// Tidak boleh meletakkan 1000 angka dalam file
System.out.println("Terlalu banyak angka.");
System.out.println("Penulisan dihentikan.");
}
finally {
// Akhiri dengan menutup semua file apapun yang terjadi
try {
data.close(); // Tutup file input
}
catch (IOException e) {
System.out.println("Tidak bisa menutup data.dat");
}
hasil.close(); // Tutup file output
}
}
}

Berikut ini adalah program lengkapnya yang bisa diimport ke dalam Eclipse beserta contoh file
data.dat.
Setelah selesai dijalankan file baru akan dibuat hasil.dat yang bisa Anda double-click untuk
melihat hasilnya

Sisipan Ukuran

Sisipan Ukuran

BalikFile-src.zip 1.82 KB

 Nama File, Direktori, dan Kelas File


 Mengkopi File

Nama File, Direktori, dan Kelas File


Posted Sen, 04/13/2009 - 02:26 by belajarprogram

Versi ramah cetak

Topik tentang nama file sebenarnya lebih kompleks daripada yang telah kita bahas. Untuk
menunjuk pada sebuah file, kita harus memberikan bukan hanya nama file, tapi juga nama
direktori di mana file tersebut disimpan. Nama file sederhana seperti "data.dat" atau "hasil.dat"
diambil dengan mengacu pada direktori sekarang (current directory, atau juga disebut direktori
kerja). Pada program di bagian sebelumnya, hasil.dat disimpan pada direktori yang sama dengan
direktori utama pada proyek balikfile.

File yang tidak diletakkan pada direktori kerja harus diberikan nama "path", atau nama lengkap
termasuk nama direktorinya. Untuk memperjelas lagi, ada dua jenis nama path, yaitu nama path
absolut dan nama path relatif. Nama path absolut memiliki informasi lengkap dari akar
direktorinya, misalnya "C:\workspace\balikfile\data.dat". Sedangkan nama path relatif adalah
nama file yang dihitung mulai dari direktori aktifnya.
Sayangnya, sintaks untuk nama path dan file bervariasi dari satu sistem ke sistem lain. Misalnya
"

 data.dat -- pada komputer apapun, yaitu file data.dat pada direktori aktif.
 /home/lyracc/java/contoh/data.dat -- Nama path absolut pada sistem operasi LINUX atau UNIX.
Mengacu pada file bernama data.dat di direktori yang ditunjuk.
 C:\lyracc\java\contoh\data.dat -- Nama path absolut pada DOS atau Windows
 Hard Drive:java:contoh:data.dat -- Misalnya "Hard Drive" adalah nama dari drivenya, maka ini
adalah nama path absolut pada Macintosh OS 9
 contoh/data.dat -- nama path relatif pada LINUX atau UNIX. "contoh" adalah nama direktori
yang terdapat pada direktori aktif, dan data.dat adalah file dalam direktori tersebut. Pada
Windows, nama path relatifnya menjadi contoh\data.dat dan pada Macintosh menjadi
contoh:data.dat.

Untuk mencegah berbagai masalah yang mungkin muncul karena beragam sistem ini, Java
memiliki kelas bernama java.io.File. Objek bertipe kelas ini melambangkan suatu file. Lebih
tepatnya, objek bertipe File melambangkan nama file, bukan file itu sendiri. Nama yang
ditunjuk belum tentu ada. Direktori juga dianggap Java sebagai File, sehingga File juga
melambangkan nama direktori sekaligus nama file.

Objek File memiliki konstruktor new File(String) yang akan membuat objek File dari
namanya. Nama tersebut bisa nama sederhana, nama path relatif, atau nama path absolut.
Misalnya new File("data.dat") membuat objek File dari file bernama data.dat di direktori
aktif.

Konstruktor lain memiliki konstruktor new File(File,String), di mana parameter pertama


adalah direktori di mana file tersebut berada, dan parameter kedua adalah nama filenya.

Objek File memiliki beberapa metode instansi. Misalnya file adalah variabel bertipe File,
berikut ini adalah beberapa metodenya :

 file.exists() -- mengembalikan nilai boolean, yang jika true maka file tersebut ada. Kita
bisa menggunakan perintah ini misalnya untuk mencegah menulis file yang sama ketika kita
membuka objek FileWriter baru.
 file.isDirectory() -- mengembalikan nilai boolean yang mengembalikan true jika objek
File adalah suatu direktori, dan false jika File adalah file biasa, atau tidak ada file dengan
nama tersebut.
 file.delete() -- menghapus file jika ada
 file.list() -- jika objek File adalah suatu direktori, maka fungsi ini mengembalikan array
bertipe String[] yang berisi nama-nama file pada direktori tersebut. Jika tidak, maka
kembaliannya adalah null.

Berikut ini adalah contoh program yang menulis isi file di dalam direktori yang diinput dari
user :

package daftardirektori;
 
import java.io.*;
 
public class DaftarDirektori {
 
/* Program ini mengembalikan isi suatu direktori
* User memasukkan direktori yang ingin dilihat
* Jika direktori tidak ada, maka pesan kesalahan
* akan ditulis dan program akan berhenti
*/
 
public static void main(String[] args) {
 
String namaDirektori = null; // Nama direktori dari user
File direktori; // objek File yang mengacu pada direktori
String[] isiFile; // Array berisi file pada direktori
 
// buat objek baru untuk mengambil input
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
 
System.out.print("Masukkan nama direktori : ");
try {
namaDirektori = br.readLine();
} catch(IOException ioe) {
System.out.println("Kesalahan IO terjadi");
System.exit(1);
}
 
direktori = new File(namaDirektori);
 
if (direktori.isDirectory() == false) {
if (direktori.exists() == false)
System.out.println("Tidak ada direktori ini!");
else
System.out.println("Ini bukan direktori.");
}
else {
isiFile = direktori.list();
System.out.println("Files dalam direktori \"" + direktori +
"\":");
for (int i = 0; i < isiFile.length; i++)
System.out.println(" " + isiFile[i]);
}
 
}
 
}

Berikut ini adalah program lengkapnya yang bisa diimport ke dalam Eclipse. Ini adalah hasil
keluarannya :
Semua kelas yang digunakan untuk memaca dan menulis data dari dan ke dalam file memiliki
konstruktor yang bisa mengambil objek File sebagai parameternya. Misalnya, jika file adalah
variabel bertipe File, dan kita ingin mengambil karakter dari file tersebut, maka kita bisa
membuat FileReader untuk melakukannya dengan menggunakan new FileReader(file).

Mengkopi File
Posted Sen, 04/13/2009 - 14:08 by belajarprogram

Versi ramah cetak

Mengkopi suatu file adalah operasi biasa, dan sistem operasi manapun memiliki perintah atau
cara untuk melakukannya. Akan tetapi kita juga bisa membuat program Java untuk
melakukannya.

Karena program harus bisa mengkopi file jenis apapun, kita tidak bisa menganggap data di
dalam file adalah data yang bisa dibaca manusia. File lagu atau video misalnya berisi deretan
byte yang merupakan representasi digital dari lagu atau video tersebut.

Oleh karena itu kita harus menggunakan InputStream dan OutputStream untuk melakukan
operasi baca tulis yang bisa menangani data biner, bukan Reader dan Writer yang hanya bisa
menangani data yang bisa dibaca manusia.

Program yang kita buat akan mengkopi beberapa byte sekaligus dari InputStream ke
OutputStream, akan tetapi kita membutuhkan tempat sementara di mana data tersebut akan
ditempatkan sebelum data tersebut ditulis kembali pada OutputStream. Tempat sementara
tersebut disebut buffer yang merupakan array berukuran tertentu, misalnya 4096 byte (atau 4 kilo
byte).
Jika sumber adalah variabel bertipe InputStream, maka byteTerbaca =
sumber.read(buffer) akan mengisi penuh buffer. Metode ini mengembalikan int yang
merupakan berapa byte yang efektif diambil oleh sumber, kemudian diletakkan dalam variabel
byteTerbaca. Jika hasilnya -1, berarti tidak ada lagi data yang bisa diambil dari dalam sumber.

Begitu juga jika kopi adalah keluaran yang bertipe OutputStream maka kopi.write(buffer,
0, byteTerbaca) menulis deretan byte dari buffer dari posisi 0 hingga byteTerbaca ke aliran
keluaran kopi.

Sehingga secara umum perintah-perintah di atas dapat dirangkum menjadi :

byte[] buffer = new byte[4096];


int byteTerbaca;
 
while((byteTerbaca = sumber.read(buffer)) != -1)
kopi.write(buffer, 0, byteTerbaca);

Perintah kopi-file pada sistem operasi baik DOS/Windows atau LINUX/UNIX menggunakan
perintah pada konsol yang menambahkan file sumber dan file tujuannya. Misalnya, pada konsol
Windows, kita bisa menggunakan "copy awal.dat akhir.dat" untuk mengkopi file awal.dat
ke file bernama akhir.dat.

Tambahan parameter pada konsol ini disebut argumen baris perintah. Argumen baris perintah ini
bisa juga digunakan dalam program Java. Dalam Java argumen baris perintah ini diisi dalam
array String[] bernama args, yang kemudian dimasukkan sebagai parameter dalam subrutin
main(). Ingat bagaimana "biasanya" subrutin main() dideklarasikan sebagai public static
void main(String[] args).

Pada program Java yang sudah dikompilasi, kita bisa memanggilnya dengan "java KopiFile
awal.dat akhir.dat" jika KopiFile adalah nama kelas yang akan kita buat untuk mengkopi
file. args[0] akan berisi awal.dat sedangkan args[1] akan berisi akhir.dat.

Program yang akan kita buat menerima input dari baris perintah. Kemudian program akan
mengecek apakah kedua parameter tersebut berisi nama file dengan benar. Jika salah satu
parameternya kosong, maka program akan menampilkan pesan kesalahan. Program juga akan
mengecek apakah akhir.dat merupakan file yang sudah ada sebelumnya, kemudian memberi
pertanyaan kepada user apakah isi file ini ingin ditindih dengan isi file awal.dat. Jika ya, maka
operasi akan diteruskan, jika tidak maka program akan dihentikan.

Berikut ini adalah listing lengkap program KopiFile, yang bisa diunduh di sini dan diimport ke
dalam Eclipse.

import java.io.*;
 
public class KopiFile {
 
/**
* @param args
*/
public static void main(String[] args) {
// Mengecek apakah argumen program cukup untuk meneruskan program
// Dibutuhkan dua argumen, yaitu sumberFile dan tujuanFile
if (args.length < 2) {
System.out.println("Cara menjalankan program : " +
"java KopiFile sumberFile tujuanFile");
return;
}
 
String sumberNamaFile = args[0];
String tujuanNamaFile = args[1];
 
File sumberFile = new File(sumberNamaFile);
File kopiFile = new File(tujuanNamaFile);
 
// Jika kopi file sudah ada, kita akan tanyakan apakah file tujuan
// akan ditimpa
if (kopiFile.exists()) {
// buat objek baru untuk mengambil input
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String timpaFile = null;
 
System.out.print("Apakah Anda ingin menimpa " + tujuanNamaFile + "
? (y/t) ");
try {
timpaFile = br.readLine();
} catch(IOException ioe) {
System.out.println("Kesalahan IO terjadi");
System.exit(1);
}
 
// jika jawabannya tidak, hentikan program
if (timpaFile.equalsIgnoreCase("t"))
return;
}
 
// Di sini kita siap untuk mengkopi file
// Buat aliran input dan output
FileInputStream sumber = null;
try {
sumber = new FileInputStream(sumberFile);
} catch (FileNotFoundException e) {
System.out.println("File sumber tidak ada, berupa direktori " +
"atau tidak bisa dibuka, program dihentikan!");
return;
}
 
FileOutputStream kopi = null;
try {
kopi = new FileOutputStream(tujuanNamaFile);
} catch (FileNotFoundException e) {
System.out.println("File tujuan tidak valid atau tidak bisa
ditulis, " +
"program dihentikan!");
return;
}
 
byte[] buffer = new byte[4096];
int byteTerbaca;
 
try {
while((byteTerbaca = sumber.read(buffer)) != -1)
kopi.write(buffer, 0, byteTerbaca);
} catch (IOException e) {
System.out.println("Ada masalah di tengah pengkopian program");
return;
}
 
System.out.println("Kopi file selesai dijalankan!");
}
 
}

Perlu diingat bahwa program ini tidak bisa dijalankan lewat Eclipse. Jika Anda mencoba
menjalankan lewat Eclipse, maka tampilan kesalahan akan muncul, karena tidak ada parameter
yang diberikan.

Untuk menjalankan program, Anda harus membuka konsol pada Windows dengan Start -> Run
-> kemudian ketik cmd dan enter. Setelah itu pergi ke direktori tempat proyek Anda berada pada
Eclipse. Misalnya pada komputer saya, saya meletakkan semua proyek Eclipse pada
c:\belajarjava.lyracc.com\KopiFile. Di dalamnya seharusnya Anda akan menemui 2
direktori, yaitu src dan bin. src adalah tempat di mana kode sumber berada, sedangkan bin
adalah tempat dimana hasil kompilasi berada. Eclipse akan melakukan kompilasi secara
otomatis.

Berikut screenshot hasil jalannya program. Di sini saya mengkopi file dari
c:\belajarjava.lyracc.com\KopiFile\src\KopiFile.java ke
c:\belajarjava.lyracc.com\Kopi123.java.
Jaringan (network)
Posted Sen, 04/13/2009 - 16:13 by belajarprogram

Versi ramah cetak

Dalam pemrograman, jaringan (network) hanyalah salah satu jenis dari input di mana data bisa
diambil, dan output di mana data bisa dikirim. Konsep ini mempermudah pemahaman kita
tentang pemrograman dalam jaringan, akan tetapi ada beberapa hal lain yang harus diperhatikan
sehingga pemrograman pada jaringan dapat berhasil dengan baik.

Pada Java, kita bisa menggunakan aliran input dan output untuk melakukan komunikasi pada
network, seperti halnya pada file. Akan tetapi membuat koneksi jaringan antara dua komputer
sedikit lebih rumit, karena ada dua komputer yang berbeda, yang keduanya harus setuju
membuka koneksi. Dan ketika data dikirimkan dari satu komputer ke komputer lain, komunikasi
harus dilakukan seirama sehingga data yang dikirimkan akan sampai ke komputer yang lain.

Salah satu paket Java standar adalah java.net. Paket ini memiliki beberapa kelas yang bisa
digunakan untuk berkomunikasi melalui jaringan. Dua jenis I/O network disediakan dalam paket
ini. Yang pertama, yang lebih tinggi tingkatannya, berdasarkan pada Web dan memberikan
fasilitas komunikasi seperti halnya web browser ketika mendownload suatu halaman web untuk
kemudian ditampilkan. Kelas utama dalam jenis network seperti ini adalah java.net.URL dan
java.net.URLConnection. Suatu objek bertipe URL adalah lambang abstrak dari sebuah URL
(Universal Resource Locator), yaitu alamat web di mana dokumen HTML atau lainnya bisa
ditemukan pada web. Sedangkan URLConnection adalah koneksi network ke dokumen tadi.
Jenis I/O kedua adalah melihat jaringan pada tingkatan yang lebih rendah, yaitu berdasarkan ide
suatu soket (socket). Soket digunakan oleh program untuk melakukan koneksi dengan program
lain pada suatu jaringan. Komunikasi melalui network melibatkan dua soket, yaitu masing-
masing pada setiap komputer. Java memiliki kelas java.net.Socket untuk merepresentasikan
suatu soket yang digunakan dalam komunikasi network.

Istilah "soket" mungkin mirip dengan colokan kabel data (misalnya) modem, akan tetapi penting
untuk diingat bahwa soket adalah objek bertipe Socket. Artinya program bisa memiliki
beberapa soket dalam waktu yang sama, yang masing-masing terhubung ke program yang
dijalankan pada komputer lain. Semuanya menggunakan koneksi network yang sama dari satu
kabel.

Bagian ini akan memberikan pengenalan tentang kelas-kelas dasar jaringan, dan bagaimana
hubungannya dengan aliran input dan ouput serta pengecualian.

 URL dan URLConnection


 Soket, Klien, dan Server
 Contoh Pemrograman pada Jaringan

URL dan URLConnection


Posted Sel, 04/21/2009 - 16:27 by belajarprogram

Versi ramah cetak

Kelas URL digunakan untuk merepresentasikan suatu sumber pada Web. Setiap sumber memiliki
alamat, yang unik (tidak bisa sama), dan memiliki informasi yang cukup sehingga web browser
bisa mencari sumber tersebut dan mengambilnya. Alamat ini disebut "url" atau "universal
resource locator".

Suatu objek beritpe kelas URL melambangkan alamat tersebut. Jika kita sudah memiliki objek
bertipe URL, maka kita bisa membuka URLConnection ke alamat tersebut. Suatu url biasanya
berupa string, misalnya "http://java.lyracc.com/belajar/java-untuk-pemula/bab-i-
pendahuluan". Ada juga yang disebut url relatif. URL relatif adalah lokasi suatu sumber relatif
terhadap url lain, yang biasanya disebut landasan (base) atau konteks (context) dari url relatif
tersebut. Misalnya jika konteksnya adalah http://java.lyracc.com/belajar/java-untuk-
pemula/ maka url relatif dari "bab-i-pendahuluan" akan menunjuk pada
http://java.lyracc.com/belajar/java-untuk-pemula/bab-i-pendahuluan.

Suatu objek bertipe URL bukan string sederhana, akan tetapi dibangun dari kumpulan string yang
membentuk suatu url. Objek URL juga bisa dibuat dari objek URL lain, yang merupakan
konteksnya, dan string lain yang berisi relatif urlnya. Konstruktornya memiliki bentuk seperti :

public URL(String alamatURL) throws MalformedURLException

dan
public URL(URL konteks, String alamatRelatif) throws MalformedURLException

Lihat bahwa kedua konstruktor akan melempar pengecualian bertipe MalformedURLException


jika string yang diberikan bukan nama url legal. Kelas MalformedURLException merupakan
kelas turunan dari IOException yang wajib ditangani, sehingga konstruktor di atas harus
dipanggil dalam pernyataan try ... catch atau ditulis di dalam subrutin yang melempar
pengecualian ini.

Konstruktur jenis kedua akan lebih nyaman digunakan untuk applet. Dalam applet, tersedia dua
metode yang bisa digunakan untuk mengambil konteks URL. Metode getDocumentBase() pada
kelas Applet mengembalikan objek bertipe URL. Objek URL ini adalah lokasi tempat halaman
HTML yang berisi applet tersebut berada. Dengan ini, kita bisa memerintahkan applet untuk
kembali dan mengambil file lain yang disimpan di tempat yang sama. Misalnya,

URL url = new URL(getDocumentBase(), "data.txt");

membuat URL baru yang merujuk pada file bernama data.txt pada komputer yang sama dan
pada direktori yang sama pada halaman web di mana applet tersebut sedang berjalan.

Metode lainnya, yaitu getCodeBase(), mengembalikan URL yang merupakan lokasi di mana
applet tersebut berada (belum tentu sama dengan lokasi HTML-nya).

Setelah kita memiliki objek URL yang benar, kita bisa memanggil openConnection() untuk
membuka koneksi pada URL tersebut. Metode ini mengembalikan objek bertipe URLConnection.
Objek URLConnection bisa digunakan untuk membuka InputStream untuk membaca halaman
atau file pada alamat URL tersebut, yaitu dengan menggunakan metode getInputStream().
Misalnya :

URL url = new URL(alamatURL);


URLConnection koneksi = url.openConnection();
InputStream dataURL = connection.getInputStream();

Metode openConnection() dan getInputStream dapat melempar pengecualian IOException.


Jika InputStream berhasil dibuka, kita bisa menggunakannya dengan cara biasa, termasuk
membungkusnya dalam aliran input jenis lain, misalnya BufferedReader. Membaca dari aliran
ini tentunya juga bisa melemparkan pengecualian.

Salah satu metode instansi yang berguna dalam kelas URLConnection adalah
getContentType(), yang mengembalikan String yang menjelaskan jenis informasi pada URL
yang ditunjuk. Hasilnya bisa bernilai null jika jenisnya belum diketahui, atau tidak bisa
ditentukan. Jenis dokumen bisa saja belum tersedia hingga aliran input berhasil dibuat, sehingga
lebih baik menggunakan getContentType() setelah getInputStream() berhasil dilakukan.

String yang dikembalikan oleh getContentType() ditulis dalam format yang disebut MIME,
misalnya "text/plain", "text/html", "image/jpeg", "image/gif", dan banyak lagi lainnya. Semua
jenis MIME terdiri dari dua bagian, yaitu bagian umum, seperti "text" atau "image", dan bagian
khususnya, misalnya "html" atau "gif". Jika kita hanya tertarik pada data teks misalnya, kita
hanya perlu menguji apakah hasil keluaran getContentType() dimulai dengan "text". (Jenis
MIME pertama kali dimaksudkan untuk menjelaskan isi email. Namanya adalah singkatan dari
"Multipurpose Internet Mail Extensions". Kini, MIME digunakan secara umum untuk
menjelaskan jenis suatu informasi atau file pada suatu sumber).

Mari kita lihat contoh singkat bagaimana membaca data dari suatu URL. Subrutin berikut akan
membuka koneksi ke URL tertentu, mengecek apakah jenisnya berupa teks, kemudian mengkopi
hasilnya ke layar. Beberapa operasi dalam subrutin ini mungkin melempar pengecualian. Kita
akan menambahkan "throws Exception" di kepala subrutin untuk meneruskan penanganan
pengecualian ini kepada program utama yang memanggil subrutin ini.

static void bacaTeksDariURL( String alamatURL ) throws Exception {


// Subrutin ini mencetak isi dari alamat URL yang
// diberikan ke layar. Semua kesalahan akan ditangani
// oleh program yang memanggil subrutin ini
 
/* Buka koneksi ke URL, dan ambil aliran input
* untuk membaca data dari URL. */
 
URL url = new URL(alamatURL);
URLConnection koneksi = url.openConnection();
InputStream dataURL = koneksi.getInputStream();
 
/* Cek apakah konten bertipe teks */
 
String jenisKonten = koneksi.getContentType();
if (jenisKonten == null || jenisKonten.startsWith("text") == false)
throw new Exception("URL tidak bertipe teks.");
 
/* Kopi karakter dari aliran input ke layar
* hingga akhir file ditemukan (atau kesalahan ditemui) */
 
while (true) {
int data = dataURL.read();
if (data < 0)
break;
System.out.print((char)data);
}
} // akhir bacaTeksDariURL()

Soket, Klien, dan Server


Posted Sab, 04/25/2009 - 18:36 by belajarprogram

Versi ramah cetak

Komunikasi melalui internet dilakukan berdasarkan sepasang protokol yang dinamakan Internet
Protocol dan Transmission Control Protocol, yang digabungkan menjadi TCP/IP. (Sebenarnya,
ada lagi protokol komunikasi yang lebih sederhana yang disebut dengan UDP yang bisa
digunakan menggantikan TCP pada beberapa aplikasi. UDP juga didukung Java, akan tetapi kita
akan membahas TCP/IP saja yang merupakan komunikasi dua arah yang handal digunakan pada
beberapa komputer melalui jaringan).

Agar dua program dapat berkomunikasi menggunakan TCP/IP, masing-masing program harus
membuat soket, yang kemudian soket-soket tersebut harus terhubung satu sama lain. Setelah
terhubung, komunikasi dapat dilakukan dengan menggunakan aliran input dan output seperti
biasa. Setiap program harus memiliki aliran input dan outputnya masing-masing. Data yang
ditulis oleh suatu program di aliran outputnya akan dikirim ke komputer lain. Di sana, data
tersebut akan diisi pada aliran input program tersebut. Ketika program tadi membaca aliran
inputnya, maka pada dasarnya program tersebut membaca data yang dikirim oleh program lain.

Bagian tersulitnya adalah bagaimana membuat koneksi antar komputer tersebut. Dalam hal ini,
dua soket akan digunakan. Pertama-tama, suatu program harus membuat soket yang menunggu
secara pasif hingga koneksi lain dari soket lain di komputer lain datang. Soket yang sedang
menunggu ini disebut sedang "mendengar" (listening) suatu koneksi.

Di sisi lain di komputer lain, program lain membuat soket yang mengirim permintaan
sambungan ke soket pendengar tadi. Ketika soket pendengar menerima permintaan sambungan
dari soket lain, soket ini akan merespon, sehingga komunikasi akan terjadi. Begitu komunikasi
terjadi, maka masing-masing program akan bisa membuat aliran input dan aliran output untuk
koneksi ini. Komunikasi akan terus terjadi hingga salah satu program menutup (close) koneksi.

Program yang membuat soket pendengar, juga sering disebut server, dan soketnya disebut soket
server. Program yang menghubungi server disebut klien (client), dan soket yang digunakan
disebut soket klien.

Idenya adalah suatu server di suatu tempat pada network sedang menunggu permintaan
sambungan dari suatu klien. Server dianggap sebagai sesuatu yang memberikan layanan, dan
klien mendapatkan layanan dengan cara menyambungkannya pada server. Pada komunikasi
jaringan, ini disebut model klien/server.

Dalam aplikasi dunia nyata, program server dapat memberikan koneksi kepada beberapa klien
pada waktu yang sama. Ketika suatu klien terhubung pada soket pendengar, maka soket tersebut
tidak berhenti mendengar. Akan tetapi, soket tersebut akan terus mendengar jika ada koneksi
klien lain pada saat yang sama.

Kelas URL yang telah didiskusikan sebelumnya menggunakan soket klien di belakang layar untuk
melakukan komunikasi jaringan yang dibutuhkan. Di sisi lainnya adalah program server yang
menerima permintaan sambungan dari objek URL, membaca permintaan objek tersebut, misalnya
permintaan file di alamat tertentu, dan meresponnya dengan mengirimkan isi file tersebut
melalui network ke objek URL tadi. Setelah mengirimkan data, server akan memutuskan koneksi
ini.
Untuk mengimplementasikan koneksi TCP/IP, paket java.net menyediakan dua kelas, yaitu
ServerSocket dan Socket. Objek bertipe ServerSocket melambangkan soket pendengar yang
menunggu permintaan sambungan dari klien. Objek bertipe Socket melambangkan sisi lain dari
suatu sambungan, yang bisa berarti soket klien, atau bisa saja soket lain yang dibuat server untuk
menangani permintaan dari klien. Dengan cara ini server bisa membuat beberapa soket dan
menangani beberapa koneksi sekaligus. (Suatu ServerSocket sendiri tidak berpartisipasi
langsung pada koneksi itu sendiri; ia hanya bertugas untuk mendengarkan permintaan
sambungan, dan membuat Socket untuk melakukan koneksi yang sesungguhnya)

Untuk menggunakan Socket dan ServerSocket, kita harus tahu tentang alamat Internet.
Program klien harus bisa menentukan komputer mana yang akan berkomunikasi dengannya.
Setiap komputer pada internet memiliki alamat IP yang merupakan alamat unik setiap komputer
di dalam internet. Komputer juga bisa memiliki nama domain seperti www.yahoo.com atau
www.google.com.

Suatu komputer bisa memiliki beberapa program untuk melakukan komunikasi network secara
bersamaan, atau satu program mungkin berkomunikasi dengan beberapa komputer sekaligus.
Agar bisa bekerja seperti ini, soket sebenarnya merupakan kombinasi antara alamat IP dan
nomor port. Nomor port hanya merupakan bilangan bulat 16-bit (dari 0 hingga 216 - 1). Suatu
server tidak hanya mendengar koneksi saja, akan tetapi ia mendengar koneksi dari port tertentu.

Klien yang ingin berkomunikasi dengan server harus mengetahui alamat Internet komputer
beserta nomor port di mana server tersebut mendengarkan permintaan sambungan. Server web,
misalnya, pada umumnya mendengarkan koneksi pada port 80; layanan internet lain juga
memiliki nomor port standar. (Nomor port standar adalah nomor di bawah 1024. Jika kita
membuat program server sendiri, kita sebaiknya menggunakan port benomor lebih besar dari
1024).

Ketika kita membuat objek bertipe ServerSocket, kita harus memberikan nomor port yang akan
didengar oleh server. Konstruktornya memiliki bentuk seperti

public ServerSocket(int port) throws IOException

Setelah ServerSocket berhasil dijalankan, ia akan mulai mendengarkan permintaan sambungan.


Metode accept() dalam kelas ServerSocket akan menerima permintaan tersebut, kemudian
mempersiapkan sambungan dengan klien, dan mengembalikan objek Socket yang bisa
digunakan untuk berkomunikasi dengan klien. Metode accept() memiliki bentuk seperti

public Socket accept() throws IOException

Ketika kita memanggil metode accept(), ia tidak akan mengembalikan hasilnya sebelum
permintaan sambungan diterima (atau suatu kesalahan terjadi). Metode ini disebut "diblokade"
ketika menunggu koneksi. (Ketika suatu metode diblokade, maka thread yang memanggil
metode tersebut tidak bisa berbuat apa-apa. Akan tetapi thread lain di program yang sama masih
bisa berjalan). ServerSocket tersebut akan terus mendengar koneksi hingga ia ditutup
menggunakan metode close() atau hingga terjadi kesalahan.
Misalnya kita akan membuat server yang akan mendengarkan port 1728, dan misalnya kita telah
menulis metode baru beriLayanan(Socket) untuk menangani komunikasi dengan suatu klien.
Maka bentuk sederhana dari program server adalah sebagai berikut :

try {
ServerSocket server = new ServerSocket(1728);
while (true) {
Socket koneksi = server.accept();
beriLayanan(koneksi);
}
}
catch (IOException e) {
System.out.println("Server dimatikan dengan pesan kesalahan: " +
e);
}

Di sisi klien, soket klien dibuat dengan menggunakan konstruktor pada kelas Socket. Untuk
melakukan koneksi ke server pada suatu alamat dan port tertentu, kita bisa menggunakan
konstruktor

public Socket(String komputer, int port) throws IOException

Parameter pertama bisa berupa alamat IP atau nama domain. Konstruktor akan memblokadi
dirinya hingga koneksi tersambung atau hingga terjadi kesalahan. Setelah koneksi tersambung,
kita bisa menggunakan metode getInputStream() dan getOutputStream() pada Socket
untuk mengambil aliran input dan output yang bisa digunakan untuk komunikasi antara dua
komputer.

Berikut ini adalah kerangka untuk melakukan koneksi klien :

void koneksiKlien(String namaKomputer, int port) {


// namaKomputer bisa berupa alamat IP atau nama domain
// dari komputer yang bertindak sebagai server.
// port adalah port dimana server mendengarkan koneksi,
// misalnya 1728.
Socket koneksi;
InputStream in;
OutputStream out;
try {
koneksi = new Socket(namaKomputer,port);
in = koneksi.getInputStream();
out = koneksi.getOutputStream();
}
catch (IOException e) {
System.out.println(
"Usah melakukan sambungan gagal, dengan kesalahan : " + e);
return;
}
.
. // Gunakan aliran in dan out untuk berkomunikasi dengan server
.
try {
koneksi.close();
// (Atau, bisa juga bergantung pada server untuk
// memutuskan sambungan)
}
catch (IOException e) {
}
} // akhir koneksiKlien()

Membuat komukasi melalui jaringan terlihat lebih mudah dari yang sebenarnya. Jika jaringan
yang kita gunakan benar-benar handal, mungkin perintah di atas cukup untuk digunakan. Akan
tetapi, untuk membuat program tangguh yang bisa menangani segala permasalahan dalam
jaringan yang kurang handal atau karena kesalahan manusia misalnya, adalah hal yang tidak
mudah. Pengalaman yang bisa membawa kita menjadi programmer jaringan yang lebih baik dan
lebih komplet. Yang kita bahas di sini semoga berguna sebagai pengantar untuk membawa Anda
lebih jauh mencari tahu tentang pemrograman dengan jaringan.

Contoh Pemrograman pada Jaringan


Posted Sab, 04/25/2009 - 18:44 by belajarprogram

Versi ramah cetak

Contoh ini melibatkan dua program, yaitu klien sederhana dan servernya. Klien melakukan
koneksi dengan server, membaca satu baris teks dari server, kemudian menampilkan teks ini
pada layar. Teks yang dikirim oleh server adalah tanggal dan waktu saat ini di komputer di mana
server dijalankan.

Untuk membuka koneksi, klien harus tahu di komputer mana server dijalankan dan di port mana
server tersebut mendengarkan permintaan sambungan. Server akan mendengarkan pada port
bernomor 32007. Nomor port ini bisa berapapun di antara 1025 hingga 65535, asalkan klien dan
servernya menggunakan port yang sama. Nomor port antara 1 hingga 1024 hanya digunakan oleh
layanan standar dan seharusnya tidak digunakan untuk server lainnya.

Nama komputer atau alamat IP di mana server dijalankan harus diberikan pada paramater baris
perintah. Misalnya jika server dijalankan pada komputer kita sendiri, kita bisa memanggilnya
dengan "java KlienTanggal localhost". Berikut ini adalah program klien lengkapnya.

import java.net.*;
import java.io.*;
 
public class KlienTanggal {
 
static final int PORT_PENDENGAR = 32007;
 
/**
* @param args
*/
public static void main(String[] args) {
String komputer; // Nama komputer yang akan disambungkan
Socket koneksi; // Soket untuk berkomunikasi dengan
// komputer tersebut
Reader masuk; // Aliran untuk membaca data dari koneksi
 
/* Ambil nama komputer dari baris perintah */
 
if (args.length > 0)
komputer = args[0];
else {
// Tidak ada nama komputer yang diberikan
// Beri pesan kesalahan dan program selesai
System.out.println("Cara menggunakan : java KlienTanggal
<server>");
return;
}
 
/* Buat koneksi, kemudian baca dan tampilkan di layar */
 
try {
koneksi = new Socket( komputer, PORT_PENDENGAR );
masuk = new InputStreamReader( koneksi.getInputStream() );
while (true) {
int ch = masuk.read();
if (ch == -1 || ch == '\n' || ch == '\r')
break;
System.out.print( (char)ch );
}
System.out.println();
masuk.close();
}
catch (IOException e) {
System.out.println("Kesalahan : " + e);
}
}
}

Perhatikan bahwa semua komunikasi dengan server dilakukan dalam pernyataan try ...
catch. Ini akan menangkap pengecualian IOException yang mungkin terjadi ketika koneksi
sedang dibuka atau ditutup atau sedang membaca karakter dari aliran input.

Aliran yang digunakan adalah aliran sederhana Reader yang memiliki operasi input
masuk.read(). Fungsi ini membaca satu per satu karakter dari aliran, kemudian mengembalikan
nomor kode Unicodenya. Jika akhir aliran telah dicapai, maka nilai -1 akan dikembalikan.
Perulangan while membaca karakter ini satu per satu hingga akhir aliran ditemui atau akhir baris
ditemui. Akhir baris ditandai dengan salah satu dari '\n' atau '\r' atau keduanya, tergantung dari
jenis komputer di mana server tersebut berjalan.

Agar program ini dapat berjalan tanpa kesalahan, maka program server harus dijalankan terlebih
dahulu. Kita bisa membuat program klien dan server pada komputer yang sama. Misalnya kita
bisa membuat dua jendela konsol pada windows, kemudian menjalankan server di konsol yang
satu dan menjalankan klien di server yang lain. Agar ini bisa berjalan, komputer lokal kita
memiliki alamat 127.0.0.1, sehingga perintah "java KlienTanggal 127.0.0.1" artinya sama
dengan memerintahkan program KlienTanggal untuk melakukan sambungan dengan server yang
berjalan di komputer yang sama. Atau bisa juga menggunakan alamat "localhost" sebagai
pengganti "127.0.0.1".

Program servernya kita namakan ServerTanggal. Program ServerTanggal membuat


ServerSocket untuk mendengarkan permintaan sambungan pada port 32007. Setelah soket
pendengar kita buat, maka server akan masuk pada perulangan tak hingga di mana ia menerima
dan mengolah permintaan sambungan. Program ini akan berjalan terus menerus tanpa henti
kecuali kita hentikan dengan paksa -- misalnya dengan menekan tombol Ctrl-C di jendela konsol
di mana server dijalankan.

Ketika koneksi diterima dari klien, server akan memanggil subrutin lain untuk menangani
koneksi tersebut. Dalam subrutin itu, pengecualian apapun yang terjadi akan ditangkap sehingga
server tidak akan mati. Subrutin akan membuat aliran PrintWriter untuk mengirim data
melalui koneksi yang terjadi.

Server akan menulis tanggal dan waktu sekarang pada aliran output ini, kemudian menutup
koneksi. (Kelas standar java.util.Date akan digunakan untuk mengambil tanggal saat ini.
Objek bertipe Date melambangkan tanggal dan waktu. Konstruktor standarnya, "new Date()"
membuat objek yang melambangkan tanggal dan waktu ketika objek tersebut dibuat.)

Berikut ini adalah program server lengkapnya :

import java.net.*;
import java.io.*;
import java.util.Date;
 
public class ServerTanggal {
 
static final int PORT_PENDENGAR = 32007;
 
/**
* @param args
*/
public static void main(String[] args) {
ServerSocket pendengar; // Mendengarkan sambungan yang masuk
Socket koneksi; // Untuk berkomunikasi dengan sambungan yang masuk
 
/*
* Menerima dan mengolah sambungan selamanya, atau hingga kesalahan
* terjadi. (Kesalahan yang terjadi ketika sedang berkomunikasi atau
* mengirimkan tanggal akan ditangkap untuk mencegah server crash)
*/
 
try {
pendengar = new ServerSocket(PORT_PENDENGAR);
System.out.println("Mendengarkan pada port " + PORT_PENDENGAR);
while (true) {
koneksi = pendengar.accept();
kirimTanggal(koneksi);
}
} catch (Exception e) {
System.out.println("Maaf, server telah mati.");
System.out.println("Kesalahan : " + e);
return;
}
}
 
static void kirimTanggal(Socket klien) {
// Parameternya, klien, adalah soket yang telah terhubung dengan
// program lain. Ambil aliran keluaran untuk melakukan sambungan,
// kirim tanggal saat ini dan tutup sambungan.
try {
System.out.println("Sambungan dari "
+ klien.getInetAddress().toString());
Date sekarang = new Date(); // Tanggal dan waktu saat ini
PrintWriter keluar; // Aliran output untuk mengirim tanggal
keluar = new PrintWriter(klien.getOutputStream());
keluar.println(sekarang.toString());
keluar.flush(); // Pastikan data telah terkirim!
klien.close();
} catch (Exception e) {
System.out.println("Kesalahan : " + e);
}
}
}

Jika kita jalankan ServerTanggal pada konsol, maka ia akan diam menunggu datangnya
permintaan sambungan dan melaporkannya apabila permintaan telah masuk. Agar layanan
ServerTanggal tetap tersedia pada suatu komputer, program tersebut seharusnya dijalankan
sebagai daemon. Daemon adalah program yang terus berjalan pada suatu komputer, tidak peduli
siapa yang menggunakan komputer itu. Komputer bisa dikonfigurasi untuk menjalankan daemon
secara otomatis ketika komputer dinyalakan. Kemudian ia akan berjalan di latar belakang,
meskipun komputer digunakan untuk hal lainnya. Misalnya, komputer yang menyediakan
layanan Web menjalankan daemon yang mendengarkan permintaan sambungan untuk melihat
halaman web dan meresponnya dengan mengirimkan isi halaman tersebut. Bagaimana
menjalankan program sebagai daemon tidak akan kita bahas di sini, dan bisa Anda temui pada
buku-buku tentang administrasi server dan jaringan.

Lihat setelah memanggil keluar.println() untuk mengirim data ke klien, program server
memanggil keluar.flush(). Metode flush() tersedia pada semua kelas aliran output. Metode
ini digunakan untuk menjamin bahwa data yang telah dikirim pada aliran benar-benar dikirim ke
tujuannya. Kita harus memanggil fungsi ini setiap kali kita menggunakan aliran output untuk
mengirim data melalui jaringan. Jika tidak, ada kemungkinan program akan mengumpulkan
banyak data dan mengirimkan semuanya sekaligus. Mungkin dari segi efisiensi terlihat bagus,
akan tetapi tentunya pesan akan sangat lambat sampai di program klien. Atau bahkan masih ada
data yang belum terkirim hingga soket ditutup.

Berikut ini adalah screen shot hasil pemanggilan program di atas pada dua konsol, masing-
masing untuk server dan kliennya.
Dan program di atas dapat diunduh pada daftar sisipan di bawah, dan diimpor ke dalam Eclipse
dengan menggunakan instruksi pada halaman berikut.

Untuk menjalankan program di atas, jalankan program server terlebih dahulu, dari dalam konsol
ketik "cd <nama_direktori_tempat_proyek_server_berada>\bin" (di screen shot di atas
direktorinya berada di c:\belajarjava.lyracc.com\servertanggal\bin) kemudian ketik "java
ServerTanggal".

Kemudian untuk menjalankan program klien, lakukan dengan cara yang serupa, yaitu buka
konsol baru, kemudian ketik "cd <nama_direktori_tempat_proyek_klien_berada>\bin" (di screen
shot di atas direktornya berada di c:\belajarjava.lyracc.com\klientanggal\bin) kemudian ketik
"java KlienTanggal localhost".

Untuk mengetahui di direktori mana proyek ini berada pada Eclpse Anda, klik kanan proyek
tersebut dari dalam Eclipse -> Properties, seperti pada screen shot berikut ini :
Pemrograman Serentak (Concurrency)
Posted Rab, 05/20/2009 - 21:30 by belajarprogram

Versi ramah cetak

Java adalah bahasa pemrograman banyak thread, yang artinya beberapa hal bisa dilakukan
bersama-sama. Thread adalah unit terkecil dari eksekusi suatu program. Thread mengeksekusi
rangkaian instruksi satu demi satu. Ketika sistem menjalankan program, komputer akan
membuat thread baru. (Thread dalam konteks ini disebut proses, akan tetapi perbedaanya tidank
penting di sini). Instruksi-instruksi dalam program akan dieksekusi oleh thread ini secara
berantai, satu demi satu dari awal hingga akhir. Thread disebut "mati" jika program selesai
dieksekusi.

Dalam sistem komputer modern, beberapa thread bisa tercipta dalam satu waktu. Pada satu saat
tertentu, hanya ada satu thread yang bisa dijalankan, karena CPI hanya bisa melakukan satu hal
dalam satu waktu. (Pada komputer dengan multiprosesor, multicore, dan hyper-threading,
masing-masing prosesor atau core melakukan thread yang berbeda-beda). Akan tetapi
sebenarnya komputer membagi waktu menjadi bagian-bagian kecil sehingga seolah-olah seluruh
thread dijalankan secara bersama-sama. Pembagian waktu berarti CPU mengeksekusi suatu
thread dalam kurun waktu tertentu, setelah itu beralih mengeksekusi thread yang lain, kemudian
thread lain, dan seterusnya dan kemudian kembali ke thread pertama -- kira-kira 100 kali per
detik. Di mata user, semua thread berjalan pada saat yang sama.

Java adalah bahasa pemrograman banyak thread. Artinya Java bisa membuat satu atau lebih
thread yang bisa dijalankan secara paralel. Hal ini adalah bagian mendasar, yang dibuat di dalam
core bahasa, bukan merupakan tambahan (add-on) seperti bahasa pemrograman lain. Tetap saja
pemrogaman dengan banyak thread adalah sesuatu yang tidak mudah.

Penggunaan thread yang banyak digunakan adalah untuk membuat GUI (graphical user
interface) yang responsif. Pada dasarnya suatu program harus dapat terus bejalan dan pada saat
yang sama tetap bisa menerima input dari user, menanggapi klik mouse, dan sebagainya.

Thread juga digunakan untuk mempercepat suatu proses, misalnya kita ingin membuat program
yang menunggu suatu input I/O dari network, dan pada saat yang sama mengolahnya sehingga
proses pengolahan berjalan serentak. Jika program harus menunggu seluruh input datang baru
kemudian melakukan pengolahan, tentunya akan memakan waktu yang lebih lama, terutama
apabila aliran network lambat atau pengolahannya memakan waktu lama.

Jika kita memiliki CPU multiprocessor atau multicore, maka menggunakan banyak thread akan
mempercepat eksekusi program, karena masing-masing thread dijalankan secara terpisah.
Misalnya untuk melakukan video encoding dengan jumlah data besar, jika kita menggunakan
seluruh core yang tersedia maka prosesnya akan dapat diselesaikan dengan cepat.

 Dasar-dasar Thread
 Berbagi Sumber Daya
 Siklus Hidup Thread
 Kerjasama Antar Thread
 Kunci Mati (Deadlock)
 Menghentikan Thread

Dasar-dasar Thread
Posted Kam, 05/21/2009 - 01:09 by belajarprogram

Versi ramah cetak

Cara termudah untuk membuat thread adalah membuat kelas turunan dari java.lang.Thread,
yang memiliki semua metode untuk membuat dan menjalankan thread. Metode paling penting
adalah run(), yang bisa kita beban-lebihkan untuk melakukan tugas yang kita butuhkan. Atau
dengan kata lain run() adalah metode yang akan dijalankan bersamaan dengan thread lain.

Contoh berikut membuat 5 thread, masing-masing memiliki nomor identifikasi unik yang dibuat
dengan menggunakan variabel statik. Metode run() dibebanlebihkan untuk menghitung mundur
hingga hitungMundur bernilai nol. Setelah metode run() selesai dijalankan, thread akan mati
secara otomatis.
(Contoh-contoh pada bagian ini bisa diunduh untuk diimport ke dalam Eclipse. Lihat akhir
halaman ini untuk tautannya)

package com.lyracc.threaddasar1;
 
public class ThreadDasar extends Thread {
private int hitungMundur = 5;
private static int jumlahThread = 0;
 
public ThreadDasar() {
super("Thread ke-" + ++jumlahThread);
start();
}
 
public void run() {
while (true) {
System.out.println( getName() + " : " + hitungMundur );
if (--hitungMundur == 0)
return;
}
}
 
/**
* @param args
*/
public static void main(String[] args) {
for(int i = 0; i < 5; i++)
new ThreadDasar();
}
}

Pada contoh program di atas, objek thread diberi nama melalui argumen pada konstruktornya.
Nama ini dipanggil ketika metode run() melakukan penghitungan mundur, yaitu dengan
menggunakan metode getName().

Metode run() pada thread biasanya memiliki perulangan internal yang akan terus menerus
dipanggil hingga tidak lagi digunakan. Kita harus membuat suatu kondisi sehingga bisa keluar
dari perulangan tersebut (misalnya pada contoh di atas, perulangan akan selesai jika
hitungMundur bernilai 0). Seringkali, run() dijalankan di dalam perulangan yang tak pernah
berhenti (kita akan lihat nanti bagaimana menghentikan suatu thread dengan aman).

Pada metode main(), thread dibuat beberapa kali kemudian dijalankan. Metode start() pada
kelas Thread digunakan untuk melakukan tugas tertentu sebelum metode run() dijalankan. Jadi,
langkah-langkahnya adalah : konstruktor dipanggil untuk membuat objek, kemudian memanggil
start() untuk melakukan konfigurasi thread, dan kemudian metode run() dijalankan. Jika kita
tidak memanggil start() maka metode run() tidak akan pernah dijalankan.

Keluaran dari program ini akan berbeda setiap kali dijalankan, karena penjadwalan thread tidak
dapat ditentukan dengan pasti (non-deterministik). Bahkan, kita bisa melihat perbedaan yang
sangat jelas ketika kita menggunakan versi JDK yang berbeda. Misalnya, JDK lama tidak
melakukan pembagian waktu lebih cepat, artinya, 1 thread mungkin bisa melakukan tugasnya
dengan cepat hingga selesai sebelum thread lain dijalankan. Pada JDK lain kita akan melihat
program akan mencetak 5 untuk seluruh thread hingga 1 untuk seluruh thread. Artinya
pembagian waktunya lebih baik, karena setiap thread memiliki kesempatan yang sama untuk
menjalankan program. Karenanya, untuk membuat suatu program multi-threading, kita tidak
boleh terpaku pada keluaran suatu kompiler. Program kita harus dibuat seaman mungkin.

Ketika objek Thread dibuat pada metode main(), kita lihat bahwa kita tidak menyimpan
referensi ke objek tersebut. Pada objek biasa, tentunya objek ini akan langsung ditangkap oleh
pemulung memori karena objek ini tidak direferensikan di manapun. Akan tetapi pada thread,
objek hanya bisa diambil oleh pemulung memori jika metode run() selesai dijalankan. Pada
contoh di atas, program masih bisa berjalan seperti biasa, dan objek Thread akan diberikan
kepada pemulung memori setelah mencetak angka 1.

Yielding (menghasilkan)

Jika kita tahu bahwa kita telah mendapatkan hasil yang kita inginkan pada metode run(), kita
bisa memberi tahu penjadwal thread bahwa kita telah selesai dan memberi jalan kepada thread
lain untuk mendapatkan kesempatan pada CPU. Akan tetapi ini hanya sebagai petunjuk, yang
artinya belum tentu dijalankan oleh penjadwal thread.

Misalnya pada contoh di atas, kita bisa mengganti isi metode run() dengan

public void run() {


while (true) {
System.out.println( getName() + " : " + hitungMundur );
if (--hitungMundur == 0)
return;
yield();
}
}

Secara umum, yield mungkin berguna untuk situasi yang agak langka, dan kita tidak bisa
menggunakannya secara serius untuk memperbaiki kinerja aplikasi kita.

Tidur (sleeping)

Cara lain untuk mengatur perilaku thread kita adalah dengan memanggil sleep untuk menunda
eksekusi thread selama waktu tertentu (dalam mili detik). Misalnya pada kode berikut, kita ubah
metode run() menjadi seperti :

public void run() {


while (true) {
System.out.println( getName() + " : " + hitungMundur );
if (--hitungMundur == 0)
return;
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}

Ketika kita memanggil sleep(), metode ini harus diletakkan di dalam blok try karena sleep()
bisa melemparkan pengecualian, yaitu jika tidurnya diganggu sebelum waktunya selesai. Hal ini
terhadi misalnya apabila thread lain yang memiliki referensi ke thread ini memanggil
interrupt() pada thread ini. Pada contoh di atas, kita lemparkan lagi pengecualian yang terjadi
dengan pengecualian lain bertipe RuntimeException, karena kita tidak tahu bagaimana
pengecualian ini harus ditangani, dan membiarkan metode yang memanggilnya menangkap
pengecualian baru ini.

Metode sleep() tidak digunakan untuk mengatur bagaimana thread akan berjalan menurut
urutan tertentu. Metode ini hanya menghentikan eksekusi suatu thread sementara. Yang dijamin
adalah bahwa thread akan tidur selama paling sedikit 100 mili detik (atau mungkin sedikit lebih
lama hingga thread jalan kembali). Urutan thread diatur oleh penjadwal thread yang memiliki
mekanisme sendiri tergantung dari keadaan thread lain atau bahkan aplikasi lain di luar Java,
oleh karena itu sifatnya disebut non-deterministik.

Jika kita harus mengatur thread mana dahulu yang harus dijalankan, cara terbaik mungkin tidak
menggunakan thread sama sekali, atau mendesain agar suatu thread memanggil thread lain
dengan suatu urutan tertentu. Tentunya cara terakhir lebih rumit dari yang dibayangkan.

Prioritas

Prioritas suatu thread digunakan untuk memberi tahu penjadwal thread tentang prioritas thread
tersebut. Tetap saja urutannya tidak bisa ditentukan karena sifatnya yang non-deterministik. Jika
ada beberapa thread yang sedang diblok dan menunggu giliran untuk dijalankan, penjadwal
thread akan cenderung menjalankan thread dengan prioritas tertinggi terlebih dahulu. Akan
tetapi, tidak berarti thread dengan prioritas rendah tidak akan pernah dijalankan, hanya lebih
jarang dijalankan ketimbang thread dengan prioritas tinggi.

Perhatikan contoh berikut :

package com.lyracc.prioritasthread;
 
public class PrioritasThread extends Thread {
private int hitungMundur = 5;
private volatile double d = 0; // No optimization
 
public PrioritasThread(int prioritas) {
setPriority(prioritas);
start();
}
 
public void run() {
while (true) {
for(int i = 1; i < 100000; i++)
d = d + (Math.PI + Math.E) / (double)i;
System.out.println(this.toString() + " : " + hitungMundur);
if (--hitungMundur == 0)
return;
}
}
 
/**
* @param args
*/
public static void main(String[] args) {
new PrioritasThread(Thread.MAX_PRIORITY);
for(int i = 0; i < 5; i++)
new PrioritasThread(Thread.MIN_PRIORITY);
}
}

Pada contoh di atas, kita ubah konstruktornya untuk mengeset prioritas kemudian menjalankan
thread. Pada metode main() kita buat 6 thread, yang pertama dengan prioritas maximum, dan
yang lain dengan prioritas minimum. Perhatikan keluarannya, bagaimana thread pertama
dijalankan lebih dulu sedangkan thread-thread lain berjalan seperti biasa dalam kondisi acak
karena memiliki prioritas yang sama.

Di dalam metode run() kita lakukan perhitungan matematika selama 100.000 kali. Tentunya ini
perhitungan yang memakan waktu sehingga setiap thread harus menunggu giliran di saat thread
lain sedang dijalankan. Tanpa perhitungan ini, thread akan dilaksanakan sangat cepat dan kita
tidak bisa melihat efek dari prioritas thread.

Prioritas suatu thread bisa kita set kapan saja (tidak harus pada konstruktor) dengan metode
setPriority(int prioritas) dan kita bisa membaca prioritas suatu thread dengan
menggunakan metode getPriority().

Meskipun JDK memiliki 10 tingkat prioritas, akan tetapi sistem operasi memiliki tingkat
prioritas yang berbeda-beda. Windows misalnya memiliki 7 tingkat dan Solaris memiliki 231
tingkat prioritas. Yang lebih pasti adalah menggunakan konstanta MAX_PRIORITY,
NORM_PRIORITY, dan MIN_PRIORITY pada kelas thread.

Thread Daemon

Thread daemon adalah thread yang bekerja di belakang layar yang memberikan layanan umum
kepada thread-thread lain selama program berjalan, akan tetapi thread ini bukan bagian penting
dari suatu program. Artinya ketika semua thread yang bukan daemon selesai dijalankan, program
akan berhenti, dan jika masih ada thread non-daemon yang masih dieksekusi, program tidak akan
berhenti.

Perhatikan contoh program berikut ini.

package com.lyracc.threaddaemon;
 
public class ThreadDaemon extends Thread {
public ThreadDaemon() {
setDaemon(true); // Harus dipanggil sebelum start
start();
}
 
public void run() {
while (true) {
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(this);
}
}
 
/**
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 5; i++)
new ThreadDaemon();
}
 
}

Perintah setDaemon() sebelum metode start() dipanggil. Pada metode run(), thread
diperintahkan untuk tidur selama 100 mili detik. Ketika semua thread dimulai, program langsung
berhenti sebelum thread bisa mencetak dirinya. Ini karena semua thread kecuali main() adalah
thread daemon. Hanya thread non-daemon saja yang bisa mencegah program untuk terus
berjalan.

Untuk mengetahui suatu thread adalah thread daemon atau bukan, kita bisa menggunakan
perintah isDaemon(). Suatu thread daemon akan membuat thread yang juga merupakan thread
daemon.

Menggabungkan thread

Perintah join() bisa digunakan pada thread lain untuk menunda eksekusi hingga thread lain
tersebut selesai dijalankan. Misalnya, jika thread a memanggil t.join() pada thread t, maka
eksekusi thread a akan terhenti sementara hingga thread t selesai dijalankan (atau ketika
t.isAlive() bernilai false).

Kita bisa juga memanggil join() dengan argumen waktu (baik dalam mili detik, ataupun
milidetik dan nanodetik), yaitu jika thread target tidak selesai dalam kurun waktu tersebut,
eksekusi pada thread induk akan kembali dilakukan.

Panggilan join() bisa dibatalkan dengan memanggil interrupt() pada thread induk, sehingga
klausa try ... catch diperlukan pada metode join().

Mari kita lihat contoh berikut ini.


package com.lyracc.joindemo;
 
class ThreadPemalas extends Thread {
private int waktu;
 
public ThreadPemalas(String namaThread, int waktuTidur) {
super(namaThread);
waktu = waktuTidur;
start();
}
 
public void run() {
try {
sleep(waktu);
} catch (InterruptedException e) {
System.out.println(getName() + " dibangunkan. "
+ "isInterrupted(): " + isInterrupted());
return;
}
System.out.println(getName() + " sudah bangun.");
}
}
 
class ThreadPenggabung extends Thread {
private ThreadPemalas sleeper;
 
public ThreadPenggabung(String namaThread, ThreadPemalas pemalas) {
super(namaThread);
this.sleeper = pemalas;
start();
}
 
public void run() {
try {
sleeper.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(getName() + " selesai setelah " +
sleeper.getName());
}
}
 
public class JoinDemo {
/**
* @param args
*/
public static void main(String[] args) {
ThreadPemalas brr = new ThreadPemalas("brr", 2000);
ThreadPemalas grr = new ThreadPemalas("grr", 2000);
 
ThreadPenggabung saya = new ThreadPenggabung("saya",brr);
ThreadPenggabung anda = new ThreadPenggabung("anda",grr);
 
grr.interrupt();
}
 
}

Hasil keluarannya adalah seperti pada gambar berikut.

ThreadPemalas adalah thread yang akan ditidurkan sepanjang waktu yang diberikan pada
konstruktornya. Metode run() bisa berhenti jika waktu tidur sudah habis atau ada interupsi yang
terjadi. Di dalam klausa catch, interupsi akan dilaporkan. Fungsi isInterrupted() melaporkan
apakah thread ini diinterupsi atau tidak. Akan tetapi ketika thread ini diinterupsi, kemudian
pengecualiannya ditangkap oleh klausa catch, misalnya, maka tanda interupsi akan segera
dihapus. Oleh karenanya isInterrupted() akan selalu bernilai false pada program di atas.
Tanda interupsi akan digunakan pada situasi lain yang mungkin berada di luar pengecualian.

ThreadPenggabung adalah thread yang menunggu hingga ThreadPemalas selesai dengan


tugasnya, yaitu dengan memanggil join() ke objek ThreadPemalas pada metode run()-nya.

Pada metode utama main(), setiap ThreadPemalas tersambung pada ThreadPenggabung. Dan
kita lihat pada keluarannya, jika ThreadPemalas selesai bekerja, baik karena dibangunkan
melalui interupsi atau karena waktu sudah selesai, ThreadPenggabung yang tersambung juga
akan menyelesaikan tugasnya.

Variasi Kode

Pada contoh-contoh di atas, semua objek thread yang kita buat diturunkan dari kelas Thread.
Kita hanya membuat objek yang berfungsi sebagai thread dan tidak memiliki tugas dan fungsi
lain. Akan tetapi, kelas kita mungkin saja merupakan kelas turunan dari kelas lain. Karena Java
tidak mendukung pewarisan berganda, kita tidak bisa menurunkan kelas tersebut bersamaan
dengan kelas Thread.

Dalam hal ini, kita bisa menggunakan cara alternatif yaitu dengan mengimplementasi interface
Runnable. Runnable hanya memiliki satu metode untuk diimplementasi, yaitu metode run().

Contoh berikut mendemonstrasikan contoh penggunaannya :

package com.lyracc.runnablesederhana;
 
public class RunnableSederhana implements Runnable {
private int hitungMundur = 5;
 
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + " : " +
hitungMundur);
if (--hitungMundur == 0)
return;
}
}
 
public static void main(String[] args) {
for (int i = 1; i <= 5; i++) {
// Buat thread baru dan jalankan
Thread a = new Thread(new RunnableSederhana(), "Thread ke-" + i);
a.start();
}
}
}

Satu-satunya yang dibutuhkan oleh kelas RunnableSederhana adalah metode run(), akan tetapi
jika kita ingin melakukan hal lainnya, seperti getName(), sleep(), dan lainnya, kita harus
secara eksplisit memberikan referensi dengan menggunakan Thread.currentThread().

Ketika suatu kelas mengimplementasikan interface Runnable, artinya kelas ini memiliki metode
bernama run(), akan tetapi tidak berarti bahwa kelas ini bisa melakukan sesuatu seperti kelas
Thread atau kelas-kelas turunan yang kita buat dari kelas ini. Kita harus membuat objek Thread
sendiri seperti ditunjukkan dalam metode main() di atas, kemudian menjalankan start()
sendiri.

Kemudahan yang ditawarkan oleh interface Runnable adalah kemungkinan untuk


menggabungkannya dengan kelas dan interface lain. Misalnya kita ingin membuat kelas baru
yang merupakan kelas turunan dari suatu kelas lain. Kita cukup menambahkan impement
Runnable pada definisi kelasnya untuk membuat kelas yang bisa kita jadikan thread. Dengan
cara ini, kita masih bisa mengakses anggota kelas induk secara langsung, tanpa melalui objek
lain. Akan tetapi, kelas dalam (inner class) juga bisa mengakses anggota kelas luar (outer class).
Kadang-kadang kita ingin juga membuat kelas dalam yang merupakan turunan dari kelas
Thread.

Perhatikan beberapa variasi untuk mendeklarasikan dan menggunakan thread pada contoh
berikut ini.

package com.lyracc.variasithread;
 
// Kelas dalam bernama
class KelasDalamBernama {
private int hitungMundur = 5;
private Dalam dalam;
 
// Kelas Dalam adalah kelas dalam (inner class) yang
// merupakan kelas turunan kelas Thread
private class Dalam extends Thread {
Dalam(String nama) {
super(nama);
start();
}
 
public void run() {
while (true) {
System.out.println(getName() + " : " + hitungMundur);
if (--hitungMundur == 0)
return;
try {
sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
} // akhir Dalam
 
// Konstruktor KelasDalamBernama
// Membuat objek baru yang merupakan instansi kelas Dalam
public KelasDalamBernama(String nama) {
dalam = new Dalam(nama);
}
} // akhir KelasDalamBernama
 
// Kelas dalam anonim
class KelasDalamAnonim {
private int hitungMundur = 5;
private Thread t;
 
// Konstruktor KelasDalamAnonim
public KelasDalamAnonim(String nama) {
// Kelas anonim turunan Thread
t = new Thread(nama) {
public void run() {
while (true) {
System.out.println(getName() + " : " + hitungMundur);
if (--hitungMundur == 0)
return;
try {
sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}; // akhir kelas anonim
t.start();
}
} // akhir KelasDalamAnonim
 
// Kelas dalam implementasi runnable bernama
class KelasRunnableBernama {
private int hitungMundur = 5;
private Dalam dalam;
 
// Kelas Dalam adalah kelas dalam (inner class) yang
// merupakan kelas yang mengimplementasi Runnable
private class Dalam implements Runnable {
Thread t;
 
Dalam(String nama) {
t = new Thread(this, nama);
t.start();
}
 
public void run() {
while (true) {
System.out.println(t.getName() + " : " + hitungMundur);
if (--hitungMundur == 0)
return;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
} // akhir kelas Dalam
 
// Konstruktor KelasRunnableBernama
// Membuat objek baru yang merupakan instansi kelas Dalam
public KelasRunnableBernama(String nama) {
dalam = new Dalam(nama);
}
} // akhir KelasRunnableBernama
 
// Kelas dalam implementasi runnable anonim
class KelasRunnableAnonim {
private int hitungMundur = 5;
private Thread t;
 
public KelasRunnableAnonim(String nama) {
t = new Thread(new Runnable() {
public void run() {
while (true) {
System.out.println(Thread.currentThread().getName() + " :
" + hitungMundur);
if (--hitungMundur == 0)
return;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
 
}, nama); // akhir kelas dalam anonim
t.start();
}
} // akhir KelasRunnableAnonim
 
// Menjalankan thread dari dalam metode dan kelas anonim
class ThreadViaMetode {
private int hitungMundur = 5;
private Thread t;
private String nama;
 
public ThreadViaMetode(String nama) {
this.nama = nama;
}
 
public void runThread() {
if (t == null) {
// Definisi kelas anonim dari dalam metode
t = new Thread(nama) {
public void run() {
while (true) {
System.out.println(getName() + " : " + hitungMundur);
if (--hitungMundur == 0)
return;
try {
sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}; // akhir kelas dalam anonim
t.start();
}
}
} // akhir ThreadViaMetode
 
public class VariasiThread {
public static void main(String[] args) {
new KelasDalamBernama("KelasDalamBernama");
new KelasDalamAnonim("KelasDalamAnonim");
new KelasRunnableBernama("KelasRunnableBernama");
new KelasRunnableAnonim("KelasRunnableAnonim");
new ThreadViaMetode("ThreadViaMetode").runThread();
}
}

Jika kita menggunakan Runnable, pada dasarnya kita menyatakan bahwa kita ingin membuat
suatu proses -- yang implementasinya berada di dalam metode run() -- bukan suatu objek yang
melakukan proses tertentu. Tentunya hal ini tergantung dari cara pandang kita, apakah kita ingin
menganggap suatu thread sebagai objek atau sesuatu yang sama sekali berbeda, yaitu proses.

Jika kita menganggap suatu thread sebagai proses, tetntunya kita akan terbebas dari cara pandang
berorientasi objek yaitu "semuanya adalah objek". Artinya juga, kita tidak perlu membuat
seluruh kelas menjadi Runnable jika hanya kita ingin memulai proses di bagian tertentu program
kita. Karenanya, mungkin lebih masuk akal untuk menyembunyikan thread di dalam kelas kita
menggunakan kelas dalam.

KelasDalamBernama[.code] membuat kelas dalam yang merupakan kelas turunan dari


kelas Thread, dan membuat instansi kelas ini di dalam konstruktornya. Cara ini
baik jika kita ingin kelas dalam tersebut memiliki suatu kemampuan tertentu
(metode lain) yang ingin kita gunakan. Akan tetapi, seringkali kita membuat
thread hanya untuk memanfaatkan [code]Thread saja, artinya kita mungkin tidak perlu
membuat kelas yang memiliki nama.
KelasDalamAnonim adalah alternatif dari KelasDalamBernama di mana kelas dalamnya
merupakan kelas anonim yang merupakan kelas turunan dari kelas Thread. Kelas anonim ini
dibuat di dalam konstruktor dan disimpan dalam bentuk referensi t bertipe Thread. Jika metode
kelas lain membutuhkan akses ke t, maka kita bisa menggunakannya seperti Thread biasa tanpa
perlu mengetahui tipe objek t sesungguhnya.

Kelas ketiga dan keempat pada contoh di atas mirip dengan contoh pertama dan kedua, akan
tetapi menggunakan interface Runnable. Contoh ini hanya ingin menunjukkan bahwa
menggunakan Runnable tidak menambah nilai apa-apa, kecuali membuat kodenya lebih sulit
dibaca.

Kelas ThreadViaMetode menunjukkan bagaimana membuat thread dari dalam metode. Kita bisa
memanggil metode tersebut jika kita siap untuk menjalankan thread ini. Metode ini akan selesai
setelah thread berjalan. Jika thread hanya melakukan tugas sampingan, mungkin cara ini lebih
cocok daripada mengimplementasikan kelas khusus untuk melakukan fungsi-fungsi thread.

Berbagi Sumber Daya


Posted Sab, 05/23/2009 - 00:37 by belajarprogram

Versi ramah cetak

Kita bisa bayangkan sebuah program dengan thread tunggal hanya memiliki satu hal yang
berpindah dari satu bagian ke bagian lain secara harmonis, karena perpindahan data dari satu
tempat ke tempat lain diatur hanya oleh satu alur. Jika ada dua atau lebih thread yang
menggunakan, membaca, menulis, menghapus data yang sama, tentunya hal ini menjadi lebih
rumit. Kita harus bisa memahami bagaimana thread-thread bekerja sama dalam berbagi sumber
daya pada komputer, termasuk memori, hard disk, tampilan, input/output dan lain-lain, sehingga
program yang kita buat menjadi lebih baik.

Ini bukan hal yang mudah, terutama karena suatu thread bersifat non-deterministik. Kita tidak
bisa menentukan atau memprediksi kapan suatu thread akan dijalankan oleh penjadwal. Bisa saja
pada saat yang bersamaan dua thread mencoba untuk mengakses data yang sama, menghapus
data yang sama, melakukan debit di rekening yang sama, mencetak di printer yang sama,
menampilkan gambar di layar yang sama. Tabrakan sumber daya harus bisa dicegah sedini
mungkin.

Cara Buruk Mengakses Sumber Daya

Kita ambil contoh berikut, di mana suatu kelas "menjamin" bahwa ia akan memberikan angka
genap setiap kali kita memanggil ambilNilai(). Akan tetapi, ada thread kedua yang dinamakan
Hansip yang selalu memanggil ambilNilai() untuk mengecek apakah nilainya selalu genap.
Sepertinya ini cara yang tidak perlu, karena setelah kita melihat kode berikut, hasilnya pasti
selalu genap. Akan tetapi, kita akan melihat ada beberapa kejutan yang terjadi.

Berikut ini adalah program versi pertama.


package com.lyracc.selalugenap;
 
public class SelaluGenap {
private int i;
 
public void berikut() {
i++;
i++;
}
 
public int ambilNilai() {
return i;
}
 
public static void main(String[] args) {
final SelaluGenap genap = new SelaluGenap();
 
new Thread("Hansip") {
public void run() {
while (true) {
int nilai = genap.ambilNilai();
// Jika ganjil, keluar dan cetak nilainya
if (nilai % 2 != 0) {
System.out.println(nilai);
System.exit(0);
}
}
}
}.start();
 
while (true)
genap.berikut();
}
}

Pada metode main(), objek SelaluGenap akan dibuat -- sifatnya harus final karena objek ini
harus bisa diakses oleh kelas anonim yang berupa Thread. Jika nilai yang dibaca oleh thread
berupa bilangan ganjil, maka bilangan tersebut akan dicetak di layar kemudian keluar dari
program.

Apa yang terjadi adalah program pasti akan keluar dengan mencetak nilai ganjil. Ini berarti ada
ketidakstabilan dalam program tersebut. Ini adalah contoh masalah mendasar dengan
pemrograman banyak thread. Kita tidak pernah tahu kapan suatu thread akan jalan. Thread kedua
bisa jalan ketika thread pertama baru selesai menjalankan i++; yang pertama di dalam metode
berikut(). Di sini thread kedua menganggap ada kesalahan perhitungan, padahal proses belum
selesai.

Kadang-kadang kita memang tidak peduli ketika suatu sumber daya (dalam contoh di atas,
variabel i) sedang diakses apakah sedang digunakan atau tidak. Akan tetapi supaya program
banyak thread bisa bekerja dengan baik, kita harus mencegah supaya dua thread tidak mengakses
sumber daya yang sama, terutama di saat-saat kritis.
Mencegah tabrakan seperti ini bisa dicegah dengan meletakkan kunci pada sumber daya ketika
sedang digunakan. Thread pertama yang sedang mengubah variabel i seharusnya mengunci
variabel ini sehingga thread kedua yang ingin mengambil nilainya harus menunggu hingga
proses penambahan selesai.

Pemecahan Masalah Tabrakan Sumber Daya Bersama

Untuk memecahkan masalah tabrakan pada thread, hampir semua metode serentak melakukan
akses serial ke suatu sumber daya yang digunakan bersama. Artinya hanya satu thread yang bisa
mengakses suatu sumber daya pada suatu waktu. Biasanya hal ini dilakukan dengan membuat
kunci sehingga satu thread saja yang bisa mengakses kunci tersebut. Kunci ini sering disebut
mutex atau mutual exclusion.

Mari kita ambil contoh di rumah kita hanya ada satu kamar mandi. Beberapa orang (thread) ingin
masuk ke kamar mandi (sumber daya bersama), dan mereka ingin masuk sendirian. Untuk masuk
ke dalam kamar mandi, seseorang harus mengetok pintu untuk mengetahui apakah ada orang di
dalamnya. Jika tidak ada, maka mereka bisa masuk dan mengunci pintunya. Thread lain yang
mau menggunakan kamar mandi "diblok" sehingga tidak bisa masuk, sehingga thread harus
menunggu hingga seseorang keluar dari kamar mandi.

Analogi di atas sedikit berbeda jika ketika seseorang keluar dari kamar mandi dan ada beberapa
orang yang ingin mengakses kamar mandi secara bersamaan. Karena tidak ada "antrian" maka
kita tidak tahu siapa yang harus masuk berikutnya, artinya penjadwal thread bersifat non-
deterministik. Yang terjadi adalah, jika banyak orang menunggu di depan kamar mandi, maka
siapa yang paling dekat dengan kamar mandi akan masuk terlebih dahulu. Seperti telah diulas
sebelumnya, kita bisa memberi tahu penjadwal thread dengan perintah yield dan
setPriority() akan tetapi tetap saja masih sangat bergantung kepada JVM dan implementasi
pada suatu platform dan tidak bisa ditentukan dengan pasti siapa yang berhak masuk terlebih
dahulu.

Java memiliki fitur untuk mencegah terjadinya tabrakan sumber daya, yaitu dengan
menggunakan kata kunci synchronized. Ketika suatu thread berusaha untuk mengeksekusi
suatu perintah yang diberi kata kunci synchronized, Java akan mengecek apakah sumber daya
tersebut tersedia. Jika ya, maka kunci ke sumber daya tersebut akan diambil, kemudian perintah
dijalankan, dan setelah selesai melepaskannya kembali. Akan tetapi synchronized tidak selalu
berhasil.

Sumber daya bersama bisa berbentuk lokasi memori (dalam bentuk objek), atau bisa juga berupa
file, I/O atau bahkan printer. Untuk mengontrol akses ke sumber daya bersama, kita biasanya
membungkusnya dalam bentuk objek. Metode lain yang mencoba untuk mengakses sumber daya
tersebut bisa diberi kata kunci synchronized. Artinya jika thread sedang mengeksekusi salah
satu metode synchronized, thread lain diblok untuk mengeksekusi metode synchronized lain
dalam kelas itu hingga thread pertama selesai.
Karena biasanya data dari suatu kelas kita buat private dan akses ke memori hanya bisa
dilakukan dengan menggunakan metode, maka kita bisa mencegah tabrakan dengan membuat
metode menjadi synchronized. Berikut ini adalah contoh pendeklarasian synchronized.

synchronized void a() { /* perintah Anda di sini */ }


synchronized void b() { /* perintah Anda di sini */ }

Setiap objek memiliki kunci masing-masing yang otomatis dibuat ketka objek tersebut dibuat
(kita tidak perlu membuat kode spesial). Ketika kita memanggil metode yang diberi tanda
synchronized, objek tersebut dikunci dan tidak boleh ada lagi metode synchronized yang bisa
dieksekusi hingga metode sebelumnya selesai dijalankan dan kunci dilepas. Karena hanya ada
satu kunci untuk setiap objek, maka kita tidak mungkin menyimpan 2 data pada satu tempat pada
saat yang bersamaan.

Satu thread bisa mengunci objek beberapa kali. Ini terjadi jika satu metode memanggil metode
lain di kelas yang sama, kemudian metode tersebut memanggil metode lain lagi di kelas yang
sama dan seterusnya. JVM akan melacak berapa kali objek tersebut terkunci. Setiap kali suatu
metode selesai, kunci akan dilepas. Ketika objek tidak terkunci lagi, maka kuncinya bernilai 0,
yang artinya thread lain bisa mulai menggunakan metode pada objek ini.

Ada juga kunci per kelas, yang artinya kunci ini berlaku untuk suatu kelas. Otomatis semua
objek yang diciptakan dari kelas yang sama memiliki kunci bersama. Caranya yaitu dengan
menggunakan synchronized static metode sehingga suatu objek bisa juga mengunci kelas
sehingga objek lain yang menggunakan metode ini tidak bisa jalan apabila sedang digunakan
oleh objek lain.

Memperbaiki SelaluGenap

Kita akan ubah sedikit program SelaluGenap di awal bagian ini untuk memberikan kata kunci
synchronized pada metode berikut() dan ambilNilai(). Jika kita hanya meletakkan kunci
pada salah satu metode, maka metode yang tidak diberi kunci akan tetap bebas untuk dieksekusi
mengabaikan ada atau tidaknya kunci. Di sini lah kunci pemrograman serentak, di mana kita
harus memberi kunci di setiap akses ke sumber daya bersama.

Metode ini akan berjalan terus menerus, oleh karena itu kita akan gunakan waktuMulai untuk
menyimpan waktu ketika thread mulai berjalan, kemudian secara periodik mengecek waktu saat
ini. Jika proses sudah berjalan lebih dari 4 detik, kita hentikan proses kemudian mencetak
hasilnya.

package com.lyracc.selalugenapsynchronized;
 
public class SelaluGenapSynchronized {
private int i;
 
synchronized public void berikut() {
i++;
i++;
}
 
synchronized public int ambilNilai() {
return i;
}
 
public static void main(String[] args) {
final SelaluGenapSynchronized genap = new SelaluGenapSynchronized();
 
new Thread("Hansip") {
// mencatat waktu ketika thread dimulai
private long waktuMulai = System.currentTimeMillis();
public void run() {
while (true) {
int nilai = genap.ambilNilai();
// Jika ganjil, keluar dan cetak nilainya
if (nilai % 2 != 0) {
System.out.println(nilai);
System.exit(0);
}
// Selesaikan program jika sudah melewati 4 detik
if (System.currentTimeMillis() - waktuMulai > 4000) {
System.out.println(nilai);
System.exit(0);
}
}
}
}.start();
 
while (true)
genap.berikut();
}
}

Bagian Kritis

Kadang-kadang kita hanya ingin mencegah beberapa thread untuk mengakses sebagian kode saja
di dalam suatu metode, bukan keseluruhan metode. Bagian kode yang kita ingin lindungi ini
disebut bagian kritis (critical section) dan juga bisa dibuat dengan kata kunci synchronized.
Akan tetapi, kata kunci ini digunakan dengan menyatakan objek mana yang memiliki kunci yang
harus dicek sebelum bagian ini dijalankan.

Berikut ini adalah bentuk umum dari pernyataan synchronized untuk melindung bagian kritis :

synchronized(objekKunci) {
// Kode di bagian ini hanya bisa diakses
// Jika objekKunci sedang tidak diakses oleh thread lain
}

Bentuk umum di atas juga disebut blok tersinkron (synchronized block); sebelum blok ini bisa
dieksekusi, kunci pada objek objekKunci harus dicek terlebih dahulu. Jika thread lain telah
mengunci ojek ini, maka bagian kritis tidak bisa dimasuki hingga thread lain selesai dan melepas
kuncinya.
Siklus Hidup Thread
Posted Min, 05/24/2009 - 17:04 by belajarprogram

Versi ramah cetak

Suatu thread bisa berada dalam salah satu kondisi berikut :

1. Baru : Objek thread baru saja dibuat, akan tetapi belum mulai dijalankan, sehingga belum bisa
berbuat apa-apa.

2. Bisa-jalan : Artinya objek ini sudah dimulai dan sudah bisa dijalankan oleh mekanisme
pembagian waktu oleh CPU. Sehingga thread ini bisa jalan kapan saja, selama diperintahkan
oleh penjadwal thread.

3. Mati : suatu thread biasanya mati ketika selesai menjalankan metode run(). Sebelumnya, kita
bisa memanggi metode stop(), akan tetapi program bisa berada dalam kondisi tidak stabil jika
metode ini dipanggil. Kita akan lihat beberapa metode lain untuk menghentikan thread di bagian
berikutnya.

4. Diblok : Thread seharusnya bisa berjalan, akan tetapi ada yang menghalanginya. Salah satunya
adalah jika thread menunggu di bagian kritis sementara ada thread lain yang sedang menjalankan
bagian kritis tersebut. Ketika suatu thread berada dalam kondisi diblok, penjadwal thread akan
mengabaikannya dan tidak memberikan waktu CPU.

Bagaimana Suatu Thread Berada dalam Kondisi Diblok

Ketika suatu thread diblok, ada suatu alasan kenapa thread tersebut tidak bisa terus berjalan.
Suatu thread dapat diblok karena beberapa alasan sebagai berikut :

 Kita memberi perintah thread untuk tidur dengan sleep(milidetik) sehingga thread tidak
akan jalan dalam waktu yang sudah disebutkan
 Kita memerintahkan thread untuk menunggu dengan perintah wait(). Thread tidak akan
dijalankan kembali hingga diberikan pesan notify() atau notifyAll().
 Thread sedang menunggu selesainya operasi I/O
 Thread mencoba memanggil metode dengan kata kunci synchronized, akan tetapi thread lain
sedang memegang kuncinya.

Kerjasama Antar Thread


Posted Min, 05/24/2009 - 19:24 by belajarprogram

Versi ramah cetak

Setelah kita mengerti bagaimana thread bisa bertabrakan satu sama lain, dan bagaimana caranya
mencegah tabrakan antar thread, langkah berikutnya adalah belajar bagaimana membuat thread
dapat bekerja sama satu sama lain. Kuncinya adalah komunikias antar thread yang
diimplementasi dengan aman dalam metode-metode pada kelas Object, yaitu wait() dan
notify().

wait() dan notify()

Pertama-tama penting untuk mengerti bahwa sleep() tidak melepas kunci thread ketika
dipanggil. Artinya jika sleep() dipanggil dari dalam bagian kritis, maka thread lain tidak bisa
masuk hingga thread yang memanggil sleep() bangun, meneruskan eksekusi, hingga keluar
dari bagian kritis. Sedangkan wait() melepas kunci ketika dipanggil, sehingga thread lain bisa
masuk ke dalam bagian kritis.

Ada dua bentuk wait(). Yang pertama memiliki argumen waktu dalam bentuk mili detik (mirip
dengan sleep(). Perbedaannya dengan sleep() adalah :

 wait() melepaskan kunci


 Kita bisa membatalkan wait() dengan menggunakan notify() atau notifyAll(), atau
hingga waktu tunggu berlalu.

Bentuk kedua dari wait() adalah wait() yang tidak memiliki argumen. Jenis wait() ini akan
terus berlangsung hingga dibatalkan dengan notify atau notifyAll().

Aspek penting dari wait(), notify() dan notifyAll() adalah metode ini merupakan bagian
dari kelas dasar Obejct dan bukan bagian dari kelas Thread seperti sleep(). Meskipun
kelihatan janggal, hal ini sangat penting karena semua objek memiliki kunci. Artinya kita bisa
memanggil wait() dari dalam metode synchronized, tidak peduli apakah kelas tersebut
merupakan kelas turunan dari Thread atau bukan.

Sebetulnya satu-satunya tempat kita bisa memanggil wait(), notify() dan notifyAll()
adalah dari dalam blok atau metode synchronized. (sleep() bisa dipanggil dari manapun
karena ia tidak berhubungan dengan kunci suatu objek). Jika kita memanggil wait(), notify()
atau notifyAll() dari luar metode atau blok synchronized, compiler tidak akan
memperingatkan Anda, akan tetapi ketika program dijalankan, kita akan mendapatkan
pengecualian IllegalMonitorStateException dengan pesan kesalahan yang tidak dimengerti,
seprti "thread ini bukan pemiliknya". Pesan ini berarti bahwa thread yang memanggil wait(),
notify() atau notifyAll() harus memiliki kunci objek sebelum bisa memanggil salah satu
metode ini.

Kita juga bisa meminta suatu objek untuk memanipulasi kuncinya sendiri. Caranya, pertama-
tama kita harus mengambil kuncinya. Misalnya, jika kita ingin memanggil notify() ke suatu
objek x, kita harus melakukannya di dalam blok synchronized untuk mengambil kunci x,
seperti :

synchronized(x) {
x.notify();
}
Biasanya, wait() digunakan jika kita menunggu sesuatu yang dikontrol oleh sesuatu di luar
kontrol metode kita (di mana sesuatu ini hanya bisa diubah oleh thread lain). Kita tidak ingin
menunggu dan berulang-ulang menguji apakah sesuatu itu sudah tersedia, karena cara ini akan
memboroskan penggunaan CPU. Kita bisa menggunakan wait() untuk memerintahkan suatu
thread untuk menunggu hingga sesuatu tersebut berubah, dan hanya ketika notify() dipanggil,
maka thread tersebut akan bangun dan mengeceknya. Dengan kata lain wait() digunakan
melakukan aktifitas tak-sinkron antara beberapa thread.

Sebagai contoh, anggap suatu restoran memiliki satu orang koki dan satu orang pelayan. Pelayan
harus menunggu hingga si koki selesai memasak makanan. Ketika koki selesai, ia akan memberi
tahu pelayan, kemudian membawa makanan ini ke customer, kemudian menunggu kembali.
Koki di sini kita sebut sebagai produsen, dan pelayan disebut sebagai konsumen.

package com.lyracc.rumahmakan;
 
class Pesanan {
private int i = 0;
 
public Pesanan(int i) {
this.i = i;
}
 
public String toString() {
return "pesanan " + i;
}
} // akhir kelas Pesanan
 
class Pelayan extends Thread {
private RumahMakan rumahMakan;
 
public Pelayan(RumahMakan r) {
rumahMakan = r;
start();
}
 
public void run() {
while (true) {
while (rumahMakan.pesanan == null)
// tunggu hingga dipanggil dengan notify oleh Koki
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("Pelayan mengantarkan " + rumahMakan.pesanan);
// pesanan sudah diantar, pesanan sekarang kosong
rumahMakan.pesanan = null;
}
}
} // akhir kelas Pelayan
 
class Koki extends Thread {
private RumahMakan rumahMakan;
private Pelayan pelayan;
 
public Koki(RumahMakan r, Pelayan p) {
rumahMakan = r;
pelayan = p;
start();
}
 
public void run() {
// masak 10 makanan
for (int i = 0; i < 10; i++) {
if (rumahMakan.pesanan == null) {
rumahMakan.pesanan = new Pesanan(i);
System.out.print("Pesanan selesai! ");
// coba panggil pelayan jika tidak sibuk
synchronized (pelayan) {
pelayan.notify();
}
}
try {
sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("Makanan habis..");
System.exit(0);
}
} // akhir kelas Koki
 
public class RumahMakan {
Pesanan pesanan;
 
public static void main(String[] args) {
RumahMakan rumahMakan = new RumahMakan();
Pelayan pelayan = new Pelayan(rumahMakan);
new Koki(rumahMakan, pelayan);
}
}

Keluarannya ada sebagai berikut.

<img src="/sites/java.lyracc.com/files/kerjasamathread_gbr1.png" alt="" />

Pesanan adalah kelas sederhana yang berisi pesanan. Konstruktor menerima angka yang
diibaratkan seperti pesanan, kemudian membebanlebihkan metode toString() untuk mencetak
objek ini langsung dengan System.out.println().

Seorang Pelayan harus tahu RumahMakan tempat ia bekerja, karena ia harus ke sana untuk
mengantarkan pesanan dari "jendela pemesanan", yaitu rumahMakan.pesanan. Pada metode
run(), Pelayan masuk dalam mode menunggu. Kuncinya dimiliki oleh pelayan ini sendiri.
Kunci ini yang akan digunakan oleh Koki untuk membangunkan Pelayan jika makanan sudah
siap dengan metode notify().

Pada aplikasi yang lebih kompleks, misalnya jika pelayannya banyak, kita bisa memanggil
notifyAll() untuk membangunkan semua pelayan. Setiap pelayan nanti akan menguji apakah
panggilan itu untuknya atau tidak.

Perhatikan bahwa wait() ditulis di dalam pernyataan while untuk menguji apakah pesanan
sudah datang. Mungkin ini agak terasa ganjil karena ketika thread ini dibangunkan ketika
menunggu pesanan, seharusnya pesanannya sudah tersedia khan? Masalahnya jika aplikasinya
terdiri dari banyak pelayan, thread lain mungkin sudah keburu mengantarkan pesanannya ketika
thread ini sedang bangun. Untuk itu, lebih aman apabila kita menggunakan bentuk berikut untuk
semua aplikasi yang menggunakan wait() :

while (sesuatuYangDitunggu)
wait();

Dengan melakukan ini, kita menjamin bahwa kondisi di atas akan terpenuhi sebelum thread
mendapatkan sesuatu yang ditunggu. Jika thread sudah dibangunkan akan tetapi pesanan tidak
ada, maka thread akan kembali tidur.

Objek Koki harus tahu di rumah makan mana ia bekerja. Pesanan yang dia masak akan dia
letakkan pada jendela pesanan (dalam hal ini rumahMakan.pesanan) dan dia juga harus tahu
siapa Pelayan yang akan mengantarkan pesanan yang sudah selesai dimasak.

Pada contoh sederhana di atas, Koki membuat objek Pesanan, kemudian setelah selesai akan
memanggil Pelayan dengan notify(). Karena panggilan notify() dilakukan di dalam klausa
synchronized, maka sudah bisa dipastikan Koki memanggil pelayan jika pelayan tersebut
sedang tidak digunakan oleh thread lain.

Kunci Mati (Deadlock)


Posted Sen, 06/01/2009 - 00:34 by belajarprogram

Versi ramah cetak

Thread bisa diblok dan objek bisa memanggil metode synchronized ke suatu objek sehingga
objek lain tidak bisa mengakses objek tersebut hingga kuncinya dilepas. Karenanya mungkin
saja satu thread tersangkut menunggu suatu thread, akan tetapi thread yang ditunggu ini juga
sedang menunggu thread lain, dan seterusnya. Jika rangkaian kunci kembali ke thread pertama,
maka semua thread akan diam menunggu satu sama lain dan tidak akan pernah jalan. Kasus ini
dinamakan kunci mati (deadlock).

Jika program yang kita buat tiba-tiba mengalamai deadlock, kita akan segera tahu dan
memperbaikinya. Akan tetapi permasalahan utamanya adalah deadlock sulit untuk dideteksi.
Sering kali program yang kita buat tampak baik-baik saja, akan tetapi mungkin menyimpan
bahaya laten deadlock, yang suatu saat nanti terjadi ketika program sudah dirilis (bahkan sering
kali deadlock ini juga tidak bisa direproduksi sehingga menyulitkan debugging). Mencegah
deadlock dengan membuat desain program yang lebih hati-hati sangat penting ketika kita
membuat program banyak thread.

Mari kita lihat contoh klasik dari deadlock yang ditemukan oleh Dijkstra, yaitu "ilmuwan yang
sedang makan". Misalnya ada 5 orang ilmuwan (kita bisa mengganti berapa saja). Ilmuwan-
ilmuwan ini menghabiskan sebagian waktu untuk berfikir dan sebagian lagi untuk makan. Ketika
mereka berfikir, mereka tidak membutuhkan apa-apa, akan tetapi ketika mereka makan, mereka
duduk di meja dengan jumlah alat makan yang terbatas. Mereka membutuhkan dua garpu untuk
mengambil spaghetti dari mangkok di tengah meja.

Kesulitannya adalah karena ilmuwan tidak punya uang, mereka tidak mampu untuk membeli
banyak garpu. Hanya ada 5 garpu yang tersedia. Garpu-garpu ini diletakkan di meja tersebar di
dekat masing-masing ilmuwan ini. Ketika ilmuwan ingin makan, dia harus mengambil garpu di
sebelah kiri dan kanannya. Jika ilmuwan di sebelahnya sedang menggunakan garpu tersebut,
maka ia harus menunggu hingga garpunya selesai digunakan.

Persoalan ini menjadi menarik karena menjelaskan bahwa program yang sepertinya berjalan
dengan benar akan tetapi mudah terkena deadlock. Kita bisa mengganti beberapa konstanta
sehingga deadlock bisa lebih cepat terjadi, atau bisa dicegah sama sekali. Parameter-parameter
yang bisa diganti adalah konstanta bertipe final static int di awal deklarasi kelas
IlmuwanMakan. Jika kita menggunakan banyak ilmuwan dan waktu berfikir yang lama, deadlock
akan lebih jarang terjadi.

package com.lyracc.ilmuwanmakan;
 
import java.util.*;
 
class Garpu {
private static int hitung = 0;
private int nomor = hitung++;
 
public String toString() {
return "garpu " + nomor;
}
} // akhir kelas Garpu
 
class Ilmuwan extends Thread {
private static Random acak = new Random();
private static int hitung = 0;
private int nomor = hitung++;
private Garpu garpuKiri;
private Garpu garpuKanan;
static int waktuFikirMaks = IlmuwanMakan.WAKTU_FIKIR_MAKS;
 
public Ilmuwan(Garpu kiri, Garpu kanan) {
garpuKiri = kiri;
garpuKanan = kanan;
start();
}
 
// Ilmuwan berfikir, gunakan sleep untuk mensimulasi
public void berfikir() {
System.out.println(this + " berfikir");
try {
sleep(acak.nextInt(waktuFikirMaks));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
 
// Ilmuwan makan
public void makan() {
// cek apakah garpu kirinya tersedia
synchronized (garpuKiri) {
System.out.println(this + " punya " + this.garpuKiri
+ ". Menunggu " + this.garpuKanan);
 
// kemudian cek apakah garpu kanannya tersedia
synchronized (garpuKanan) {
System.out.println(this + " makan");
}
}
}
 
public String toString() {
return "Ilmuwan " + nomor;
}
 
// Metode ketika thread dijalankan
// masing-masing ilmuwan akan berfikir kemudian makan
// begitu seterusnya
public void run() {
while (true) {
berfikir();
makan();
}
}
} // akhir kelas ilmuwan
 
// Kelas timeout untuk menghentikan proses setelah
// waktu yang ditentukan
class Timeout extends Timer {
public Timeout(int jeda, final String pesan) {
super(true); // Daemon thread
schedule(new TimerTask() {
public void run() {
System.out.println(pesan);
System.exit(0);
}
}, jeda);
}
} // akhir kelas Timeout
 
// Kelas utama
public class IlmuwanMakan {
final static int JUMLAH_ILMUWAN = 3; // bisa diganti
final static int WAKTU_FIKIR_MAKS = 10; // mili detik, bisa diganti
final static boolean DEADLOCK = true; // ubah ini menjadi false untuk
mencegah deadlock
final static int WAKTU_TIMEOUT = 10000; // mili detik atau buat 0 jika
tidak ingin timeout
 
public static void main(String[] args) {
// Buat array ilmuwan sejumlah JUMLAH_ILMUWAN
Ilmuwan[] ilmuwan = new Ilmuwan[JUMLAH_ILMUWAN];
 
// Mula-mula buat 2 garpu
Garpu kiri = new Garpu();
Garpu kanan = new Garpu();
 
// Garpu pertama hanya sebagai penanda
// yaitu garpu di kiri ilmuwan pertama
Garpu pertama = kiri;
 
int i = 0;
 
// buat masing-masing ilmuwan
// yang pertama memiliki garpu kiri dan kanan
// ilmuwan kedua duduk di sebelah kanan ilmuwan pertama
// sehingga garpu kirinya adalah garpu kanan ilmuwan pertama
// buat garpu baru untuk garpu kanannya
// demikian seterusnya hingga JUMLAH_ILMUWAN minus 1
while (i < ilmuwan.length - 1) {
ilmuwan[i++] = new Ilmuwan(kiri, kanan);
kiri = kanan;
kanan = new Garpu();
}
 
// Sekarang buat ilmuwan terakhir
// Jika kita ingin membuat deadlock (makan menghadap meja) :
// - garpu kirinya adalah garpu kanan ilmuwan sebelumnya
// - garpu kanannya adalah garpu kiri ilmuwan pertama
//
// Jika tidak (makan berbalik arah)
// - garpu kirinya adalah garpu kiri ilmuwan pertama
// - garpu kanannya adalah garpu kanan ilmuwan sebelumnya
if (DEADLOCK)
ilmuwan[i] = new Ilmuwan(kiri, pertama);
else
ilmuwan[i] = new Ilmuwan(pertama, kiri);
 
// Keluar dari program setelah jeda waktu selesai
if (WAKTU_TIMEOUT > 0)
new Timeout(WAKTU_TIMEOUT, "Waktu habis..");
}
}

Kelas Garpu dan Ilmuwan menggunakan penghitung otomatis untuk memberi nomor
identifikasi tersendiri untuk setiap objek Garpu dan Ilmuwan yang diciptakan. Setiap Ilmuwan
diberi referensi ke garpu kiri dan garpu kanan. Garpu-garpu ini akan diambil oleh ilmuwan
ketika hendak makan.
Variabel statik waktuFikirMaks adalah waktu maksimum yang digunakan oleh ilmuwan untuk
berfikir. Jika nilainya tidak nol, maka nilai variabel ini akan digunakan sebagai argumen perintah
sleep() dalam kelas Ilmuwan. Mungkin kita beranggapan dengan mengubah waktu berfikir
setiap ilmuwan, mereka tidak akan makan secara bersamaan sehingga kemungkinan terjadinya
deadlock menjadi lebih kecil. Padahal sebenarnya tidak demikian.

Di dalam metode makan(), seorang ilmuwan akan mengambil garpu dengan melakukan
sinkronisasi pada garpu tersebut. Jika garpu sedang digunakan oleh ilmuwan lain, maka ilmuwan
tersebut akan menunggu hingga garpu selesai digunakan. Mula-mula garpu kiri dahulu yang
dicoba untuk diambil, baru kemudian garpu kanan. Setelah digunakan, garpu kanan akan dilepas
terlebih dahulu baru kemudian garpu kiri.

Dalam metode run() serorang ilmuwan makan dan berfikir terus menerus.

Ada empat konstanta yang bisa kita ubah-ubah di dalam kelas IlmuwanMakan. JUMLAH_ILMUWAN
dan WAKTU_FIKIR_MAKS adalah banyaknya ilmuwan yang ada dan waktu fikir ilmuwan seperti
dijelaskan sebelumnya. Variabel ketiga DEADLOCK berupa boolean yang bisa berisi true atau
false. Jika bernilai true maka program cepat atua lambat pasti akan mengalami deadlock.
Untuk menghindari deadlock, kita bisa menggantinya dengan false. Variabel keempat, yaitu
WAKTU_TIMEOUT digunakan untuk menghentikan semua proses pada waktu tertentu. Pada proses
yang sulit atau tidak mungkin deadlock (jika variabel DEADLOCK false, atau jumlah ilmuwan
banyak, atau waktu fikir ilmuwan sangat panjang), maka proses akan berhenti pada waktu time
out, seringkali sebelum deadlock terjadi.

Setelah array objek Ilmuwan dibuat, dua objek Garpu akan dibuat. Objek pertama, juga disimpan
dalam variabel pertama akan digunakan kemudian. Setiap objek ilmuwan akan diberi garpu kiri
dan kanannya, kecuali objek ilmuwan terakhir. Setiap kali, garpu kiri dipindah ke garpu kanan.
Bayangkan meja ilmuwan dibuat dalam urutan melingkar berlawanan arah jarum jam. Garpu kiri
ilmuwan baru adalah garpu kanan ilmuwan sebelumnya. Sedangkan garpu kanan ilmuwan baru
adalah objek garpu baru.

Pada versi di mana DEADLOCK bernilai true, garpu kiri ilmuwan terakhir adalah garpu kanan
ilmuwan sebelumnya, akan tetapi garpu kanannya adalah garpu pertama, karena semua ilmuwan
duduk pada posisi melingkar. Dengan pengaturan seperti ini, mungkin saja pada suatu waktu
semua ilmuwan akan makan dan saling menunggu garpu di sebelahnya, dan ilmuwan sebelahnya
menunggu garpu sebelahnya lagi. Dan karena posisi duduknya melingkar, semua saling
menunggu satu sama lain.

Coba ganti variabelnya dengan beberapa nilai dan amati seberapa cepat deadlock terjadi.
Deadlock ditandai dengan semua ilmuwan saling menunggu satu sama lain hingga waktu time
out berakhir. (Seperti pada gambar berikut).
Untuk memecahkan masalah ini, kita harus mengerti bahwa deadlock bisa terjadi jika keempat
kondisi berikut ini terjadi pada saat yang sama :

1. Saling melarang (mutual exclusion): Paling sedikit salah satu sumber daya yang digunakan objek
tidak boleh digunakan bersama. Dalam hal ini, satu garpu bisa digunakan oleh dua orang
ilmuwan
2. Paling sedikit salah satu proses sedang memegang suatu sumber daya, dan di saat yang sama
menunggu sumber daya lain yang dipegang oleh proses lain. Dalam hal ini, agar deadlock terjadi,
seorang ilmuwan pasti sedang memegang satu garpu dan menunggu garpu lain yang dipegang
oleh ilmuwan lain.
3. Suatu sumber daya tidak bisa diambil secara paksa. Proses hanya bisa melepas sumber daya
dalam kondisi normal. Ilmuwan-ilmuwan kita adalah orang yang beradab, sehingga tidak bisa
merebut garpu yang sedang dipegang oleh ilmuwan lain.
4. Lingkaran menunggu sedang terjadi, di mana proses pertama sedang menunggu satu sumber
daya yang dipegang oleh proses kedua, yang juga sedang menunggu sumber daya yang dipegang
oleh proses ketiga, dan seterusnya hingga proses terakhir menunggu sumber daya yang
dipegang oleh proses pertama, sehingga semua proses saling menunggu satu sama lain. Pada
contoh ini, lingkaran menunggu terjadi karena semua ilmuwan mengambil garpu kiri terlebih
dahulu baru kemudian garpu kanan. Kita bisa memecahkan deadlock dengan membalik garpu
kiri dan garpu kanan pada ilmuwan terakhir, sehingga ilmuwan terakhir akan mengambil garpu
kanan terlebih dahulu, baru kemudian garpu kiri.

Karena semua kondisi di atas harus terjadi secara bersama-sama agar deadlock bisa terjadi, maka
untuk mencegah terjadinya deadlock, kita harus memecah salah satu kondisi saja. Pada program
ini, cara termudah adalah dengan memecah kondisi keempat. Akan tetapi ini bukan satu-satunya
pemecahan, kita bisa memecahkannya dengan teknik yang lebih canggih. Untuk ini saya
mereferensikan Anda pada buku-buku teknik threading tingkat lanjut untuk lebih detailnya.

Kesimpulannya, Java tidak menyediakan bantuan secara alami untuk mencegah deadlock: Anda
harus menghindarinya sendiri dengan membuat program multi threading dengan lebih hati-hati.

Sisipan Ukuran
Komentar
Ralat
by yadieet - 09/16/2009 - 17:57

Synchronization merupakan mekanisme pengaksesan suatu resource (bukan 'object' seperti yang
tertulis pada comment saya diatas). Meskipun telah diralat, tetap saja ini tidak menjelaskan
definisi synchronization serta mekanismenya sama sekali. Mohon maaf.

 balas

Hallo, sebenarnya sudah


by belajarprogram - 09/16/2009 - 18:05

Hallo, sebenarnya sudah ditulis dengan menggunakan ilustrasi kamar mandi di sini.

 balas

Sorry.. but..
by yadieet - 09/15/2009 - 22:01

.. not really !

-----------------------------------------------------------

Pada baris 1 -> "..sehingga objek lain tidak bisa mengakses objek tersebut". Ini salah !

Seharusnya -> "..sehingga Thread lain tidak bisa mengakses objek tersebut".

COMMENT :

- Synchronization merupakan suatu mekanisme pengaksesan suatu object. Suatu object dapat
diakses secara synchron atau usynchron.

Pertanyaannya adalah "SIAPA YANG MENGAKSES OBJECT ?"

Yang mengakses Object tidak lain adalah Thread.

Tidak pernah ada Object mengakses Object. Yang ada adalah suatu class|object|method 'calling'
(memanggil) suatu class|object|method lain.

Hati2 dalam penggunaan kata|bahasa.

-----------------------------------------------------------
Pada baris 2 -> 'KUNCI'

COMMENT :

'Kunci' ? Key ? Or Lock ?

Jangan terjemahkan kata 'LOCK' dengan 'KUNCI' karena 'KUNCI' jika di bahasa Inggriskan
maka jadinya 'KEY'. Sedangkan kata 'KEY' dan 'LOCK' di bahasa Inggris memiliki definisi yang
berbeda karena 'KEY' adalah kata benda sedangkan 'LOCK' adalah kata kerja.

---------------------------------------------------------------------------------------------------------------------
----

jika ada 'LOCK' di JAVA, maka ada 'BLOCK' di JAVA.

jika ada 'LOCKING', di JAVA maka ada 'BLOCKING' di JAVA.

jika ada 'KEY' di JAVA, ini namanya NGACO ! (kecuali interface java.security.Key)

---------------------------------------------------------------------------------------------------------------------
----

Saran :

kata 'LOCK' mungkin dapat diganti dengan kata 'PENGUNCIAN' sehingga tidak berubah
maknanya.

Jangan terjemahkan seluruh istilah JAVA, istilah pemprograman, atau istilah komputer 100% ke
bahasa Indonesia. Jangan menghalalkan segala cara untuk membuat pembaca faham, malah
jadinya bertambah bingung.

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

Pada bagian 'Kerjasama Antar Thread' tertulis : "Setiap object memiliki kunci". Mungkin yang
dimaksud Kunci disini tidak lain adalah 'Object Monitor'. Tidak masalah jika 'Object Monitor' di
ibaratkan seperti 'KUNCI' yang mana ANAK KUNCI nya dipegang oleh suatu Thread pada
suatu pengaksesan secara SYNCHRON. Tapi jika kata 'LOCK' diterjemahkan 'KUNCI', ini tidak
masuk akal.

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

Btw, mengapa definisi DEADLOCK tidak ditulis ? Kasus DEADLOCK ada yang sederhana dan
ada yang rumit.

Btw, kalo ingin menjelaskan pengertian DEADLOCK tidak perlu menggunakan contoh kasus
yang serumit itu.
Malah membuat pembaca bingung.

 balas

Terima kasih atas inputnya.


by belajarprogram - 09/15/2009 - 22:41

Terima kasih atas inputnya. Saya coba perbaiki mana yang salah tapi juga saya mau sedikit
komentari komentar Anda.

1. Objek mengakses objek. Pada Java, thread sendiri adalah suatu objek. Thread sendiri adalah
suatu unit proses, objek berada di dalam thread. Ibaratnya thread adalah baskom dan objek ada di
dalam baskom. It doesn't make sense kalo baskom mengakses objek. Yang ada suatu objek
mengakses objek lain via thread, either the same thread or different one. Mengakses bisa
memanggil method, mengambil isi variabel, atau mengubah isi variabel suatu objek.

2. Saya setuju jika kunci dalam bahasa Inggris bisa berarti Key atau Lock. Ini karena ambigu
dalam bahasa Indonesia sendiri. Kebanyakan orang Indonesia menganggap kunci adalah anak
kunci, yaitu sesuatu yang bisa dibawa di dalam kantong (i.e. kunci mobil, kunci rumah). Kita
juga menganggap kunci yang menempel di pintu (tempat memasukkan anak kunci) disebut
kunci. Sedangkan dalam bahasa inggris, key dan lock adalah dua barang berbeda yang saling
berpasangan. Dalam bahasa Inggris, lock tidak mungkin masuk kantong kecuali lock untuk
koper.

Lock dan key sendiri bukan hanya kata kerja atau kata benda. Lock bisa berupa kata kerja atau
kata benda. Demikian juga key, bisa kata kerja atau kata benda. Silakan lihat artinya sendiri di
http://dictionary.reference.com/browse/lock dan http://dictionary.reference.com/browse/key

Tapi "kunci dilepas" sudah pasti "lock is released", bukan "key is released", karena makna yang
kedua kuncinya dijatuhkan, which doesn't make sense. Lock sendiri bukan cuma kata kerja, tapi
juga kata benda, yang artinya bisa kunci atau gembok. Sedangkan key artinya anak kunci. Key
ngga pernah nyantel di garasi, tapi nyantel di gembok yang nyantel di garasi. Sementara "key"
untuk security itu persis artinya anak kunci. Karena anak kunci ini digunakan untuk membuka
kotak (atau pesan) rahasia.

Anyway, saya coba perbaiki lagi tata bahasanya untuk masalah kunci ini. Memang agak susah
jika kita belajar Java via bahasa Inggris atau bahasa Indonesia campur Inggris jadinya runyam.
Apalagi bahasa Indonesia sangat terbatas dibandingkan bahasa Inggris.

3. Definisi deadlock sudah diilustrasikan di paragraf pertama.

Terima kasih untuk inputnya, semoga menjelaskan apa yang saya maksud

Pengenalan GUI dengan Eclipse SWT


Posted Min, 04/26/2009 - 21:12 by belajarprogram
Versi ramah cetak

SWT adalah GUI berbagai platform yang dikembangkan oleh IBM. Kenapa IBM membuat
sistem GUI lain dan tidak menggunakan rangka kerja GUI yang sudah ada pada Java? Untuk
menjawab pertanyaan ini, kita perlu melihat kilas balik tentang Java di awal perkembangannya.

Sun telah membuat rangka kerja GUI yang dinamakan AWT (Abstract Windowing Toolkit).
Rangka kerja AWT menggunakan widget (komponen pada GUI, seperti tombol, menu, teks, dll)
alami yang merupakan bawaan dari setiap sistem operasi. Akan tetapi widget tersebut memiliki
masalah pada LCD. Masalah LCD ini mengakibatkan hilangnya beberapa fitur pada sistem
operasi lain. Atau dengan kata lain, jika platform A memiliki widget 1 - 40 dan platform B
memiliki widget 20 - 25, maka rangka kerja AWT hanya bisa digunakan untuk sebagian widget
yang beririsan saja.

Untuk memecahkan masalah ini, Sun membuat rangka kerja baru yang merupakan emulasi
widget, bukan menggunakan widget bawaan platform. Hal ini memecahkan masalah LCD dan
memberikan rangka kerja yang kaya widget, akan tetapi masalah lain muncul. Misalnya, aplikasi
Swing tidak lagi mirip seperti aplikasi lain pada platform di mana ia dijalankan.

Dengan adanya perbaikan pada JVM, aplikasi Swing tetap saja mengalami masalah kinerja
karena sifatnya yang berupa emulasi. Hal ini tidak ditemukan pada widget bawaan platform
karena widget ini lebih dekat dengan sistem operasi. Lebih jauh, aplikasi Swing menghabiskan
lebih banyak memori yang tidak bisa digunakan untuk piranti kecil seperti PDA dan telepon
genggam.

IBM memutuskan bahwa pendekatan tersebut tidak memenuhi kebutuhannya. Akhirnya, IBM
membuat pustaka GUI baru yang disebut SWT, yang memecahkan masalah yang terdapat pada
rangka kerja AWT dan Swing. Rangka kerja SWT langsung mengakses widget bawaan sistem
operasi melalui JNI. Jika widget tersebut tidak tersedia, maka SWT akan mengemulasi widget
yang hilang itu.

Blok Penyusun Suatu Aplikasi SWT

Display, Shell dan kumpulan Widget adalah blok penyusun aplikasi SWT. Display bertugas
untuk mengatur perulangan event (dari keyboard atau mouse) dan mengatur komunikasi antara
thread UI dan thread lainnya. Shell adalah jendela di mana aplikasi berjalan. Setiap aplikasi SWT
memiliki paling tidak satu Display dan satu atau lebih instansi Shell.
Gambar di atas mengilustrasikan aplikasi SWT dari sudut pandang yang berbeda. Diagram
pertama di sebelah kiri adalah diagram kelas-kelas turunan dari objek-objek UI. Diagram tengah
adalah bagaimana objek UI diletakkan, dan gambar kanan adalah UI yang dihasilkan.

Jika suatu aplikasi menggunakan beberapa thread, setiap thread akan memiliki instansi objek
Display masing-masing. Kita bisa mengambil instansi suatu objek Display dengan menggunakan
metode statik Display.getCurrent().

Suatu Shell melambangkan jendela suatu aplikasi. Shell bisa ditampilkan dalam ukuran seluruh
layar, ukuran biasa, atau dikecilkan hingga tak terlihat. Ada dua jenis shell yang tersedia. Yang
pertama adalah shell dengan tingkat paling tinggi, yaitu yang dibuat langsung sebagai anak dari
jendela utama Display. Jenis kedua adalah shell dialog yang bergantung pada shell-shell lainnya.

Jenis suatu Shell bergantung pada bit gaya (style bit) yang diberikan pada konstruktornya. Nilai
awalnya adalah DialogShell. Artinya, jika tidak ada parameter yang diberikan pada
konstruktornya, maka shell yang dibuat akan bertipe DialogShell. Jika parameter
konstruktornya berupa objek bertipe Display, maka ia akan menjadi shell tingkat atas.

Beberapa sifat widget harus ditentukan pada saat widget tersebut dibuat. Sifat widget tersebut
disebut bit gaya (style bit). Bit gaya ini adalah konstanta yang didefinisikan dalam kelas SWT.
Misalnya,

Button tombol = new Button(shell, bitGaya)

Kita bisa menggunakan lebih dari satu gaya dengan menggunakan operator OR atau |. Misalnya,
kita ingin membuat tombol yang bisa ditekan dan memiliki garis tepi, kita bisa menggunakan
SWT.PUSH | SWT.BORDER sebagai parameter bit gayanya.

 Memulai SWT
 Widget-widget SWT
Memulai SWT
Posted Min, 04/26/2009 - 22:34 by belajarprogram

Versi ramah cetak

Untuk memulai pemrograman dengan SWT, mari kita buat program sederhana yang kita
namakan HelloSWT.

 Anda membutuhkan "link" ke pustaka SWT. Ada dua cara untuk melakukannya :

1. Menggunakan pustaka SWT bawaan dari Eclipse. Untuk ini Anda tidak perlu mendownload apa-
apa. Pustaka SWT bawaan eclipse terdapat pada direktori Eclipse Anda, misalnya pada Windows
(C:\eclipse\plugins\org.eclipse.swt.win32.win32.x86_3.4.1.v3449c.jar) atau pada Linux
(eclise/plugins/org.eclipse.swt.gtk.linux.x86_3.4.1.v3452b.jar)
2. Menggunakan pustaka SWT beserta sumber kodenya untuk dokumentasi lebih lengkap. Pustaka
SWT ini bisa diunduh pada alamat berikut : http://www.eclipse.org/swt/. Pilih Releases -> Stable
-> (platform Anda, misalnya Windos atau Linux). Setelah diunduh, import ke dalam Eclipse
seperti Anda mengimport proyek-proyek pada website ini, yaitu dengan File -> Import ->
General -> Existing Projects Into Workspace -> Select Archieve File -> (file zip SWT hasil
download) -> Finish. Langkah ini hanya dilakukan satu kali saja.

 Buat proyek baru dari Eclipse, File -> New -> Java Project, kemudian isi Project Name dengan
HelloSWT dan click Next
 Kita harus menambahkan pustaka SWT ke dalam proyek kita.

1. Jika Anda menggunakan SWT bawaan Eclipse seperti di atas, pilih halaman Libraries. Klik Add
External JAR, kemudian navigasi ke direktori plugin di dalam instalasi Eclipse Anda. Misalnya di
komputer saya, direktori itu berada di C:\eclipse\plugins. Pilih JAR untuk SWT pada direktori
tersebut. Namanya tergantung dari sistem operasi Anda, misalnya pada Windows file ini
bernama org.eclipse.swt.win32.win32.x86_3.4.1.v3449c. Klik OK setelah file ini
ditambahkan di dalam folder Libraries.
1. Jika Anda mengunduh proyek SWT, pilih halaman Projects. Klik Add, kemudian tambahkan
org.eclipse.swt. Kemudian klik OK setelah proyek ini ditambahkan.
 Folder proyek baru akan dibuat, seperti pada gambar berikut. 
 Kemudian klik kanan pada folder src, dan pilih New -> Class. Isi nama kelas dengan HelloSWT,
nama package dengan helloswt, dan tik "public static void main(String[] args)" untuk membuat
metode main() secara otomatis.

 Ketik kode berikut ini di dalam metode main()

Display display = new Display();


Shell shell = new Shell(display);
shell.setLayout( new RowLayout());
Label label = new Label(shell, SWT.NONE);
label.setText("Hello, World!");
shell.pack();
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
label.dispose();

 Perhatikan bahwa Display, Shell, RowLayout dan Label diberi tanda merah sebagai tanda
bahwa kesalahan program terjadi.

 Sekarang pindahkan mouse Anda pada kesalahan pada kelas Display. Eclipse akan memberi
tahu Anda kesalahan apa yang terjadi. Pada contoh ini, kelas ' Display' belum diketahui oleh
Eclipse. Klik pada pilihan Import 'Display' (org.eclipse.swt.widgets).  Lihat sekarang di awal
program Anda Eclipse menambahkan import org.eclipse.swt.widgets.Display;
secara otomatis.

 Lakukan hal yang sama pada semua kesalahan, yaitu Shell, Label, RowLayout dan
SWT.NONE, sehingga tidak ada lagi kesalahan yang dilaporkan oleh Eclipse.
 Untuk menjalankan program Anda, klik tombol Run seperti pada gambar berikut.

 Berikut ini adalah tampilan program SWT pertama Anda.

 Mengkompilasi dan Membuat Program SWT Berjalan di Luar Eclipse


 Melihat Lebih Dekat HelloSWT
 Pengenalan Konsep Widget pada SWT
 Event dan Listener
Mengkompilasi dan Membuat Program SWT Berjalan di Luar Eclipse
Posted Sab, 05/02/2009 - 01:10 by belajarprogram

Versi ramah cetak

Untuk bisa membuat program kita berguna untuk orang lain, kita harus bisa mengkompilasi dan
membuat program tersebut sebagai satu "paket". Proses ini disebut menyebarkan (deploy). Pada
Eclipse, program yang telah kita buat bisa kita deploy dalam format JAR (Java Archive), yang
menggabungkan semua file kelas yang sudah dikompilasi beserta pustaka yang dibutuhkan untuk
bisa menjalankan program tersebut.

Mari kita lihat contoh program HelloSWT yang sudah dibahas sebelumnya. Untuk men-deploy
program ini sehingga bisa dijalankan di luar Eclipse, lakukan langkah-langkah berikut :

 Klik kanan pada nama proyek Anda, kemudian pilih Export. Setelah itu kotak dialog akan
terbuka. Kemudian pilih Runnable JAR File dari dalam folder Java.
 Pilih HelloSWT - HelloSWT pada Launch configuration dan juga masukkan di mana file JAR
hasilnya akan ditempatkan. Jika nama direktori tidak diberikan, Eclipse akan meletakkan file JAR
tersebut pada direktori di mana workspace berada, yaitu di mana data proyek ditempatkan.
(Misalnya, di komputer saya proyek HelloSWT berada pada direktori
C:\belajarjava.lyracc.com\HelloSWT, maka file JAR tersebut akan diletakkan pada direktori
C:\belajarjava.lyracc.com\)
 Klik Finish, kemudian OK untuk setiap pertanyaan yang mungkin muncul berikutnya. Sekarang,
gunakan Windows Explorer untuk mencari di mana file JAR hasilnya berada. Double click pada
file tersebut dan Anda akan bisa menjalankannya langsung seperti aplikasi lainnya. Anda bisa
juga mengirimkan file ini melalui email atau mengkopinya melalui flash disk ke teman atau
kerabat Anda tanpa perlu menyertakan Eclipse.
 CATATAN : Ingat bahwa SWT bergantung penuh pada sistem operasi yang Anda gunakan,
karena SWT menggunakan widget bawaan sistem operasi seperti dijelaskan pada bagian
sebelumnya. Ketika Anda membuat program ini pertama kali, Anda menambahkan pustaka SWT
yang spesifik terhadap sistem operasi di mana Eclipse berjalan. Artinya, jika Anda menambahkan
pustaka org.eclipse.swt.win32.win32.x86_3.4.1.v3449c, maka program JAR Anda hanya akan
bisa dijalankan pada sistem operasi Windows. Untuk bisa menjalankannya pada sistem operasi
lain, misalnya Linux, maka Anda harus menambahkan pustaka SWT khusus Linux yang bisa
diunduh secara terpisah atau menggunakan Eclipse pada Linux.
 Berikut ini adalah screen shot hasil jalannya program

Melihat Lebih Dekat HelloSWT


Posted Sab, 05/02/2009 - 03:59 by belajarprogram
Versi ramah cetak

Secara umum aplikasi SWT membutuhkan beberapa langkah sebagai berikut :

1. Buat Display baru


2. Buat satu atau lebih Shell
3. Buat manager layout untuk Shell baru
4. Buat widget di dalam shell
5. Buka jendela shell
6. Buat perulangan pengirim event
7. Buang (dispose) display dan widget-widget lainnya
8. Tentunya import berbagai paket yang diperlukan oleh program

package helloswt;
 
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
 
public class HelloSWT {
 
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout( new RowLayout());
Label label = new Label(shell, SWT.NONE);
label.setText("Hello, World!");
shell.pack();
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
label.dispose();
}
}

Mari kita bahas satu per satu

1. Membuat Display baru

Membuat Display dapat dilakukan dengan membuat instansi dari objek bertipe Display, misalnya
seperti perintah berikut

Display display = new Display();


Display (tampilan) adalah objek maya yang merupakan kontainer induk semua komponen GUI.
Suatu tampilan sebetulnya tidak terlihat, akan tetapi komponen yang ditambahkan ke dalam
tampilan dapat dilihat. Biasanya, suatu aplikasi hanya membutuhkan satu tampilan.

2. Membuat Shell baru

Membuat Shell dapat dilakukan dengan membuat instansi dari objek bertipe Shell, misalnya
seperti perintah berikut

Shell shell = new Shell(display);

Pada pernyataan di atas, konstruktor Shell mengambil parameter yang merupakan induk di
mana shell ini akan diletakkan. Pada pernyataan di atas, kita membuat objek shell bertipe
Shell yang memiliki induk objek display.

Shell adalah jendela suatu aplikasi. Shell tertinggi adalah shell yang berada langsung di bawah
objek bertipe Display, dan merupakan jendela utama suatu aplikasi. Shell sebenarnya adalah
widget komposit, yaitu suatu widget yang terdiri dari beberapa widget lain. Oleh karenanya shell
juga bisa berisi shell lain. Untuk aplikasi sederhana yang menampilkan kata "Hello World!", kita
hanya membutuhkan satu shell saja yang kita letakkan pada objek display.

3. Membuat manager layout untuk Shell baru

Untuk membuat manager layout, kita menggunakan metode instansi dari objek shell, yaitu
setLayout() yang mengambil parameter jenis layout yang akan disusun pada shell. Misalnya,

shell.setLayout( new RowLayout());

Pada contoh di atas, kita memerintahkan objek shell untuk mengatur widget-widget di dalamnya
dalam urutan seperti baris. RowLayout adalah kelas layout yang digunakan objek shell untuk
mengatur objek widget di dalamnya.

Manager layout digunakan untuk mengatur secara otomatis peletakkan setiap widget. Pada SWT,
objek komposit seperti Shell tidak mengetahui bagaimana widget harus ditampilkan. Oleh
karenanya jika kita tidak memberikan manager layout kepada objek bertipe Shell, maka tidak ada
widget yang akan ditampilkan.

Bahasan khusus tentang layout cukup kompleks, dan karenanya kita akan bahas tersendiri pada
bagian selanjutnya.

4. Membuat widget di dalam shell

Widget adalah komponen pembangun GUI. Menu, tombol, teks, kotak cek, kotak input teks,
hingga kanvas, adalah contoh-contoh widget. Setiap widget memiliki sifat dan cara kerja yang
berbeda-beda. Pada contoh ini, kita menggunakan widget yang sangat sederhana yang
dinamakan Label. Widget ini digunakan untuk menampilkan teks, misalnya digunakan sebagai
label atau pertanyaan pada suatu input teks.

Pada contoh HelloSWT, kita gunakan konstruktor yang mengambil 2 parameter. Yang pertama,
adalah kontainer induk di mana Label ini akan ditampilkan, dan parameter kedua adalah bit gaya.

Label label = new Label(shell, SWT.NONE);

Label ini kemudian kita isi dengan kata "Hello Word!" untuk menampilkan kata ini pada jendela
utama.

label.setText("Hello, World!");

5. Membuka jendela shell

Setelah Display, Shell, dan widget-widgetnya disiapkan, kita perlu secara eksplisit
memerintahkan shell untuk membuka jendela dan menggambar seluruh widget yang sudah
disiapkan. Untuk ini kita gunakan perintah

shell.open();

6. Membuat perulangan pengirim event

SWT mengharuskan kita untuk membuat sendiri perulangan untuk mengirimkan event. Artinya,
blok perintah berikut ini "harus" selalu ada dalam semua aplikasi SWT yang akan kita buat.

while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();

7. Membuang (dispose) display dan widget-widget lainnya

Karena SWT bekerja langsung dengan widget bawaan sistem operasi, maka tanggung jawab
untuk menghapus komponen GUI ada di tangan programmernya. Hal ini disebabkan widget
tersebut berada di luar jangkauan pemulung memori Java yang hanya bisa meraih objek yang
dibuat dan dijalankan dalam JVM (Java Virtual Machine).

Untuk menghapus widget dari memori, kita dapat menggunakan metode dispose() yang
dimiliki oleh hampir semua widget SWT. Pada contoh program ini, kita memiliki 2 widget, yaitu
shell dan label, sehingga keduanya harus dihapus dengan menggunakan perintah

display.dispose();
label.dispose();

8. Mengimport berbagai paket yang diperlukan oleh program

Kita bisa menggunakan Eclipse untuk membantu kita mengimpor setiap paket (seperti yang
diilustrasikan pada bagian sebelumnya), atau menggunakan wildcard seperti import
org.eclipse.swt.widgets.*
Beberapa paket penting yang tersedia pada SWT :

Nama Paket Kegunaan

Berisi kelas SWT, kumpulan konstanta, dan kelas-kelas pengecualian dan


org.eclipse.swt
kesalahan

Widget dan kelas-kelas yang berhubungan dengannya, misalnya menu,


org.eclipse.swt.widgets kotak dialog, dukungan event, kelas super abstrak untuk layout, dan
sebagainya

org.eclipse.swt.events Event tingkat tinggi, pendengar event, dan colokan (adapter)

Kelas layout standar seperti FillLayout, RowLayout, GridLayout, FormLayout,


org.eclipse.swt.layout
dan kelas-kelas lainnya

Huruf, warna, gambar, dan operasi grafik dasar, seperti untuk menggambar
org.eclipse.swt.graphics
garis dan lingkaran

Widget buatan sendiri dan kelas lain yang dibuat khusus untuk Eclipse; tidak
org.eclipse.swt.custom bergantung pada platform apapun (implementasinya sama pada semua
sistem operasi)

org.eclipse.swt.dnd Kelas bantuan untuk melakukan drag-and-drop pada berbagai platform

org.eclipse.swt.accessibility Perluasan untuk memberikan bantuan dan dukungan untuk orang cacat

org.eclipse.swt.printing Dukugan printer dan kotak dialog untuk melakukan percetakan

Berisi kelas Program, untuk mempermudah pada saat program dijalankan,


pemetaan dokumen, dan icon; juga dibuat untuk Eclipse, akan tetapi sangat
org.eclipse.swt.program
bergantung pada platformnya (implementasinya bisa berbeda untuk setiap
sistem operasi)

Menyediakan widget sebagai web broswer, dan kelas-kelas yang


org.eclipse.swt.browser mendukungnya. Menggunakan browser bawaan sistem operasi untuk
implementasinya

Menyediakan dukungan untuk membuat UI yang berisi campuran widget


org.eclipse.swt.awt
dari SWT dan AWT

Hanya tersedia pada Windows; menyediakan fasilitas untuk mengakses OLE


org.eclipse.swt.win32.ole
(Object Linking and Embedding)
Pengenalan Konsep Widget pada SWT
Posted Min, 05/03/2009 - 01:28 by belajarprogram

Versi ramah cetak

Secara tradisional, widget bisa dibayangkan seperti perangkat abstrak yang berguna untuk
melakukan tugas tertentu. Istilah ini popules dalam bidan ekonomi. Para pembuat software
meminjam istilah ini untuk menyebut suatu paket program pembuat GUI (grahical user
interface). SWT adalah kepanjangan dari Standard Widget Toolkit karena widget merupakan
dasar pembangun suatu aplikasi yang dibangun dengan menggunakan SWT.

Apa itu widget?

Widget adalah elemen GUI yang dapat berinteraksi dengan user. Widget mengatur dan
menentukan kondisinya sendiri dengan memggunakan kombinasi beberapa operasi grafik.
Dengan menggunakan mouse atau keyboard, user bisa mengubah kondisi suatu widget. Ketika
kondisi suatu widget berubah, baik diubah oleh user ataupun diubah oleh suatu kode program,
maka widget akan menggambar dirinya kembali untuk merefleksikan hasil perubahannya.

Siklus hidup widget

Widget memiliki siklus hidup sendiri. Widget dibuat oleh programmer dan dibuang ketika tidak
lagi dibutuhkan. Karena siklus hidup suatu widget sangat penting untuk memahami SWT, maka
kita akan bahas lebih jauh pada bagian ini.

1. Membuat Widget

Widget dibuat dengan menggunakan konstruktornya, atau dengan kata lain membuat instansi
suatu kelas. Ketika widget dibuat, widget akan mengambil sumber daya komputer (memori,
prosesor) dari sistem operasi. Artinya semua widget akan berada di level sistem operasi,
sehingga unjuk kerja dan pengaturan memori akan lebih optimal.

Konstruktor akan mengambil argumen yang biasanya tidak akan bisa diubah setelah widget
dibuat. Ada 4 kemungkinan konstruktor dari suatu jenis widget :

 Widget()
 Widget(Widget induk)
 Widget(Widget induk, int bitGaya)
 Widget(Widget induk, int bitGaya, int posisi)

Widget tidak bisa dibuat tanpa induk. Ini bisa dilihat dari pengenalan tentang widget di bagian
sebelumnya bagaimana widget tersusun secara hirarkis. Jenis induknya tergantung dari jenis
widgetnya. Misalnya, induk dari suatu menu harus berupa menu, dan tidak bisa berupa tombol.
Kompiler akan mengecek apakah induk suatu widget sesuai dengan tipenya, jika tidak, kompiler
akan menampilkan pesan kesalahan. (Pada beberapa platform, kita dibolehkan untuk mengubah
induk suatu widget. Akan tetapi SWT tidak memiliki metode getParent() pada kelas-kelas
Widgetnya. Ini disebabkan karena kompleksitasnya yang mengharuskan kita untuk melakukan
type cast kepada tipe induk yang benar.)

Bit gaya (style) adalah nilai bit integer yang digunakan untuk mengatur perilaku dan tampilan
suatu widget. Biasanya bit gaya hanya dibutuhkan pada saat widget dibuat, misalnya memilih
jenis editor multi baris atau baris tunggal. Karena atribut ini tidak bisa diubah setelah widget
dibuat, maka gaya suatu widget juga tidak bisa diubah setelah widget diinstansikan.

Semua gaya widget dikumpulkan sebagai konstanta pada kelas org.eclipse.swt.SWT. Kita bisa
menggambungkan beberapa gaya dengan menggunakan operasi OR. Misalnya kode berikut akan
membuat widget teks multi baris yang memiliki tepi serta scroll bar horizontal dan vertikal.

Text teks = new Text (induk, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL |


SWT.BORDER);

Gaya suatu widget bisa kita ambil setelah widget tersebut dibuat dengan menggunakan metode
instansi getStyle(). Untuk mengujinya, kita bisa menggunakan operasi AND yang jika
hasilnya tidak nol, maka widget tersebut memiliki gaya yang diuji. Misalnya, kode berikut
menguji apakah suatu widget teks memiliki tepi, kemudian mencetak hasilnya pada konsol.

if ((teks.getStyle() & SWT.BORDER) != 0)


System.out.println("teks memiliki tepi");
else
System.out.println("teks tidak memiliki tepi");

Paremeter posisi memungkinkan kita membuat widget baru pada suatu induk di posisi tertentu.
Jika tidak diberikan, maka secara otomatis widget baru akan ditempatkan di akhir posisi. Hal ini
akan lebih memudahkan kita untuk membuat widget pada urutan tertentu, misalnya membuat
menu dengan urutan tertentu.

2. Membuang widget

Ketika widget tidak lagi dibutuhkan, termasuk ketika program selesai, maka widget harus
dihapus secara eksplisit dengan menggunakan metode instansi dispose(). Metode ini akan
menyembunyikan widget, menghapus widget yang ditampungnya, dan membuat semua referensi
di dalamnya menjadi null.

Jika metode dispose() tidak dipanggil setelah program selesai dijalankan, maka hal ini akan
menyebabkan kebocoran memori, di mana memori pada sistem operasi lambat laun akan habis
dipenuhi oleh widget yang tidak dihapus setelah program selesai.

Memanggil metode dispose() untuk widget yang sudah dibuang, akan melemparkan
pengecualian SWTException. Untuk mengetahui apakah suatu widget sudah dihapus, kita bisa
menggunakan metode instansi isDisposed().

Ada dua aturan yang penting untuk diingat :


 Jika Anda membuat widget, maka pastikan Anda menghapusnya. Atau dengan kata lain, semua
widget yang Anda buat dengan konstruktor wajib dihapus. Akan tetapi jika Anda mendapatkan
widget dari metode instansi suatu widget, misalnya Font huruf = kontrol.getFont(),
maka Anda tidak perlu menghapusnya
 Jika Anda menghapus suatu widget, maka semua widget di bawahnya akan dihapus juga. Atau
dengan kata lain, jika Anda menghapus suatu Shell, maka isi seluruh Shell akan dihapus secara
otomatis. Demikian juga halnya dengan menu, jika Anda menghapus menu utama, maka semua
sub-menu akan otomatis dihapus.

Event dan Listener


Posted Min, 05/03/2009 - 02:01 by belajarprogram

Versi ramah cetak

Event

Event adalah inti dari pemrograman GUI. GUI program tidak memiliki alur apa yang akan
terjadi ketika program dijalankan, dalam arti langkah per langkah dari awal hingga akhir. Akan
tetapi, program harus bisa bereaksi akan berbagai event (kejadian) yang bisa berasal dari mouse
atau keyboard. User bisa menekan tombol keyboard apa saja, menggeser mouse, atau menekan
tombol mouse. User bisa melakukannya kapan saja, dan komputer harus bisa bereaksi dengan
tepat.

Dalam Java, event dilambangkan oleh objek. Ketika suatu event terjadi, sistem akan
mengumpulkan informasi yang sesuai dengan even tersebut, kemudian membuat objek yang
berisi informasi ini. Jenis even berbeda dilambangkan oleh objek dengan kelas yang berbeda
pula. Setelah objek event dibuat, ia akan diberikan sebagai parameter pada subrutin yang
ditugaskan untuk menangani event tersebut. Dengan menulis subrutin ini, programmer bisa
memberi tahu apa yang harus dilakukan jika mouse diklik atau keyboard ditekan, misalnya.

Sebagai programmer Java, kita hanya melihat even dari sisi yang lebih umum. Banyak sekali hal
yang terjadi antara tombol ditekan hingga subrutin yang kita buat melakukan tugasnya. Secara
garis besar, dalam metode main() kita harus menuliskan perulangan dalam bentuk seperti :

ketika program masih berjalan:


Tunggu hingga even berikutnya terjadi
Panggil subrutin untuk menangai event tersebut

Perulangan ini disebut perulangan event. Pada SWT kita harus menulis sendiri perulangan event
ini pada metode main() kita dalam bentuk

while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();

SWT memiliki dua jenis event, yaitu event tanpa tipe dan event bertipe.
Event tanpa tipe diwakili oleh kelas Event. Kelas ini menyimpan informasi yang berbeda-beda
tergantung dari jenis. Akan tetapi secara umum semua event jenis apapun memiliki informasi
berikut :

Informasi Penjelasan

display Display di mana event ini terjadi

widget Widget di mana event ini terjadi

type Jenis event yang terjadi

Jenis event yang terjadi beserta penjelasannya dirangkum dalam tabel berikut ini :

Jenis Event Penjelasan

SWT.KeyDown Tombol ditekan

SWT.KeyUp Tombol dilepaskan

SWT.MouseDown Tombol mouse ditekan

SWT.MouseUp Tombol mouse dilepaskan

SWT.MouseMove Mouse berpindah posisi

SWT.MouseEnter Mouse masuk ke wilayah klien

SWT.MouseHover Mouse berada di sekitar klien

SWT.MouseExit Mouse keluar dari wilayah klien

SWT.MouseDoubleClick Mouse di-double click

SWT.Paint Suatu widget diberi perintah untuk menggambar dirinya

SWT.Move Posisi suatu widget berubah

SWT.Resize Ukuran widget berubah

SWT.Dispose Widget dihapus

Suatu aksi pemilihan dilakukan dalam widget (misalnya memilih item pada drop
SWT.Selection
down list

SWT.DefaultSelection Ada pilihan awal pada suatu widget


SWT.FocusIn Widget menerima fokus dari keyboard

SWT.FocusOut Widget kehilangan fokus dari keyboard

SWT.Expand Item pada pohon dikembangkan

SWT.Collapse Item pada pohon ditutup

SWT.Iconify Jendela Shell diminimasi

SWT.Deiconify Jendela Shell dibuka (restore)

SWT.Close Jendela Shell ditutup (dengan tombol X)

SWT.Show Widget bisa dilihat

SWT.Hide Widget disembunyikan

SWT.Modify Teks berubah pada suatu kontrol

SWT.Verify Input teks sedang diverifikasi

SWT.Activate Widget sedang diaktifkan

SWT.Deactivate Widget dimatikan

SWT.Help User meminta pertolongan tentang suatu widget

SWT.DragDetect Aksi drag-and-drop dideteksi

SWT.MenuDetect User menekan tombol kik kanan untuk mengaktifkan menu konteks

SWT.Arm Item pada menu digambarkan

SWT.Traverse Navigasi pada keyboard dideteksi

SWT.HardKeyDown Tombol pada hardware ditekan (untuk perangkat genggam)

SWT.HardKeyUp Tombol pada hardware dilepas (untuk perangkat genggam)

Suatu event juga bisa memiliki tipe. Artinya event yang dihasilkan merupakan objek bertipe
suatu kelas, misalnya MouseEvent, bukan hanya bertipe kelas Event yang jenisnya disimpan
dalam variabel tertentu. Event bertipe mengikuti pola JavaBeans standar. Kelas-kelas ini terdapat
dalam paket org.eclipse.swt.events

Tabel berikut menggambarkan perbandingan antara event bertipe dan jenis event dari event tanpa
tipe.
Event Bertipe Jenis Event Tanpa Tipe

ArmEvent SWT.Arm

SWT.Move
ControlEvent
SWT.Resize
DisposeEvent SWT.Dispose

SWT.FocusIn
FocusEvent
SWT.FocusOut
HelpEvent SWT.Help

SWT.KeyDown
KeyEvent
SWT.KeyUp
SWT.Hide
MenuEvent
SWT.Show
ModifyEvent SWT.Modify

SWT.MouseDoubleClick
MouseEvent SWT.MouseDown

SWT.MouseUp
MouseEvent SWT.MouseMove

SWT.MouseEnter
MouseEvent SWT.MouseExit

SWT.MouseHover
PaintEvent SWT.Paint

SWT.DefaultSelection
SelectionEvent
SWT.Selection
ShellEvent SWT.Activate

SWT.Close

SWT.Deactivate
SWT.Iconify

SWT.Deiconify
TraverseEvent SWT.Traverse

SWT.Collapse
TreeEvent
SWT.Expand
VerifyEvent SWT.Verify

Pertanyannya kenapa ada dua jenis event yang berbeda?

Pada versi awal SWT, hanya ada satu jenis yaitu jenis tanpa tipe. Setelah diskusi yang cukup
antar beberapa programmer Eclipse, komunitas user SWT dan developernya, maka akhirnya
diputuskan untuk menambahkan jenis bertipe seperti pada JavaBeans. Alasannya adalah untuk
memudahkan pemrograman SWT bagi programmer yang sudah terlanjur terbiasa dengan
AWT/Swing. Jenis tanpa tipe masih tetap ada seperti biasa.

Listener

Supaya suatu event berarti, suatu program harus bisa mendeteksi event dan bereaksi akan event
tersebut. Untuk mendeteksi suatu event, suatu program harus mendengarkannya. Mendengarkan
event ini dilakukan oleh objek yang berna,a pendengar event (event listener). Objek listener
harus memiliki metode instansi untuk menangani event yang didengarkannya. Bentuknya
bervariasi tergantung dari jenis event yang ditanganinya.

Ada beberapa hal detail yang harus diingat untuk bisa bekerja dengan event. Beberapa langkah
yang harus diingat :

1. Menambahkan import paket yang dibutuhkan, misalnya "org.eclipse.swt.events"

2. Mendeklarasikan kelas yang mengimplementasikan interface suatu listener

3. Menambahkan aksi yang dilakukan oleh kelas baru tersebut. Aksi ini adalah aksi yang
dilakukan untuk menangani suatu event

4. Mendaftarkan event tersebut ke komponen yang mungkin memberikan event.

Objek apapun bisa bertindah sebagai event listener asalkan ia mengimplementasikan interface
yang tepat. Suatu komponen dapat mendengarkan event yang dihasilkannya sendiri. Suatu kelas
dapat dibuat secara khusus hanya untuk mendengarkan suatu event. Kebanyakan orang
menganggap lebih mudah untuk menggunakan kelas bertingkat anonim untuk mendengarkan
suatu objek. (Kelas bertingkat anonim telah dibahas sebelumnya di sini).
Seperti hanya Event, SWT memiliki dua jenis listener : tanpa tipe dan bertipe. Masing-masing
digunakan untuk menangani event tanpa tipe dan event bertipe.

Listener Tanpa Tipe (untuk menangani event tanpa tipe)

nterface generik yang digunakan untuk menangai event tanpa tipe dinamakan Listener. Listener
tanpa tipe dapat ditambahkan pada suatu widget dengan menggunakan metode addListener().

Metode addListener() memiliki bentuk seperti

addListener(int jenisEvent, Listener listener)

Metode ini akan menambah listener ke dalam koleksi listener yang akan dipanggil ketika
event tipe tertentu terjadi. Ketika suatu event terjadi, maka listener akan dipanggil dengan
menggunakan metode handleEvent().

Contoh berikut mengilustrasikan bagaimana menambah suatu Listener ke dalam suatu widget,
yang akan dipanggil ketika event SWT.Dispose terjadi.

widget.addListener(SWT.Dispose, new Listener() {


public void handleEvent(Event event) {
// widget was disposed
}
});

Perhatikan bahwa bentuk di atas menggunakan kelas anonim yang langsung diturunkan dari
interface Listener. Di dalam kelas anonim tersebut, metode handleEvent() harus
diimplementasikan, di mana implementasinya adalah tugas yang harus dilakukan ketika widget
dihapus.

Jika beberapa listener ditambahkan, maka mereka akan dipanggil dengan urutan ketika mereka
ditambahkan (first in first called). Artinya listener pertama diberi kesempatan untuk mengolah
event (mungkin untuk memfilter sejumlah data) sebelum listener lain melakukan tugasnya. Kita
juga bisa menambah listener yang sama beberapa kali, yang artinya listener tersebut akan
dipanggil beberapa kali.

Kita bisa menghapus listener dari suatu widget dengan menggunakan metode
removeListener(). Bentuknya adalah sebagai berikut

removeListener(int jenisEvent, Listener listener)

Untuk menghapus suatu listener, kita harus memberikan instansi yang persisi sama ketika
listener tersebut ditambahkan. JIka beberapa instansi listener yang sama sudah ditambahkan
sebelumnya, maka kita harus menghapusnya berulang kali sejumlah ia ditambahkan. Secara
umum, menghapus suatu listener mungkin tidak diperlukan. Listener akan diambil oleh
pemulung memori ketika suatu widget dihapus dan listener ini tidak lagi digunakan di manapun
di dalam program.
Kita juga bisa memanggil suatu listener untuk melakukan tugas tertentu, yaitu dengan
menggunakan metode notifyListeners, yang memiliki bentuk seperti

notifyListeners(int jenisEvent, Event event)

jenisEvent adalah jenis event yang akan dilakukan, dan Event adalah objek yang berisi event
yang akan dilakukan. Hal penting yang harus dicatat adalah memanggil metode
notifyListeners() tidak menyebabkan event akan benar-benar terjadi. Misalnya memanggil
notifyListeners() dengan jenis SWT.MouseDown tidak akan menyebabkan tombol terlihat
seperti ditekan. Dan juga memanggil notifyListeners() tidak menjamin bahwa semua data
pada event terinisialisasi seperti pada event sesungguhnya.

Listener Bertipe (untuk menangani Event bertipe)

Karena event bertipe dibuat mengikuti pola listener pada JavaBeans, penggunaan listener bertipe
sangat mirip dengan penggunaan listener pada AWT/Swing.

Misalnya untuk mendengarkan event ketika suatu widget dihapus, maka aplikasi bisa
menggunakan addDisposeListener(), yang memiliki bentuk seperti

addDisposeListener(DisposeListener listener)

Metode ini menambahkan listener ke dalam koleksi listener yang akan dipanggil ketike suatu
widget dihapus. Ketika suatu widget dihapus, maka listener akan dipanggil dengan memanggil
metode widgetDisposed().

Potongan kode berikut digunakan untuk menangani event ketika suatu widget dihapus.

widget.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent event) {
// widget was disposed
}
});

DisposeListener adalah suatu interface. Jika ada lebih dari satu metode yang didefinisikan
dalam listener, maka SWT akan secara otomatis menambahkan kelas adapter yang berisi
implementasi kosong dari metode-metode yang didefinisikan pada interface tersebut. Misalnya
interface SelectionListener memiliki dua metode, yaitu widgetSelected() dan
widgetDefaultSelected, yang keduanya mengambil argumen bertipe SelectionEvents.
Dalam hal ini kelas SelectionAdapter tersedia untuk memberikan implementasi kosong untuk
setiap metode. Kelas adapter ini hanyalah sebagai kelas bantu yang sesuai dengan konvensi pada
listener JavaBeans.

Listener bertipe bisa dihapus dengan menggunakan metode penghapus untuk setiap listner.
Misalnya, listener untuk event ketika suatu widget dihapus bisa dibuang dengan menggunakan
removeDisposeListener(), yang memiliki bentuk
removeDisposeListener(DisposeListener listener)

listener adalah objek listener yang akan dihapus dari koleksi listener yang dipanggil ketika
widget dihapus.

Tabel berikut merangkum event bertipe, nama interface listener yang menanganinya, serta
metode pada interface tersebut, dibandingkan dengan listener tanpa tipe.

Event Bertipe Interface Listener Metode Jenis Event Tanpa Tipe

ArmEvent ArmListener widgetArmed(ArmEvent) SWT.Arm

ControlListener (dan controlMoved(ControlEvent) SWT.Move


ControlEvent
ControlAdapter)
controlResized(ControlEvent) SWT.Resize
DisposeEvent DisposeListener widgetDisposed(DisposeEvent) SWT.Dispose

FocusListener (dan focusGained(FocusEvent) SWT.FocusIn


FocusEvent
FocusAdapter)
focusLost(FocusEvent) SWT.FocusOut
HelpEvent HelpListener helpRequested(HelpEvent) SWT.Help

KeyListener (dan keyPressed(KeyEvent) SWT.KeyDown


KeyEvent
KeyAdapter)
keyReleased(keyEvent) SWT.KeyUp
MenuListener (dan menuHidden(MenuEvent) SWT.Hide
MenuEvent
MenuAdapter)
menuShown(MenuEvent) SWT.Show
ModifyEvent ModifyListener modifyText(ModifyEvent) SWT.Modify

SWT.MouseDoubleClic
mouseDoubleClick(MouseEvent)
k
MouseListener (dan
MouseEvent mouseDown(MouseEvent)
MouseAdapter) SWT.MouseDown
mouseUp(MouseEvent)
SWT.MouseUp
MouseEvent MouseMoveListener mouseMove(MouseEvent) SWT.MouseMove

MouseTrackListener mouseEnter(MouseEvent) SWT.MouseEnter


(dan
MouseEvent
MouseTrackAdapter mouseExit(MouseEvent) SWT.MouseExit
)
mouseHover(MouseEvent) SWT.MouseHover
PaintEvent PaintListener paintControl(PaintEvent) SWT.Paint
SelectionListener widgetDefaultSelected(SelectionEven
SWT.DefaultSelection
SelectionEvent (dan t)
SelectionAdapter) SWT.Selection
widgetSelected(SelectionEvent)
shellActivated(ShellEvent) SWT.Activate

shellClosed(ShellEvent) SWT.Close
ShallListener (dan
ShellEvent shellDeactivated(ShellEvent) SWT.Deactivate
ShellAdapter)

shellIconified(ShellEvent) SWT.Iconify

shellDeiconified(ShellEvent) SWT.Deiconify
TraverseEvent TraverseListener keyTraversed(TraverseEvent) SWT.Traverse

TreeListener (dan treeCollapsed(TreeEvent) SWT.Collapse


TreeEvent
TreeAdapter)
treeExpanded(TreeEvent) SWT.Expand
VerifyEvent VerifyListener verifyText(VerifyEvent) SWT.Verify

 Penanganan Mouse
 Penanganan Keyboard

Penanganan Mouse
Posted Min, 05/03/2009 - 17:55 by belajarprogram

Versi ramah cetak

Semua sistem operasi di mana SWT diimplementasikan mendukung perangkat tunjuk. Biasanya
berbentuk mouse, akan tetapi bisa jadi berupa trackball, trackpad, atau jenis perangkat keras
lainnya. Pada komputer genggam, perangkat tunjuk bisa jadi berupa stylus. Untuk
mempermudah pembahasan, kita akan gunakan mouse sebagai perangkat tunjuk, tidak peduli
bagaimana perangkat aslinya.

Posisi suatu mouse biasanya digambarkan dalam bentuk ikon kecil pada layar yang disebut
kursor. Hal ini berlaku untuk semua platform, kecuali pada Windows CE, karena perangkat
Windows CE biasanya berupa perangkat tunjuk "langsung", seperti stylys, yang tidak
membutuhkan kursor.

Mouse biasanya memiliki tiga tombol (kecuali pada Macintosh yang hanya memiliki satu
tombol, walaupun sebenarnya mouse lebih dari 1 tombol pun bisa digunakan). Mouse digunakan
untuk menunjuk, klik, geser (drag) dan memilih komponen kontrol GUI. Bisa juga digunakan
untuk menampilkan menu konteks yang biasanya ditampilkan dengan mengklik kanan suatu
mouse. Perilaku "drag-and-drop" mouse kurang lebih sangat bergantung pada platformnya.
Ketika kita menggeser mouse, kursor akan berbah bentuk, tergantung dari kontrol apa di
bawahnya. Misalnya, widget teks akan mengubah tampilan kursor seperti huruf I untuk
menunjukkan bahwa user bisa mengetikkan sesuatu pada widget tersebut. Di dalam kursor, ada
titik pusat yang menunjukkan koordinat x dan y suatu mouse ketika event pada mouse terjadi.

Event pada Mouse

Ketika tombol mouse ditekan atau mouse digerakkan, event mouse dibuat dan akan diberikan
kepada widget yang ada di bawahnya. Akan tetapi ketika tombol mouse ditekan dan ditahan
(terus ditekan), dan mouse berada di luar widget (mungkin ada di widget lain atau pada aplikasi
lain di desktop), eventnya akan diberikan kepada widget awal di mana mouse tersebut ditekan.
Pengalihan event sementara ini disebut pengambilan mouse. Widget yang menerima event
disebut widget pengambil. Pengambilan mouse terhadi secara otomatis pada SWT. (Ini mungkin
bukan sesuatu masalah, akan tetapi sebagai informasi saja kepada Anda).

Tabel - Isi Event Mouse ketika suatu tombol mouse ditekan, dilepaskan atau mouse digeser

Nama Field Penjelasan

button Tombol yang ditekan atau dilepaskan

x Koordinat x ketika event terjadi

y Koordinat y ketika event terjadi

stateMask Bit mask yang menyatakan kondisi keyboard dan mouse sebelum event terjadi

Ketika mouse ditekan atau dilepas, field bernama "button" akan diisi oleh tombol mana yang
ditekan. Tombol mouse diberi nomor dari kiri ke kanan yang dimulai dari 1. Untuk user kidal
(dan mengkonfigurasi sistem operasi untuk orang kidal), penomoran tombol tetap sama, akan
tetapi dimulai dari kanan ke kiri. Pemetaan tombol untuk orang kidal ini tidak tampak oleh SWT
dan aplikasi kita, karena dilakukan secara otomatis oleh sistem operasi.

Ketika terjadi event pada mouse, koordinat x dan y-nya juga dilaporkan dalam event. Koordinat
yang dilaporkan adalah koordinat relatif widget ketika event tersebut dibuat (bukan koordinat
global layar atau aplikasi kita). Karena user mungkin telah memindahkan mouse setelah
menekan tombol, maka lokasi sebenarnya ketika event ini ditangani mungkin berbeda dengan
ketika event dibuat. Hal ini untuk menghindari program kita untuk bertindak terlalu sensitif
terhadap pergerakan mouse. (Jika kita membutuhkan lokasi yang aktual pada saat-saat tertentu,
kita bisa menggunakan metode getCursorLocation() yang dimiliki oleh kelas Display.)

Event pada mouse juga menggunakan field lain yang dinamakan stateMask untuk menunjukkan
keadaan mouse. Seperti pada penanda tombol, stateMask berisi keadaan mouse sebelum
terjadinya suatu event. Misalnya, jika tidak ada tombol mouse yang ditekan atau tombol
keyboard lain yang ditekan ketika tombol kiri mouse ditekan, maka event mouse akan diisi
dengan button bernilai 1 dan stateMask bernilai 0. stateMask tidak berisi "tombol 1". Akan
tetapi ketika terjadi event lain ketika mouse kiri sedang ditekan, maka stateMask akan berisi 1.

Keadaan suatu mouse dilambangkan oleh konstanta pada kelas SWT, seperti pada tabel berikut :

stateMask Penjelasan

SWT.BUTTON1 Tombol 1 ditekan

SWT.BUTTON2 Tombol 2 ditekan

SWT.BUTTON3 Tombol 3 ditekan

SWT.BUTTON_MASK Bitwise-OR dari tombol-tombol yang ditekan

Berikut ini adalah event pada mouse yang disediakan oleh SWT. Seperti disebutkan pada bagian
sebelumnya, event dan listener SWT terdiri dari event/listener tanpa tipe dan event/listener
bertipe. Keduanya disarikan dalam tabel berikut :

Kelas Event Interface/Kelas


Jenis event (event tanpa Penjelasa
(event Listener (listener Metode (listener bertipe)
tipe) n
bertipe) bertipe)

Mouse di-
mouseDoubleClick(MouseEve SWT.MouseDoubleCli double
nt) ck click

Tombol
MouseEven MouseListener (dan
mouseDown(MouseEvent) SWT.MouseDown mouse
t MouseAdapter)
ditekan

Tombol
mouseUp(MouseEvent) SWT.MouseUp mouse
dilepaskan

Mouse
MouseEven MouseMoveListene
mouseMove(MouseEvent) SWT.MouseMove berpindah
t r
posisi

MouseEven MouseTrackListene mouseEnter(MouseEvent) SWT.MouseEnter Mouse


t r (dan masuk ke
MouseTrackAdapte wilayah
r) klien
Mouse
berada di
mouseExit(MouseEvent) SWT.MouseExit sekitar
klien

Mouse
keluar dari
mouseHover(MouseEvent) SWT.MouseHover wilayah
klien

Mari kita lihat contoh penggunaan mouse event pada program berikut. Anda bisa mengunduh
program ini dan mengimportnya pada Eclipse di sini.

package net.lyracc.pelacakmouse;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
 
public class PelacakMouse {
 
/**
* @param args
*/
public static void main(String[] args) {
// Membuat display dan shell baru
Display display = new Display();
Shell shell = new Shell(display);
 
// Kelas Listener baru, menggunakan listener tanpa tipe
Listener mouseListener = new Listener() {
 
// metode handleEvent pada interface Listener harus
diimplementasikan
public void handleEvent(Event e) {
String output = "UNKNOWN";
switch (e.type) {
case SWT.MouseDown: output = "DOWN"; break;
case SWT.MouseUp: output = "UP"; break;
case SWT.MouseMove: output = "MOVE"; break;
case SWT.MouseDoubleClick:
output = "DOUBLE";
break;
case SWT.MouseEnter: output="ENTER"; break;
case SWT.MouseExit: output = "EXIT"; break;
case SWT.MouseHover: output="HOVER"; break;
}
 
// Mengambil stateMask pada event, kemudian menampilkannya
// dalam bentuk heksadesimal
output += ": stateMask=0x"
+ Integer.toHexString(e.stateMask);
 
// Jika tombol Ctrl ditekan, tambahkan CTRL pada keluarannya
if ((e.stateMask & SWT.CTRL) != 0)
output += " CTRL";
 
// Jika tombol Alt ditekan, tambahkan ALT pada keluarannya
if ((e.stateMask & SWT.ALT) != 0)
output += " ALT";
 
// Jika tombol Shift ditekan, tambahkan SHIFT pada
keluarannya
if ((e.stateMask & SWT.SHIFT) != 0)
output += " SHIFT";
 
// Jika tombol Command ditekan, tambahkan COMMAND pada
keluarannya
if ((e.stateMask & SWT.COMMAND) != 0)
output += " COMMAND";
 
// Jika tombol kiri mouse ditekan, tambahkan BUTTON1 pada
keluarannya
if ((e.stateMask & SWT.BUTTON1) != 0)
output += " BUTTON1";
 
// Jika tombol tengah mouse ditekan, tambahkan BUTTON2 pada
keluarannya
if ((e.stateMask & SWT.BUTTON2) != 0)
output += " BUTTON2";
 
// Jika tombol kanan mouse ditekan, tambahkan BUTTON3 pada
keluarannya
if ((e.stateMask & SWT.BUTTON3) != 0)
output += " BUTTON3";
 
// Mengambil field button pada event, kemudian menampilkannya
// dalam bentuk heksadesimal
output += ", button=0x"
+ Integer.toHexString(e.button);
 
// Mengambil koordinat x dan y
output += ", x=" + e.x + ", y=" + e.y;
 
// Menampilkan pesan keluaran pada konsol
System.out.println(output);
}
 
};
 
// Tambahkan listener pada setiap event yang ingin kita pantau
shell.addListener(SWT.MouseDown, mouseListener);
shell.addListener(SWT.MouseUp, mouseListener);
shell.addListener(SWT.MouseMove, mouseListener);
shell.addListener(SWT.MouseDoubleClick, mouseListener);
shell.addListener(SWT.MouseEnter, mouseListener);
shell.addListener(SWT.MouseExit, mouseListener);
shell.addListener(SWT.MouseHover, mouseListener);
 
// Ubah ukuran jendela menjadi 200 x 200 piksel
shell.setSize(200, 200);
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
}

Program di atas akan melacak aktivitas mouse kemudian menampilkannya pada konsol. Jangan
lupa untuk menambahkan pustaka SWT sebelum menjalankan program ini seperti dibahas pada
bagian ini.

Klik Run pada Eclipse dan jalankan sebagai Java Application. Setelah jendela aplikasi yang kita
buat keluar, coba jalankan mouse dan perhatikan "Console" pada Eclipse seperti gambar berikut.

 Penanganan Keyboard
Posted Kam, 05/07/2009 - 00:00 by belajarprogram

Versi ramah cetak

Membuat API yang bisa dijalankan di berbagai platform untuk mengakses keyboard bukan
sesuatu yang mudah. Bahkan untuk platform yang sama tetapi dengan versi sistem operasi atau
kedaerahan (locale) yang berbeda, karakter bisa dimasukkan dengan cara yang berbeda.

Metode input, atau sering juga disebut IM (input method) atau IME (input method engine),
adalah mesin pengolah karakter yang disediakan oleh setiap sistem operasi. Tugasnya untuk
mengubah urutan tombol keyboard menjadi karakter yang bisa dibaca sesuai dengan konfigurasi
locale usernya. Misalnya, pada locale Jepang, tombol yang dimasukkan diproses oleh IME
sehingga user bisa memasukkan karakter Kanji.

Untungnya, kebanyakan kontrol (widget yang bisa berinteraksi dengan user) bisa menangani
keyboard tanpa perlu campur tangan aplikasi. Misalnya, ketika user memasukkan karakter Kanji
pada kontrol teks, kontrol tersebut akan mengolah karakter dan menampilkannya. Jika ada menu
konteks, maka menu ini akan secara otomatis disediakan.

Ketika user menekan tombol pada mouse, maka event yang dihasilkan akan diberikan kepada
widget yang ada dibawahnya. Apa yang terjadi ketika tombol keyboard di tekan? Komponen
mana yang harus menangani event yang dihasilkan?

Ketika suatu tombol pada keyboard ditekan, tombol tersebut akan diberikan kepada subsistem
berikut dalam urutan :

1. Sistem jendela
2. Akselerator untuk menu
3. Traversal
4. Kontrol fokus

Artinya setiap subsistem diberi kesempatan untuk bereaksi terhadap tombol keyboard, dalam
urutan seperti di atas. Jika salah satu subsistem mampu menangani tombol tersebut, maka tombol
ini tidak akan diteruskan ke subsistem berikutnya. Dalam hal ini kita sebut tombol tersebut telah
digunakan.

Kita akan diskusikan setiap subsistem dari bawah ke atas, mulai dari kontrol fokus, karena
konsep ini adalah konsep dasar yang diperlukan dalam pemrograman GUI.

 Kontrol Fokus
 Traversal
 Tombol Akselerator dan Tombol Sistem Jendela

Kontrol Fokus
Posted Kam, 05/07/2009 - 00:01 by belajarprogram

Versi ramah cetak

Program GUI menggunakan fokus input untuk menentukan komponen mana yang yang harus
menangani event dari keyboard. Pada suatu saat, hanya ada elemen pada layar yang bisa
menerima input, yaitu di mana semua event dari keyboard akan diarahkan. Mungkin merupakan
sesuatu yang baik untuk memberi user sedikit bantuan untuk mengetahui apakah suatu
komponen memiliki fokus input. Misalnya, jika komponen tersebut adalah tempat mengetik pada
program pengolah kata, maka biasanya kursornya akan berubah menjadi bentuk I dan berkedip-
kedip. Contoh lainnya adalah misalnya dalam suatu formulir, input teks yang sedang dalam
fokus memiliki warna latar belakang yang berbeda dengan input teks yang tidak memiliki fokus.

Untuk memberikan fokus kepada suatu komponen, kita bisa menggunakan metode setFocus()
yang terdapat pada hampir semua widget. Jika kontrol adalah objek bertipe suatu widget yang
bisa menerima fokus dan sukses adalah variabel bertipe boolean, maka

sukses = kontrol.setFocus();

memberi perintah kepada kontrol untuk mencoba mengambil fokus input. Jika kontrol atau
salah satu komponen yang ditampungnya berhasil mengambil fokus, fungsi ini akan
mengembalikan true. Jika gagal, maka false akan dikembalikan.

Widget komposit (yaitu widget yang bisa berisi widget-widget lain) akan berusaha untuk
memberi fokus kepada widget yang ditampungnya sebelum mengambil fokus untuk dirinya
sendiri. Beberapa widget lain, seperti label, biasanya tidak mengambil fokus. Suatu kontrol tidak
bisa mengambil fokus jika ia tidak aktif atau disembunyikan, atau jika input diblokade karena
modalitas (atau karena kontrol lain tidak mengijinkan fokus berpindah tempat).

Fungsi lain kontrol.isFocusControl() mengembalikan true jika kontrol tersebut sedang


memegang fokus atau false jika tidak. Kita juga bisa mencari tahu kontrol mana yang sedang
memiliki fokus dengan menggunakan metode pada kelas Display yaitu
Display.getFocusControl().

Berikut ini adalah daftar event dan listener yang berkaitan dengan fokus.

Interface/Kelas
Kelas Event Jenis event (event
Listener (listener Metode (listener bertipe) Penjelasan
(event bertipe) tanpa tipe)
bertipe)

Widget menerima
focusGained(FocusEvent) SWT.FocusIn fokus dari
keyboard
FocusListener (dan
FocusEvent
FocusAdapter)
Widget kehilangan
focusLost(FocusEvent) SWT.FocusOut fokus dari
keyboard

Mari kita lihat contoh berikut ini untuk memahami lebih lanjut tentang fokus input. Kita akan
buat 2 widget yang berupa input teks. Ketika input teks atas menerima fokus, maka judul aplikasi
kita ganti dengan "Fokus pada input teks atas". Ketika input teks bawah menerima fokus, maka
judul aplikasi kita ganti dengan "Fokus pada input teks bawah". Jika input teks atas kehilangan
fokus, kita isi input teks yang kehilangan fokus dengan "Saya kehilangan fokus", begitu input
teks atas menerima fokus kembali, kita akan hapus kalimat tersebut.
Contoh program ini dapat Anda unduh di sini, untuk diimport pada Eclipse. Pembahasan detail
tentang contoh program ini akan dibahas kemudian.

Event pada Tombol

Ketika suatu tombol pada keyboard ditekan, event tombol akan dibuat dan diberikan kepada
aplikasi kita. Akan tetapi, tergantung pada platformnya, kedaerahan (locale), dan kombinasi
tombol, ada kalanya event tidak terjadi. Misalnya, pada karakter Eropa yang memiliki aksen,
mesin pengolah karakter dari sistem operasi akan mengambil tombol tersebut untuk diolah.
Misalnya pada kedaerahan Jerman jika karakter ^ ditekan kemudian diikuti dengan tombol e,
maka karakter ê akan ditampilkan. Demikian juga jika tombol bantu ditekan untuk mengolah
bahasa Jepang, IME akan mengolah urutan karakter menjadi karakter Kanji.

Dengan kata lain, event tingkat rendah seperti ini sangat bergantung pada platform dan sistem
operasi, sehingga tidak terlalu berguna untuk kebanyakan program. SWT menyembunyikan
event sistem operasi dan hanya menampilkan satu event tombol saja setelah sistem operasi
selesai mengolah tombol tersebut.

Berikut ini adalah daftar event dan listener yang berkaitan dengan tombol.

Kelas Event Interface/Kelas Listener Metode (listener Jenis event (event


Penjelasan
(event bertipe) (listener bertipe) bertipe) tanpa tipe)

Tombol
keyPressed(KeyEvent) SWT.KeyDown
ditekan
KeyListener (dan
KeyEvent
KeyAdapter) Tombol
keyReleased(keyEvent) SWT.KeyUp
dilepaskan

Event SWT.KeyDown dan SWT.KeyUp merupakan representasi tingkat tinggi dari tombol yang
ditekan dan dilepaskan. Event-event ini berguna jika kita ingin mencegat suatu tombol tertentu
dan melakukan aksi khusus ketika tombol itu ditekan.

Berikut ini adalah isi event keyboard ketika ditekan/dilepaskan.

Nama Field Penjelasan


character Nilai Unicode dari karakter yang ditekan

keyCode Konstanta yang menunjukkan tombol mana yang ditekan, misalnya SWT.PAGE_UP

stateMask Melambangkan tombol tambahan, misalnya SWT.SHIFT

doit Suatu boolean yang bisa digunakan untuk membatalkan aksi penekanan tombol

character berisi karakter yang kita masukkan lewat keyboard setelah diolah oleh sistem
operasi. Misalnya jika kita menekan tombol <a> maka character berisi 'a'. Jika tombol <Shift>
dan <a> ditekan, maka character berisi 'A'. Jika tombol <Ctrl> dan <a> ditekan, maka
character akan diisi karakter yang bersesuaian dengan Ctrl+a, yaitu karakter dengan kode
Unicode '\u0001' (atau SOH). Beberapa tombol seperti Enter, Backspace, Tab, memiliki kode
karakter Unicode tersendiri. SWT juga memiliki konstanta untuk mewakili tombol-tombol ini,
yaitu

Konstanta character Penjelasan

SWT.BS Tombol backspace

SWT.CR Tombol Enter

SWT.DEL Tombol Del

SWT.ESC Tombol Esc

SWT.LF Tombol LF

SWT.TAB Tombol Tab

keyCode berisi karakter yang tidak bisa diwakilkan dengan karakter Unicode, misalnya tombol
<F1>, tombol <PgUp>, tombol <Panah Atas>, dan lain-lain termasuk tombol angka pada keypad
dan tombol <+> <-> <*> pada keypad. Beberapa tombol tersebut dilambangkan dalam konstanta
sebagai berikut. Khusus untuk keypad, apabila tombol <+> ditekan, maka selain keyCode berisi
SWT.KEYPADD_ADD, character juga berisi '+'.

SWT.F1 SWT.F11 SWT.PAGE_DOWN SWT.KEYPAD_0 SWT.KEYPAD_EQUAL

SWT.F2 SWT.F12 SWT.HOME SWT.KEYPAD_1 SWT.KEYPAD_CR

SWT.F3 SWT.F13 SWT.END SWT.KEYPAD_2 SWT.HELP

SWT.F4 SWT.F14 SWT.INSERT SWT.KEYPAD_3 SWT.CAPS_LOCK

SWT.F5 SWT.F15 SWT.KEYPAD_MULTIPLY SWT.KEYPAD_4 SWT.NUM_LOCK


SWT.F6 SWT.ARROW_UP SWT.KEYPAD_ADD SWT.KEYPAD_5 SWT.SCROLL_LOCK

SWT.F7 SWT.ARROW_DOWN SWT.KEYPAD_SUBTRACT SWT.KEYPAD_6 SWT.PAUSE

SWT.F8 SWT.ARROW_LEFT SWT.KEYPAD_DECIMAL SWT.KEYPAD_7 SWT.BREAK

SWT.F9 SWT.ARROW_RIGHT SWT.KEYPAD_DIVIDE SWT.KEYPAD_8 SWT.PRINT_SCREEN

SWT.F10 SWT.PAGE_UP SWT.KEYPAD_0 SWT.KEYPAD_9

stateMask berisi tombol sebelum tombol ditekan, yang biasanya <Ctrl>, <Shift>, <Alt>,
<Command>. Pada kebanyakan keyboard hanya ada 3 tombol pertama, akan tetapi ada juga yang
memiliki lebih dari 3 tombol. Tombol-tombol ini disebut tombol pengubah.

SWT membuat tombol-tombol ini menjadi kode seperti

stateMask Penjelasan

Tombol pengubah pertama ditekan (biasanya SWT.CONTROL pada Windows atau


SWT.MOD1
SWT.COMMAND pada Macintosh)

SWT.MOD2 Tombol pengubah kedua ditekan (biasanya SWT.SHIFT)

SWT.MOD3 Tombol pengubah ketiga ditekan (biasanya SWT.ALT)

SWT.MOD4 Tombol pengubah keempat ditekan (biasanya 0)

SWT.MODIFIER_MASK Gabungan dari keempatnya (menggunakan bitwise OR)

Dengan representasi seperti ini, maka SWT bisa dijalankan pada beberapa platform, dan tidak
bergantung dengan tombol apa  yang ada pada suatu sistem operasi. Bayangkan jika Anda ingin
menggunakan <Control> + <b> untuk membuat karakter menjadi tebal, akan tetapi tombol <Control>
tidak tersedia pada Macintosh.

Untuk menguji tombol pengubah mana yang ditekan, kita bisa menggunakan bitwise AND,
misalnya (e.stateMask & SWT.SHIFT).

Berikut ini adalah contoh program pelacak keyboard yang akan melaporkan tombol apa yang
Anda tekan dan lepaskan. Contoh program ini dapat Anda unduh di sini untuk mengimportnya
ke dalam Eclipse. Jalankan program ini pada Eclipse, kemudian ketik apa saja di program Anda,
perhatikan "Console" di Eclipse akan penuh dengan berbagai laporan tentang tombol yang
ditekan dan dilepaskan.
Kadang kala dalam kondisi yang sangat langka, kita harus mengolah sendiri tombol kita sebelum
diolah oleh suatu wudget. Karena SWT menggunakan widget bawaan sistem operasi, pengolahan
tombol terjadi di level sistem operasi. Misalnya, ketika user mengetik pada widget teks, listener
SWT.KeyDown akan dijalankan, kemudian sistem operasi akan memasukkan karakter dan
menggambarnya kembali dijalankan oleh sistem operasi. Dengan menggunakan doit, kita bisa
membuang karakter tersebut untuk tidak meneruskannya ke sistem operasi.

Contoh berikut akan menghalangi user untuk memasukkan karakter pada widget teks dengan
mengeset doit menjadi false setiap kali event SWT.KeyDown terjadi.

package com.lyracc.penghalangtombol;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
 
public class PenghalangTombol {
 
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
Text text = new Text(shell, SWT.SINGLE | SWT.BORDER);
 
text.addListener(SWT.KeyDown, new Listener() {
public void handleEvent(Event event) {
event.doit = false;
}
});
 
text.pack();
shell.pack();
 
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
}

Traversal
Posted Jum, 05/08/2009 - 20:54 by belajarprogram

Versi ramah cetak

Traversal atau penelusuran berarti memindahkan fokus dari satu kontrol ke kontrol lain. Tombol
traversal berbeda dengan tombol akselerasi dan tombol sistem jendela (yang akan dibahas nanti),
yaitu : Suatu kontrol bebas memilih apakah akan menjalankan operasi traversal atau mengolah
tombol yang ditekan. Jika kontrol memilih untuk menjalankan operasi traversal maka tombol
tersebut tidak akan diproses lebih lanjut.

Ada dua jenis traversal, yaitu mnemonik dan tab.

Traversal Mnemonik

Mnemonik biasanya tertulis sebagai karakter yang diberi garis bawah pada label suatu widget.
Suatu aksi akan dilakukan jika user menekan kombinasi tombol yang cocok dengan mnemonik
tersebut, biasanya dengan menekan tombol <Alt> bersamaan dengan karakter yang digaris
bawah tersebut.

Gambar berikut adalah contoh mnemonik pada program OpenOffice ketika kita membuka kotak
dialog Format Font
Jika kita menekan <Alt> + H maka tampilan Help akan ditampilkan.

Menekan tombol kombinasi untuk memanggil mnemonik sama dengan mengaktifkan widget
tersebut. Pada contoh di atas, mnemonik <Alt> + H diterapkan pada tombol, yang artinya ketika
kita menekan <Alt> + H, sama dengan kita menekan tombol Help. Beberapa widget yang tidak
bisa menerima pilihan, seperti label dan kotak grup masih bisa menerima mnemonik, akan tetapi
fungsinya hanya untuk memindahkan fokus ke widget tersebut.

Bagaimana caranya menambahkan mnemonik? Mudah saja. Cukup tambahkan '&' di depan
karakter yang akan kita tandai sebagai mnemonik, kemudian masukkan string ini sebagai
argumen pada metode setText() suatu widget. Misalnya pada perintah berikut :

Button tombol1 = new Button(shell, SWT.PUSH);


tombol1.setText("&Klik saya");

akan membuat tombol dengan mnemonik <Alt> + K, seperti pada gambar berikut ini :
Untuk membuat mnemonik pada karakter '&' sendiri, gunakan '&&', misalnya "Ini && Itu" akan
menghasilkan "Ini & Itu"

Traversal Tab

Traversal tab didukung pada semua platform. Tidak seperti pada mnemonik, pada traversal tab,
kita tidak perlu mendefinisikan apa-apa, karena setiap platform memiliki cara sendiri bagaimana
memindahkan fokus dari satu widget ke widget lain. Misalnya, ketika kita menekan tombol
<Tab>, maka fokus akan otomatis pindah ke widget berikutnya. Ketika sampai pada widget
terakhir, maka fokus akan diulang dari widget pertama.

Nama traversal tab mungkin agak sedikit salah sasaran, karena sepertinya hanya tombol <Tab>
saja yang bisa digunakan untuk memindahkan fokus dari satu widget ke widget lain. Pada
beberapa platform, menekan tombol panah juga memindahkan fokus.

Beberapa tombol lain seperti <Esc> digunakan untuk menutup kotak dialog, dan sebenarnya
termasuk dalam tombol traversal tab juga.

Berikut ini adalah daftar event dan listener yang berkaitan dengan traversal.

Interface/Kelas Jenis event


Kelas Event
Listener (listener Metode (listener bertipe) (event tanpa Penjelasan
(event bertipe)
bertipe) tipe)

Navigasi pada
TraverseEvent TraverseListener keyTraversed(TraverseEvent) SWT.Traverse keyboard
dideteksi

Berikut ini adalah isi event ketika event traversal terjadi.

Nama Field Penjelasan

detail Detail traversal yang terjadi

doit Suatu boolean yang bisa digunakan untuk membatalkan aksi traversal

detail berisi salah satu dari nilai-nilai berikut.

isi detail Penjelasan

Traversal yang terjadi ditutupnya suatu kotak dialog, misalnya


SWT.TRAVERSE_ESCAPE
dengan menekan tombol Cancel atau tombol <Esc>

SWT.TRAVERSE_RETURN Traversal yang terjadi ketika kotak dialog selesai diisi misalnya
setelah menekan tombol OK atau tombol <Enter>

SWT.TRAVERSE_TAB_PREVIOUS Traversal yang terjadi ketika fokus pindah ke group tab sebelumnya

SWT.TRAVERSE_TAB_NEXT Traversal yang terjadi ketika fokus pindah ke group tab sesudahnya

SWT.TRAVERSE_ARROW_PREVIOUS Traversal yang terjadi ketika fokus pindah ke item sebelumnya

SWT.TRAVERSE_ARROW_NEXT Traversal yang terjadi ketika fokus pindah ke item sesudahnya

SWT.TRAVERSE_MNEMONIC Traversal mnemonik terjadi

Traversal yang terjadi ketika untuk pindah ke halaman sebelumnya


SWT.TRAVERSE_PAGE_PREVIOUS
pada kotak dialog

Traversal yang terjadi ketika untuk pindah ke halaman berikutnya


SWT.TRAVERSE_PAGE_NEXT
pada kotak dialog

SWT.TRAVERSE_NONE Traversal tidak terjadi

Variabel detail bukan hanya untuk dibaca akan tetapi kita juga bisa mengisinya apabila kita
ingin mengubah jenis traversal. Misalnya kita ingin mengubah tombol <Enter> bukan untuk
menutup dialog akan tetapi untuk memindahkan fokus ke widget lain, kita bisa mengisi variabel
detail dengan SWT.TRAVERSE_ARROW_PREVIOUS.

doit digunakan untuk membatalkan traversal jika variabel ini diisi false. Akan tetapi lihat bahwa
pada variabel detail juga bisa SWT.TRAVERSE_NONE. Apa perbedaannya? Ingat bahwa tombol
yang tidak digunakan untuk traversal akan diberikan kepada widget yang menerima traversal
untuk diolah lebih lanjut.

Artinya jika event doit kita isi dengan true, traversal akan dilakukan dan tombol akan
"dikonsumsi" (tidak diberikan kepada widget untuk diproses kembali). Jika doit kita isi denga
false, traversal tidak dilakukan dan tombol akan diberikan kepada widget untuk diproses.

Apa yang terjadi jika detail juga diisi dengan SWT.TRAVERSE_NONE? Jika detail diisi dengan
SWT.TRAVERSE_NONE maka widget tidak akan melakukan traversal, tidak peduli apakah isi doit
berisi true atau false. Akan tetapi, variabel doit menentukan apakah tombol akan diberikan
kepada widget untuk diproses.

Jadi jika doit berisi false dan detail berisi SWT.TRAVERSE_NONE, maka tombol akan diberikan
kepada widget, dan traversal tidak dilakukan. Akan tetapi jika doit berisi true dan detail
berisi SWT.TRAVERSE_NONE, maka traversal tidak dilakukan, dan tombol akan dikonsumsi dan
tidak akan diberikan kepada widget.

Berikut ini adalah contoh penggunaan traversal.


Program ini akan membuat 6 tombol. Coba tekan tombol <Tab>. Fokus akan pindah ke tombol
berikutnya setiap kali Anda menekan tombol <Tab>. Ketika Anda melewati tombol 4 atau
tombol 6, akan tercetak "Button {4} ditelusuri". Jika Anda menekan tombol <Shift> + <Tab>
fokus akan berpindah ke tombol sebelumnya. Akan tetapi jika Anda sampai pada tombol 4 atau
tombol 6, event traversal yang terjadi akan ditangkap dan traversal akan diabaikan. Akibatnya
Anda tidak akan bisa pindah dari tombol 4 ke tombol 3 atau tombol 6 ke tombol 5. Pada saat
yang sama di konsol akan tercetak "Anda tidak bisa kembali!".

Program lengkapnya adalah sebagai berikut, yang bisa diunduh di sini.

package com.lyracc.traversalkustom;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
 
public class TraversalKustom {
 
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(300, 200);
 
Button b1 = new Button(shell, SWT.PUSH);
Button b2 = new Button(shell, SWT.PUSH);
Button b3 = new Button(shell, SWT.PUSH);
Button b4 = new Button(shell, SWT.PUSH);
Button b5 = new Button(shell, SWT.PUSH);
Button b6 = new Button(shell, SWT.PUSH);
b1.setBounds(10,10,50,50);
b2.setBounds(100,10,50,50);
b3.setBounds(200,10,50,50);
b4.setBounds(10,100,50,50);
b5.setBounds(100,100,50,50);
b6.setBounds(200,100,50,50);
b1.setText("1");
b2.setText("2");
b3.setText("3");
b4.setText("4");
b5.setText("5");
b6.setText("6");
 
TraverseListener traverseListener = new TraverseListener() {
public void keyTraversed(TraverseEvent e) {
if (e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
System.out.println("Anda tidak bisa kembali!");
e.doit = false;
}
System.out.println(e.widget + " ditelusuri");
}
};
b4.addTraverseListener(traverseListener);
b6.addTraverseListener(traverseListener);
 
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
}

Tombol Akselerator dan Tombol Sistem Jendela


Posted Jum, 05/08/2009 - 21:25 by belajarprogram

Versi ramah cetak

Tombol Akselerator

Akselerator adalah tombol shortcut ke salah satu menu, misalnya pada kebanyakan program
pengolah kata menekan tombol <Ctrl> dan S artinya menyimpan teks yang sedang diedit.
Akselerator biasanya berupa rangkaian tombol yang ditekan bersamaan, bisa 2 tombol seperti
contoh <Ctrl> di atas atau mungkin lebih, misalnya pada Firefox, tombol <Ctrl> + <Shift> + J
membuka konsol kesalahan (error console).

Akselerator selalu berhubungan dengan menu, sehingga akselerator bersifat global, yang berarti
kita bisa menekan tombol akselerator dari dalam widget manapun yang sedang aktif pada saat
itu. Ketika akselerator dipanggil, maka tombol-tombol yang ditekan akan dikonsumsi langsung
oleh aplikasi dan tidak diberikan kepada widget apa-apa.

Akselerator direpresentasikan pada SWT dalam bentuk kode integer tertentu. Kode integer
tersebut berisi gabungan beberapa tombol, yaitu tombol pengubah (seperti <Ctrl>, <Shift>,
<Alt>) dan satu tombol lain yang berupa karakter atau keyCode (seperti tanda panah, F1 hingga
F15, <Esc>, dll). Lihat bahasan tentang fokus kontrol untuk mengerti lebih jauh tentang
bagaimana penanganan tombol pada SWT. Tombol akselerator tidak bisa hanya terdiri dari
tombol pengubah saja.

Berikut ini adalah beberapa contoh akselerator.

Akselerator Rangkaian Tombol

SWT.CONTROL + 'A' <Ctrl> + <A>

SWT.SHIFT + SWT.ARROW_UP <Shift> + tombol panah ke atas

SWT.MOD1 + 'S' Tombol pengubah pertama (biasanya <Ctrl> atau <Command>) + <S>

SWT.MOD1 + SWT.MOD2 + 'B' Tombol pengubah pertama + Tombol pengubah kedua + <B>

Akselerator diberikan kepada menu atau toolbar dengan menggunakan metode


setAccelerator(int kodeAkselerator) di mana kodeAkselerator adalah kode akselerator
seperti dicontohkan pada tabel di atas. Untuk mereset akselerator, isi kodeAkselerator dengan
0.

Untuk mengambil tombol akselerator suatu menu atau toolbar bisa digunakan dengan
menggunakan metode getAccelerator() yang mengembalikan nilai integer.

Misalnya jika item adalah suatu item pada menu, maka potongan kode berikut akan
menambahkan akselerator pada item tersebut :

item.setText("Pilih &Semua\tCtrl+S");
item.setAccelerator(SWT.MOD1 + 'S');
item.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event e) {
System.out.println("Item dipilih.");
}
});
Karakter '\t' di dalam setText memberi tahu SWT bahwa karakter setelah itu adalah tombol
akseleratornya. Perlu dicatat bahwa hanya menambahkan teks akselerator pada metode
setText() tidak membuat tombol akselerator otomatis ditambahkan dalam metode
setAccelerator(). Menambahkan teks akselerator pada setText() berfungsi untuk
membetulkan kesalahan yang terjadi jika tombol akselerator tidak terdapat pada platform yang
dituju. Misalnya pada contoh di atas, tombol <Ctrl> tidak ada pada Macintosh, akan tetapi SWT
akan mengganti tampilan Ctrl-S menjadi -S.

Tombol Sistem Jendela

Tombol yang diproses oleh sistem jendela tidak akan sampai pada aplikasi kita. Misalnya,
tombol Alt-F4 pada beberapa sistem akan menutup jendela yang aktid. Manager jendela akan
melakukan aksi terlebih dahulu dan tombol tersebut akan dikonsumsi oleh manager jendela.
Manager jendela tidak sama dengan sistem operasi. Pada Windows, manager jendela itu
terintegrasi dengan sistem operasi. Pada Linux misalnya manager jendela bisa bermacam-
macam, misalnya KDE dan Gnome.

Tombol-tombol mana yang akan dimanage oleh manager jendela berbeda-beda, tergantung dari
sistem jendela tersebut. Karena tidak adanya kesamaan pada setiap manager jendela, maka kita
tidak bisa mencegat penekenan tombol ini misalnya dialihkan untuk melakukan fungsi lain.

<!-- @page { margin: 0.79in } TD P { margin-bottom: 0in } P { margin-bottom: 0.08in } -->

Widget-widget SWT
Posted Sab, 05/09/2009 - 00:30 by belajarprogram

Versi ramah cetak

Pada bagian ini akan kita bahas widget-widget yang disediakan oleh SWT. Kelas Widget
merepresentasikan semua objek user interface. Kelas ini adalah kelas abstrak yang tidak bisa
langsung diinstansiasi.

Berikut ini adalah metode-metode yang dimiliki oleh seluruh widget turunan dari kelas abstrak
Widget yang mencakup hampir seluruh widget SWT.

Metode Penjelasan

dispose() Menghapus widget dari memori.

isDisposed() Mengembalikan true jika widget ini sudah dihapus dari memori

setData(Object o) Menambahkan data tambahan (terserah kita) ke dalam suatu widget. Data ini
disebut data aplikasi. Data ini tidak akan ditampilkan pada widget.

Mengembalikan Object yang merupakan data yang bisa kita tambahkan ke


getData()
dalam widget

Jika kita akan menambahkan banyak data ke dalam objek, akan lebih mudah
setData(String key,
Object o)
jika kita menandai data tersebut dengan suatu kunci key. Data ini tidak akan
ditampilkan pada widget.

Mengembalikan Object yang merupakan data tambahan ke suatu widget,


getData(String key)
yang memiliki kunci key

getStyle() Mengembalikan int yang merupakan bit gaya suatu widget.

Event ini terdapat pada semua kelas turunan dari kelas abstrak Widget

Interface/Kelas Jenis event


Kelas Event
Listener (listener Metode (listener bertipe) (event tanpa Penjelasan
(event bertipe)
bertipe) tipe)

Widget
DisposeEvent DisposeListener widgetDisposed(DisposeEvent) SWT.Dispose
dihapus

 Shell
 Kotak Dialog
 Dasar-dasar Kontrol dan Label
 Button (Tombol)
 Text

Shell
Posted Min, 05/10/2009 - 16:33 by belajarprogram

Versi ramah cetak

Objek bertipe Shell adalah suatu jendela pada aplikasi. Objek yang tidak memiliki induk (atau
induknya bertipe Display) disebut shell tingkat paling tinggi. Objek yang memiliki induk yang
berupa shell lain disebut shell sekunder atau shell dialog.

 Bit Gaya Shell


 Metode pada Shell
 Event pada Shell
Bit Gaya Shell
Posted Min, 05/10/2009 - 16:36 by belajarprogram

Versi ramah cetak

Shell memiliki beberapa bit gaya yang dibagi menjadi 3 jenis, sebagai berikut. Akan tetapi perlu
diingat bahwa bit gaya untuk shell hanya digunakan sebagai bantuan saja. Apa yang digambar
oleh manager jendela setiap sistem operasi bisa berbeda-beda.

1. Gaya yang mempengaruhi tampilan, suatu jendela bisa memiliki satu atau beberapa bit
gaya berikut

 SWT.BORDER, suatu jendela memiliki garis tepi di sekitarnya


 SWT.NO_TRIM, suatu jendela tanpa garis tepi (bisa digunakan untuk tool tip), akan tetapi tidak
bisa digabungkan dengan SWT.BORDER
 SWT.CLOSE, suatu jendela memiliki tombol Close (atau biasanya sering digambar dengan X) di
pojok kanan atas jendela
 SWT.MIN, suatu jendela memiliki tombol Minimize (biasanya sering digambar dengan -) di pojok
kanan atas jendela
 SWT.MAX, suatu jendela memiliki tombol Maximimze di pojok kanan atas jendela
 SWT.RESIZE, suatu jendela memiliki tombol Resize di pojok kanan atas jendela
 SWT.TITLE, suatu jendela memiliki judul.
 SWT.ON_TOP, suatu jendela yang akan berada di atas jendela-jendela lain bahkan jendela dari
aplikasi lain. Jendela ini tidak memblok input ke jendela lain, artinya hanya tampilannya saja
yang berada paling atas. Bisa digunakan untuk menampilkan logo pada saat program pertama
kali dijalankan.
 SWT.TOOL, suatu jendela yang berbentuk seperti tips sesaat yang tujuannya memberikan
bantuan kepada user. Dalam Eclipse, biasanya toop tips ini muncul ketika kita mengarahkan
mouse ke suatu perintah, kemudian berhenti sesaat di sana. Kemudian akan muncul bantuan
tentang suatu perintah tersebut, yang menjelaskan di antaranya input dan output suatu metode
dan komentar bagaimana menggunakan suatu metode.

2. Bit gaya yang mempengaruhi modalitas suatu jendela

Modalitas adalah bagaimana suatu jendela mempertahankan fokus input pada dirinya dan
memblokade input ke jendela lain. Modalitas suatu jendela tergantung pada siapa yang bisa
diblokade inputnya. Hanya salah satu modalitas saja yang bisa diberikan kepada suatu jendela

 SWT.MODELESS, suatu jendela tidak memblok jendela lain, biasanya merupakan default dari
suatu jendela shell tingkat atas yang baru dibuat
 SWT.PRIMARY_MODAL, suatu jendela memblok input induknya, biasanya digunakan untuk kotak
dialog
 SWT.APPLICATION_MODAL, suatu jendela memblok input jendela-jendela lain pada aplikasi
yang sama
 SWT.SYSTEM_MODAL, suatu jendela memblok seluruh jendela bahkan jendela aplikasi lain.
3. Bit gaya untuk kenyamanan pemrograman

SWT memberikan beberapa bit gaya yang bisa digunakan seorang programmer yang merupakan
gabungan dari beberapa bit gaya di atas, yang merupakan kombinasi yang sering digunakan
dalam aplikasi. Oleh karena itu bit gaya ini digunakan untuk kenyamanan programmer akan
tetapi memiliki efek yang persis sama dengan apabila kita menggabungkannya sendiri

 SWT.SHELL_TRIM, merupakan gaya shell yang biasa digunakan untuk jendela suatu aplikasi.
Merupakan gabungan dari (SWT.CLOSE | SWT.TITLE | SWT.MIN | SWT.MAX | SWT.RESIZE)
 SWT.DIALOG_TRIM, merupakan gaya shell yang biasa digunakan untuk kotak dialog.
Merupakan gabungan dari (SWT.CLOSE | SWT.TITLE | SWT.BORDER)

Untuk melihat efek dari beberapa bit gaya di atas, lakukan ekspremen kecil pada program berikut
:

package com.lyracc.contohshell;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
 
public class ContohShell {
 
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display, SWT.CLOSE | SWT.BORDER);
 
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
}

Anda bisa mengganti-ganti kontruktor shell dengan beberapa kombinasi berikut dan lihat
hasilnya sendiri :

 Shell shell = new Shell(display, SWT.SHELL_TRIM)


 Shell shell = new Shell(display, SWT.DIALOG_TRIM)
 Shell shell = new Shell(display, SWT.TOOL)
 Shell shell = new Shell(display, SWT.CLOSE | SWT.BORDER)
 Shell shell = new Shell(display, SWT.NO_TRIM)

Beberapa contoh di atas tidak akan menampilkan tombol close, sehingga untuk mematikannya
Anda harus menghentikannya dari dalam Eclipse dengan menekan tombol
Contoh berikut (kode lengkapnya untuk diimport ke dalam Eclipse bisa diunduh di sini) ini
membuat shell kosong, jika mouse kita berhenti di suatu tempat (hover), shell baru yang berisi
tool tip akan ditampilkan, seperti pada gambar berikut. Tool tip ini akan hilang jika mouse
berpindah tempat.

Untuk membuatnya, kita akan membuat satu kelas yang khusus menangani event, yang kita
namakan ToolTipListener. Kelas ini mengimplementasikan MouseMoveListener dan
MouseTrackListener (lihat bagian penanganan mouse untuk apa apa listener digunakan).
MouseTrackListener digunakan untuk menangkap event hover yang akan membuat shell baru,
kemudian menambahkan label untuk menampilkan tulisan ToolTip. Shell baru ini kita buat
dengan bit gaya SWT.TOOL. Berikut ini adalah listing dari kelas ToolTipListener.

package com.lyracc.tooltipdemo;
 
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.graphics.*;
 
public class ToolTipListener implements MouseTrackListener, MouseMoveListener
{
 
Shell tip = null;
Label label = null;
 
// Metode buatToolTip dipanggil oleh event hover
void buatToolTip(MouseEvent e) {
// Ambil display dan shell utama dari event
Display displayUtama = e.display;
Shell shellUtama = displayUtama.getActiveShell();
 
// Buat tool tip baru sebagai shell, dengan bit gaya SWT.ON_TOP
tip = new Shell(shellUtama, SWT.ON_TOP);
tip.setLayout(new FillLayout());
 
// Tambahkan label
label = new Label(tip, SWT.NONE);
label.setText("ToolTip");
 
// Tambahkan tip ke dalam shell supaya bisa digambar
tip.pack();
}
 
// Metode tutupToolTip dipanggil ketika mouse pindah
void tutupToolTip() {
if (tip != null) tip.dispose();
tip = null;
}
 
@Override
public void mouseEnter(MouseEvent e) {
}
 
@Override
public void mouseExit(MouseEvent e) {
// Jika mouse keluar dari shell, tutup tool tip
tutupToolTip();
}
 
@Override
public void mouseHover(MouseEvent e) {
// Jika tip sudah ada, keluar dan tidak lakukan apa-apa
if (tip != null) return;
 
// Jika belum ada, buat tool tip baru
buatToolTip(e);
 
// Mengambil display dan shell utama dari event yang memanggil
Display displayUtama = e.display;
Shell shellUtama = displayUtama.getActiveShell();
 
// Hitung di mana tool tip akan ditampilkan, diambil dari lokasi
mouse
// yang disimpan di dalam e.x dan e.y
Rectangle rect = tip.getBounds();
rect.x = e.x;
rect.y = e.y + 22;
 
// Ubah posisi tip menggunakan metode setbounds
tip.setBounds(
displayUtama.map(shellUtama, null, rect));
 
// Buat supaya tip bisa dilihat (visible)
tip.setVisible(true);
}
 
@Override
public void mouseMove(MouseEvent e) {
// Jika mouse pindah lokasi, tutup tool tip
tutupToolTip();
}
}

Kelas utamanya (yang memiliki metode main()) akan menginstansiasi kelas ToolTipListener
dan menambahkan listener ke shell utamanya. Berikut ini adalah listing kelasnya.

package com.lyracc.tooltipdemo;
 
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
 
public class ToolTipDemo {
 
/**
* @param args
*/
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
 
shell.setLayout(new FillLayout());
 
// Membuat instansi listener baru
ToolTipListener tipListener = new ToolTipListener();
 
// Tambahkan listener ke dalam shell
// (kelas listener kita mengimplementasi kelas MouseMoveListener
// dan kelas MouseTrackListener, kita tambahkan listener tersebut
// sendiri-sendiri)
shell.addMouseMoveListener(tipListener);
shell.addMouseTrackListener(tipListener);
 
shell.pack();
 
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
}

Metode pada Shell


Posted Min, 05/10/2009 - 17:29 by belajarprogram

Versi ramah cetak

Mengeset judul jendela dan icon jendela

Metode Penjelasan

setText(String judul) Mengeset judul jendela. Tidak bisa mengandung mnemonik.

Mengambil judul jendela. Jika tidak pernah diset, maka hasilnya adalah
getText()
string kosong

setImage(Image Mengeset gambar icon pada jendela, atau gambar icon yang akan
gambar) digunakan ketika jendela diminimasi

getImage() Mengambil gambar icon jendela


setImages(Image[] Mengeset beberapa gambar icon pada jendela. Pada kebanyakan manager
gambar) jendela, hanya gambar terakhir saja yang ditampilkan

getImages() MEngambil gambar-gambar yang sudah diset pada jendela

Membuka dan menutup jendela

Metode Penjelasan

open() Membuka jendela dan mengarahkan fokus pada jendela ini.

Membuat suatu jendela menjadi jendela aktif. Mirip dengan open() akan
setActive()
tetapi fokus tidak otomatis di set ke jendela aktif

Memaksa agar suatu jendela menjadi jendela aktif, akan tetapi tidak
forceActive()
selamanya akan berhasil.

Menutup jendela, sama seperti ketika user menutup jendela dengan


close()
menekan tombol (X) di sudut kanan atas jendela.

Mengembalikan true jika jendela ini bisa menerima fokus, dan semua
isEnabled()
induknya hingga level tertinggi juga enabled.

getEnabled() Mengembalikan true jika jendela ini bisa menerima fokus

setEnabled(boolean
enabled)
Mengeset apakah suatu jendela bisa menerima fokus

isVisible() Mengembalikan true jika jendela bisa dilihat

getVisible() Mengembalikan true jika jendela bisa dilihat

setVisible(boolean
visible)
Mengeset apakah suatu jendela bisa dilhat atau tidak.

Mengubah ukuran suatu jendela

Metode Penjelasan

Mengembalikan Rectangle yang merupakan koordinat sudut-sudut


getBounds()
suatu jendela relatif terhadap induknya

Mengeset bentuk suatu jendela, misalnya kita ingin jendela kita


setRegion(Region wilayah)
berbentuk bentuk lain selain persegi panjang.
Mengembalikan Region yang merupakan bentuk suatu jendela (bisa
jadi bukan berupa persegi panjang, tapi bentuk lain yang kita
getRegion()
definisikan sebelumnya). Mengembalikan null jika bentuk jendela
seperti biasa (persegi panjang)

Mengembalikan Point yang merupakan ukuran suatu jendela, x


getSize()
adalah lebar dan y adalah tingginya

setSize(int lebar, int


tinggi)
Mengeset ukuran suatu jendela

setSize(Point p)
Mengeset ukuran suatu jendela, dengan parameter dalam bentuk
Point

Mengembalikan Point ukuran minimum suatu jendela. Ukuran


getMinimumSize() minimum adalah ukuran di mana user tidak bisa memperkecil ukuran
jendela lagi lebih kecil dari ukuran ini.

setMinimumSize(int lebar, Mengeset ukuran minimum suatu jendela. User tidak bisa
int tinggi) memperkecil jendela lebih kecil dari ukuran ini.

Mengeset ukuran minimum suatu jendela. Menerima argumen


setMinimumSize(Point p)
bertipe Point

getLocation() Mengambil lokasi suatu jendela relatif terhadap induknya

setLocation(int x, int y) Mengeset lokasi suatu jendela relatif terhadap induknya

getFullScreen() Mengembalikan true jika jendela dalam keadaan full screen

setFullScreen(boolean
fullscreen)
Mengeset keadaan full screen suatu jendela

Mengembalikan true jika jendela dalam keadaan dimaksimasi


getMaximized()
(masiximized)

setMaximized(boolean
maximized)
Mengeset keadaan maximized suatu jendela

Mengembalikan true jika jendela dalam keadaan diminimasi


getMinimized()
(minimized)

setMinimized(boolean
minimized)
Mengeset keadaan minimasi suatu jendela

Mengelola isi suatu jendela


Metode Penjelasan

setMenuBar(Menu menu) Mengeset menu suatu jendela

getMenuBar() Mengembalikan Menu suatu jendela

Mengembalikan array Shell[] yang merupakan shell-shell anak


getShells()
dari shell ini

Mengembalikan array Control[] yang merupakan wkontrol-


getChildren()
kontrol yang terdapat di dalam jendela ini.

Mengembalikan tombol apa yang akan dieksekusi jika tombol


getDefaultButton()
<Enter> ditekan (berguna untuk kotak dialog)

setDefaultButton(Button Mengeset tombol apa yang akan dieksekusi jika tombol <Enter>
tombol) ditekan (biasanya pada kotak dialog)

Mengembalikan Color yang merupakan latar belakang suatu


getBackground()
jendela

setBackground(Color warna) Mengeset warna latar belakang suatu jendela

getForeground() Mengembalikan Color yang merupakan latar depan suatu jendela

setForeground(Color warna) Mengeset warna latar depan suatu jendela

Mengembalikan Image yang merupakan gambar latar belakang


getBackgroundImage()
suatu jendela

setBackgroundImage(Image Mengeset gambar latar belakang suatu jendela. Jika gambar lebih
gambar) kecil dari ukuran jendela, gambar akan dibuat berulang-ulang.

Pada contoh berikut ini kita akan membuat shell berbentuk oval dengan latar belakang merah.
Kita bisa memindahkan shell tersebut dengan menggesernya ke posisi lain (tekan mouse di
dalam oval, kemudian gerakkan mouse). Karena tidak ada tombol (X) di sudut kanan atas
jendela, kita tambahkan event yang akan menutup jendela ketika sembarang tombol keyboard
ditekan.
Program lengkapnya dapat diunduh di sini dan dapat Anda import ke dalam Eclipse. Berikut
program lengkapnya.

package com.lyracc.shellberbentuklingkaran;
 
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
 
public class ShellBerbentukLingkaran {
 
// Jumlah titik pada lingkaran, semakin banyak semakin halus
// Dari rumus geometri, untuk membuat suatu bangun datar
// dibutuhkan minimum 3 titik.
final static int JML_TITIK = 151;
 
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
// Membuat shell baru tanpa garis tepi
Shell shell = new Shell(display, SWT.NO_TRIM);
 
// Mengambil warna hitam dari sistem
Color warnaMerah =
display.getSystemColor(SWT.COLOR_RED);
 
// Mengeset warna dan ukuran shell mula-mula
shell.setBackground(warnaMerah);
shell.setSize(100, 200);
 
// Mengambil batas-batas shell
Rectangle wilayah = shell.getClientArea();
 
// Koordinat tengah jendela
Point tengah = new Point(0, 0);
tengah.x = wilayah.x + wilayah.width / 2;
tengah.y = wilayah.y + wilayah.height / 2;
 
int[] koordinat = new int[JML_TITIK * 2];
 
// menggunakan rumus trigonometri untuk mendapatkan koordinat
lingkaran
for (int i = 0; i < JML_TITIK; ++i) {
double r = Math.PI * 2 * i / JML_TITIK;
koordinat[i*2] = (int)(tengah.x + Math.cos(r) * wilayah.width /
2);
koordinat[i*2+1] = (int)(tengah.y + Math.sin(r) * wilayah.height /
2);
}
 
// Membuat region baru dan menambahkannya pada shell
Region region = new Region(display);
region.add(koordinat);
shell.setRegion(region);
 
Listener listener = new Listener() {
 
int offsetX = 0;
int offsetY = 0;
 
public void handleEvent(Event e) {
Shell shellUtama = (Shell)e.widget;
 
switch (e.type) {
// Jika mouse ditekan ambil koordinat saat itu
case SWT.MouseDown:
if (e.button == 1) {
offsetX = e.x;
offsetY = e.y;
}
break;
 
case SWT.MouseMove:
// Jika mouse pindah sambil ditekan dengan tombol
kiri
if ((e.stateMask & SWT.BUTTON1) != 0) {
 
// Ambil lokasi mouse relatif terhadap display
Point pt = shellUtama.toDisplay(e.x, e.y);
 
// Translasikan dengan offset awal
pt.x -= offsetX;
pt.y -= offsetY;
 
// Set lokasi baru
shellUtama.setLocation(pt);
}
break;
 
case SWT.KeyDown :
// Jika tombol keyboard ditekan tutup jendela
shellUtama.dispose();
break;
}
}
};
 
// Tambah listener ke dalam shell
shell.addListener(SWT.MouseDown, listener);
shell.addListener(SWT.MouseMove, listener);
shell.addListener(SWT.KeyDown, listener);
 
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
// Jangan lupa untuk mendispose region juga
region.dispose();
display.dispose();
}
}

Event pada Shell


Posted Min, 05/10/2009 - 18:36 by belajarprogram

Versi ramah cetak

Event berikut hanya terdapat pada widget Shell.

Kelas Event Interface/Kelas


Jenis event (event
(event Listener (listener Metode (listener bertipe) Penjelasan
tanpa tipe)
bertipe) bertipe)

shellActivated(ShellEvent) SWT.Activate Jendela diaktifkan

Jendela Shell
shellClosed(ShellEvent) SWT.Close ditutup (dengan
tombol X)

ShellListener (dan Jendela


ShellEvent shellDeactivated(ShellEvent) SWT.Deactivate
ShellAdapter) dinonaktifkan

Jendela Shell
shellIconified(ShellEvent) SWT.Iconify
diminimasi

Jendela Shell
shellDeiconified(ShellEvent) SWT.Deiconify
dibuka (restore)

Untuk menambahkan event bertipe pada suatu shell, gunakan metode


addShellListener(ShellListener listener).
Berikut ini adalah contoh program untuk memberikan kotak dialog yang menanyakan apakah
kotak dialog akan ditutup, kemudian menampilkan tombol "Yes/No/Cancel". Program ini
menangkap event SWT.Close yang dilempar ketika program hendak ditutup. Jika jawaban user
"Cancel", maka variabel doit di dalam event akan diisi dengan false, yang berarti
membatalkan event menutup program.

Berikut ini adalah listing program lengkap, yang juga dapat diunduh di sini untuk diimport ke
dalam Eclipse.

package com.lyracc.tutupshell;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
 
public class TutupShell {
 
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
 
// Mengubah ukuran jendela dan mengeset judul jendela
shell.setSize(200, 200);
shell.setText("Tutup Shell");
 
// Membuat event listener shell menggunakan listener bertipe
ShellAdapter listener = new ShellAdapter() {
@Override
// Kita tindih metode shellClosed untuk mencegat event penutupan
shell
public void shellClosed(ShellEvent e) {
// Ambil shell dari mana event ini dikirim
Shell induk = (Shell)e.widget;
 
// Buat message box yang dengan modalitas aplikasi
// dan tombol yes, no, cancel
MessageBox box = new MessageBox(induk, SWT.YES | SWT.NO |
SWT.CANCEL | SWT.APPLICATION_MODAL);
 
// Set judul kotak dialog dengan judul yang sama dengan judul
jendela
box.setText(induk.getText());
 
// Set pesan yang akan ditampilkan
box.setMessage("Simpan hasil kerjaan Anda?");
 
// Buka pesan dialog, jika hasilnya "Cancel" batalkan
penutupan
// kotak dialog dengan mengeset doit = false;
// Jawaban lainnya (yes dan no) akan meneruskan penutupan
aplikasi
switch (box.open()) {
case SWT.YES: break;
case SWT.NO: break;
case SWT.CANCEL :
e.doit = false;
break;
}
}
};
 
// Tambah listener pada shell utama
shell.addShellListener(listener);
 
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
}

Kotak Dialog
Posted Min, 05/10/2009 - 19:09 by belajarprogram

Versi ramah cetak

Kelas Dialog adalah kelas super abstrak dari beberapa jenis kotak dialog yang merupakan kotak
dialog bawaan dari sistem operasi. Kotak dialog adalah shell tingkat tinggi yang digunakan oleh
sistem operasi untuk memasukkan suatu nilai atau memberi tahu user tentang suatu suatu pesan
atau kesalahan. Misalnya, kotak dialog file akan meminta user memilih suatu file yang kemudian
digunakan untuk programmer untuk membuka dan membaca isi file tersebut.

Kotak dialog sangat berbeda dari satu platform ke platofrm yang lain. Pada beberapa platform,
programmer bisa mengakses widget-widget di dalamnya, sedangkan pada platform lain hal ini
tidak dimungkinkan. Dengan alasan ini, SWT dianggap sebagai kotak hitam. Lebih penting lagi,
kotak dialog bukan widget. Dialog bukan kelas turunan dari kelas Widget dan tidak memiliki
metode yang dimiliki oleh widget-widget lain.

Ada beberapa jenis kotak dialog yang disediakan SWT :


Jenis kotak dialog Penjelasan

Kotak dialog untuk memberi pesan atau pertanyaan sederhana, seperti


MessageBox
Yes/No/Cancel/Ok

ColorDialog Kotak dialog untuk memilih warna

DirectoryDialog Kotak dialog untuk memilih direktori

FileDialog Kotak dialog untuk memilih file

FontDialog Kotak dialog untuk memilih huruf

PrintDialog Kotak dialog untuk melakukan pencetakan ke printer

Ada 3 jenis modalitas yang didukung oleh suatu kotak dialog, yang bisa diset sebagai bit gaya
ketika membuat kotak dialog :

 SWT.PRIMARY_MODAL, suatu kotak dialog memblok input induknya, default untuk kotak dialog
 SWT.APPLICATION_MODAL, suatu kotak dialog memblok input jendela-jendela lain pada
aplikasi yang sama
 SWT.SYSTEM_MODAL, suatu kotak dialog memblok seluruh jendela bahkan jendela aplikasi lain.

Untuk membuat kotak dialog, sama seperti pada jendela, yaitu dengan menggunakan konstruktor

new Dialog(Shell induk);

atau

new Dialog(Shell induk, int gaya);

Gaya yang bisa digunakan berbeda-beda tergantung dari jenis kotak dialognya.

Beberapa metode umum yang tersedia untuk semua jenis kotak dialog adalah sebagai berikut

Metode Penjelasan

getParent() Mengembalikan Shell yang merupakan induk dari kotak dialog ini

getStyle() Mengembalikan int yang merupakan kumpulan gaya dari kotak dialog ini

getText() Mengembalikan String yang merupakan judul kotak dialog

setText(String judul) Mengeset judul kotak dialog


 Kotak Dialog MessageBox
 Kotak Dialog FileDialog
 Kotak Dialog DirectoryDialog
 Kotak Dialog ColorDialog
 Kotak Dialog FontDialog

Kotak Dialog MessageBox


Posted Min, 05/10/2009 - 19:27 by belajarprogram

Versi ramah cetak

Kotak dialog bertipe MessageBox digunakan untuk memberikan pesan kepada user dan meminta
input sederhana dari user. Input yang diminta ini diberikan sebagai bit gaya ketika suatu kotak
dialog dibuat.

Berikut ini adalah beberapa bit gaya dari suatu MessageBox :

 Salah satu dari SWT.ICON_ERROR, SWT.ICON_INFORMATION, SWT.ICON_QUESTION,


SWT.ICON_WARNING, SWT.ICON_WORKING, yang memberikan tambahan icon sebagai penanda
jenis kotak dialog misalnya apakah kotak dialog ini merupakan kotak dialog kesalahan, informasi,
peringatan, atau pertanyaan. Misalnya, pada Windows Vista bit-bit gaya tersebut menampilkan
icon-icon seperti berikut

Gaya Gambar

SWT.ICON_ERROR

SWT.ICON_INFORMATION

SWT.ICON_QUESTION

SWT.ICON_WARNING

SWT.ICON_WORKING

 Bit gaya yang merupakan pertanyaan yang diberikan kepada user. Ada beberapa kombinasi yang
bisa digunakan, seperti pada tabel berikut, beserta contohnya pada Windows Vista.

Gaya Tampilan
SWT.OK
 

SWT.OK | SWT.CANCEL
 

SWT.YES | SWT.NO
 

SWT.YES | SWT.NO | SWT.CANCEL


 

SWT.RETRY | SWT.CANCEL
 

SWT.ABORT | SWT.RETRY | SWT.IGNORE


 

Metode-metode pada Message Box

Berikut ini adalah beberapa metode yang tersedia pada message box

Metode Penjelasan

setMessage(String Mengeset pesan yang akan ditampilkan pada MessageBox. Pesan ini akan
pesan) ditampilkan sebelum tombol Ok/Yes/No/Cancel/Retry/Abort/Ignore

String Mengembalikan String yang merupakan pesan yang akan ditampilkan pada
getMessage() MessageBox

1. Membuka kotak dialog untuk dipresentasikan kepada user


2. Mengembalikan int yang merupakan jawaban dari user. int yang
int open() dikembalikan bisa dibandingkan dengan salah satu dari SWT.YES,
SWT.NO, SWT.CANCEL, SWT.ABORT, SWT.RETRY, SWT.IGNORE untuk
mengecek tombol apa yang ditekan oleh user.

Untuk melihat contoh penggunaan MessageBox lihat contoh sebelumnya pada bahasan tentang event
pada shell.

Kotak Dialog FileDialog


Posted Min, 05/10/2009 - 20:59 by belajarprogram

Versi ramah cetak


Kelas FileDialog melambangkan kotak dialog untuk memilih file. Pada dasarnya ada dua jenis
kotak dialog pemilihan file, yaitu untuk menyimpan dan membaca file, seperti
diimplementasikan pada kebanyakan program File -> Open dan File -> Save. Keduanya hampir
sama dalam tampilan, kecuali beberapa detail lain yang berbeda, misalnya tombol "Open" pada
kotak dialog untuk membaca file, dan "Save" untuk kotak dialog untuk menyimpan file.

Kotak dialog pemilihan file bisa diset untuk memilih hanya beberapa file saja dengan bentuk
tertentu, misalnya hanya file berekstensi *.html saja yang ditampilkan dalam daftar file. Ini
disebut file filter. Kotak dialog pemiihan file juga bisa diset untuk memilih satu file saja atau
beberapa file sekaligus.

Mirip dengan kotak dialog lain, kotak dialog file tidak akan ditutup jika user sebelum user
menekan tombol "Open" atau "Save" atau "Cancel".

Berikut ini adalah beberapa bit gaya yang bisa diberikan ketika kotak dialog pemilihan file
dibuat dengan konstruktornya.

Bit gaya Penjelasan


SWT.OPEN Membuat kotak dialog untuk membuka file

SWT.CLOSE Membuat kotak dialog untuk menutup file

Membuat kotak dialog pemilihan file yang hanya bisa memilih satu file saja (perilaku
SWT.SINGLE
standar jika tidak disebutkan)

SWT.MULTI Membuat kotak dialog pemilihan file yang bisa memilih beberapa file sekaligus

Metode-metode pada FileDialog

Metode Penjelasan

1. Membuka kotak dialog untuk dipresentasikan kepada


user
2. Mengembalikan string yang merupakan nama lengkap
(termasuk direktorinya) file yang dipilih. Jika tidak ada
open()
file yang dipilih atau tombol Cancel ditekan, akan
mengembalikan null. Jika kotak dialog diset dengan
SWT.MULTI, dan beberapa file dipilih, hanya file
pertama yang dikembalikan

Mengembalikan String nama lengkap file yang dipilih, atau


getFileName()
string kosong jika tidak ada yang dipilih

Mengembalikan array String[] yang berisi nama-nama file


getFileNames() yang dipilih. Bisa berisi array dengan panjang 0 jika tidak ada file
yang dipilih

Mengeset nama file pada kotak dialog. Berguna untuk memberi


setFileName(String namafile) pentunjuk kepada user bahwa nama file dengan nama tertentu
saja yang sebaiknya dipilih

getFilterPath() Mengembalikan String path ketika kotak dialog ditutup

setFilterPath(String path) Mengeset path di mana pencarian file dimulai

Mengembalikan array String[] ekstensi file-file yang akan


getFilterExtensions()
ditampilkan pada kotak pencarian file

Mengeset ekstensi file-file yang akan ditampilkan pada kotak


setFilterExtensions(String[]
ekstensi)
pencarian file, misalnya "*.txt" untuk menampilkan hanya file
berekstensi txt saja.

getFilterNames() Mengembalikan String[] nama dari ekstensi file. Biasanya


nama ini digunakan untuk memberikan nama ekstensi yang lebih
jelas. Misalnya "File teks" untuk menjelaskan ekstensi "*.txt"

setFilterNames(String[] Mengeset penjelasan dari ekstensi file-file yang akan


namaEkstensi) ditampilkan.

Mengembalikan int yang berisi indeks ekstensi yang dipilih


getFilterIndex()
user. Indeks dimulai dari 0

Mengeset filter mana yang akan ditunjukkan terlebih dahulu


setFilterIndex(int indeks) kepada user. Jika tidak diset, maka ekstensi yang pertama kali
dimasukkan akan ditampilkan terlebih dahulu

Mengembalikan true jika kotak dialog tambahan untuk


getOverwrite()
menimpa file akan ditampilkan yang berguna untuk mencegah
user menimpa data. Digunakan pada kotak dialog bertipe
SWT.SAVE

Mengeset apakah kotak dialog tambahan untuk menimpa file


setOverwrite(boolean timpa)
untuk ditampilkan pada kotak dialog bertipe SWT.SAVE

Berikut ini (dapat diunduh di sini) adalah contoh untuk menampilkan kotak dialog untuk
menyimpan suatu file. Ketika Anda menjalankan program ini, shell kosong akan ditampilkan.
Jika Anda menekan tombol mouse di dalam shell kosong ini, kotak dialog untuk menyimpan file
akan ditampilkan. Hanya ada dua ekstensi yang diperbolehkan, yaitu "*.java" dan "*.class". Jika
nama file sudah ada, program akan menanyakan apakah Anda akan menimpa isi file. Jika tidak,
maka kotak dialog kembali ditampilkan. Jika ya, kotak dialog akan ditutup, dan hasil pilihan
Anda akan ditampilkan pada MessageBox yang berisi nama file pilihan Anda.

package com.lyracc.kotakdialogfile;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
 
public class KotakDialogFile {
 
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
 
// Mengubah ukuran jendela dan mengeset judul jendela
shell.setSize(200, 200);
shell.setText("Demo kotak dialog file");
 
// Membuat event listener shell menggunakan listener bertipe
MouseAdapter listener = new MouseAdapter() {
@Override
// Kita tindih metode mouseDown untuk menampilkan kotak dialog
// ketika mouse di klik
public void mouseDown(MouseEvent e) {
// Ambil shell dari mana event ini dikirim
Shell induk = (Shell)e.widget;
 
// Buat kotak dialog file yang dengan modalitas aplikasi
FileDialog kotakDialogFile = new FileDialog(induk,
SWT.SAVE |
SWT.APPLICATION_MODAL);
 
// Set judul kotak dialog
kotakDialogFile.setText("Nama file untuk disimpan");
// Set filter untuk menyaring ekstensi
kotakDialogFile.setFilterExtensions(new String[] {
"*.java", "*.class"
}
);
// Set penjelasan filter
kotakDialogFile.setFilterNames(new String[] {
"Sumber kode Java (*.java)", "File biner Java
(*.class)"
}
);
// Buat kotak dialog untuk menanyakan user apakah ingin
menimpa
// isi file yang sudah ada.
kotakDialogFile.setOverwrite(true);
 
// Buka kotak dialog file dan ambil file yang dipilih
// dan letakkan di variabel namaFile
String namaFile = kotakDialogFile.open();
 
MessageBox pesan = new MessageBox(induk,
SWT.ICON_INFORMATION | SWT.OK);
pesan.setMessage("File yang dipilih " + namaFile);
pesan.open();
}
};
 
// Tambah listener pada shell utama
shell.addMouseListener(listener);
 
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
}
Kotak Dialog DirectoryDialog
Posted Min, 05/10/2009 - 22:41 by belajarprogram

Versi ramah cetak

Kelas DirectoryDialog melambangkan kotak dialog untuk memilih direktori. Kelas ini lebih
sederhana dibandingkan dengan FileDialog. Kelas ini tidak memiliki bit gaya apapun.

Untuk membuat kotak dialog untuk direktori, cara yang sama bisa dilakukan seperti pada
FileDialog. Metode-metode yang dimiliki juga mirip dengan FileDialog dengan lebih sedikit
variasi, yaitu :

Metode Penjelasan

1. Membuka kotak dialog untuk dipresentasikan kepada user


2. Mengembalikan string yang merupakan nama lengkap direktori
open()
yang dipilih. Jika tidak ada direktori yang dipilih atau tombol
Cancel ditekan, akan mengembalikan null.

getFilterPath() Mengembalikan String path ketika kotak dialog ditutup

setFilterPath(String
path)
Mengeset path di mana pencarian file dimulai

getMessage() Mengembalikan String yang merupakan pesan yang ditampilkan sebagai


instruksi kepada user untuk memilih direktori

getMessage(String Mengeset pesan yang ditampilkan sebagai instruksi kepada user untuk
pesan) memilih direktori

Kotak Dialog ColorDialog


Posted Min, 05/10/2009 - 22:53 by belajarprogram

Versi ramah cetak

Kotak dialog ColorDialog digunakan untuk memilih warna, misalnya digunakan untuk memilih
warna huruf, latar belakang kanvas, dan lain sebagainya.

Kotak dialog ini tidak memiliki bit gaya atau event. Keluarannya bertipe RGB yang merupakan
representasi dari gabungan warna Red Green Blue yang tidak bergantung pada suatu device.
Kelas RGB tersedia dalam paket org.eclipse.swt.graphics

Untuk menggunakannya sama seperti pada kotak-kotak dialog lainnya.

Berikut ini adalah beberapa metode yang terdapat pada kelas ColorDialog

Metode Penjelasan
1. Membuka kotak dialog untuk dipresentasikan kepada user
open() 2. Mengembalikan RGB yang merupakan warna yang dipilih user. Jika tidak ada
warna yang dipilih atau tombol Cancel ditekan, akan mengembalikan null.

getRGB() Mengembalikan RGB warna yang dipilih user.

setRGB(RGB
warna)
Mengeset warna RGB awal ketika kotak dialog dipresentasikan kepada user

Kotak Dialog FontDialog


Posted Min, 05/10/2009 - 23:49 by belajarprogram

Versi ramah cetak

Kotak dialog FontDialog digunakan untuk memilih salah satu huruf dari huruf-huruf yang
tersedia pada suatu platform. Suatu huruf yang tersedia pada platform yang satu belum tentu
tersedia pada platform yang lain.

Sama seperti ColorDialog, kotak dialog ini tidak mempunyai bit gaya yang bisa diset. Untuk
menggunakannya mirip dengan kotak-kotak dialog yang lain.

Beberapa platform memungkinkan kita untuk mengeset jenis huruf dan warnanya sekaligus.
SWT juga menyediakan metode untuk mengambil warna dan jenis huruf yang dipilih user
sekaligus.

Kotak dialog FontDialog mengembalikan array objek bertipe FontData.

Berikut ini adalah beberapa metode yang tersedia pada FontDialog

Metode Penjelasan

1. Membuka kotak dialog untuk dipresentasikan kepada user


2. Mengembalikan FontData yang merupakan huruf yang dipilih.
open()
Jika tidak ada huruf yang dipilih atau tombol Cancel ditekan, akan
mengembalikan null.

Mengembalikan array FontData[] yang berupa kumpulan font yang


getFontList()
dipilih user.

setFontList(FontData
huruf)
Mengeset huruf yang menjadi default ketika kotak dialog ditampilkan

getRGB() Mengembalikan warna huruf yang dipilih dalam bentuk RGB


Mengeset warna huruf yang menjadi default ketika kotak dialog
setRGB(RGB warna)
ditampilkan

Berikut ini adalah contoh menggunakan FontDialog. Shell yang berisi "contoh teks" akan
berubah warna dan penampilannya apabila kita mengubah jenis hurufnya dengan menekan
tombol "Ubah huruf".

Listing program lengkapnya adalah sebagai berikut, atau bisa juga diunduh di sini untuk diimport
ke dalam Eclipse.
package com.lyracc.kotakdialogfont;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
 
public class KotakDialogFont {
 
/**
* @param args
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
 
// Mengeset layout shell
shell.setLayout(new RowLayout());
 
// Mengubah ukuran jendela dan mengeset judul jendela
shell.setText("Demo kotak dialog huruf");
 
// Membuat teks baru
final Text teks = new Text(shell,SWT.BORDER | SWT.H_SCROLL |
SWT.V_SCROLL);
teks.setLayoutData(new RowData(100, 200));
teks.setText("contoh teks");
 
// Membuat tombol baru
Button tombol = new Button(shell, SWT.PUSH);
tombol.setText("Ubah huruf");
 
// Membuat kotak dialog font baru
final FontDialog dialog = new FontDialog(shell);
dialog.setText("Pilih huruf");
 
// Membuat event listener menggunakan listener bertipe
SelectionAdapter listener = new SelectionAdapter() {
@Override
// Ketika tombol ditekan
public void widgetSelected(SelectionEvent e) {
// Jika kotak dialog mengembalikan null, artinya
// tidak ada huruf yang dipilih
if (dialog.open() == null) return;
 
// Referensi ke display
Display displayUtama = e.display;
 
// Mengambil huruf yang dipilih
FontData[] list = dialog.getFontList();
// Ubah dari FontData ke Font
Font huruf = new Font(displayUtama, list);
 
// Set huruf pada teks
teks.setFont(huruf);
// Jangan lupa hapus dari memori untuk mencegah kebocoran
memori
huruf.dispose();
 
// Ambil warna dari dialog. Jika tidak null, ubah warna teks
RGB rgb = dialog.getRGB();
if (rgb != null) {
Color warna = new Color(displayUtama, rgb);
teks.setForeground(warna);
warna.dispose();
}
}
};
 
// Tambah listener pada tombol
tombol.addSelectionListener(listener);
 
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
}

Dasar-dasar Kontrol dan Label


Posted Jum, 05/15/2009 - 22:07 by belajarprogram

Versi ramah cetak

Kelas Control merepresentasikan elemen user interface yang berada di dalam suatu jendela.
Kelas ini merupakan kelas abstrak yang tidak bisa digunakan secara langsung. Sedangkan Label,
Button, Text, dan kontrol-kontrol lain yang biasa kita temui pada suatu jendela merupakan kelas
turunan dari kelas Control yang bisa kita gunakan. Kelas Shell pun adalah salah satu kelas
turunan tidak langsung dari kelas Control, sehingga beberapa metode dan event pada kelas
Control tersedia pada kelas Shell.

Kelas Control memiliki beberapa bit gaya, yaitu

Bit gaya Keterangan

SWT.NONE Bit gaya kosong, tidak ada gaya apa-apa

Membuat label yang diberi garis tepi (border). Bit gaya SWT.BORDER dimiliki oleh
SWT.BORDER
semua Widget, bukan hanya Label

Teks akan ditampilkan dari kiri ke kanan seperti bahasa Indonesia, Inggris atau
SWT.LEFT_TO_RIGHT
Latin lainnya
SWT.RIGHT_TO_LEFT Teks akan ditampilkan dari kanan ke kiri seperti bahasa Arab dan Hebrew

Untuk lebih menjelaskan tentang kelas abstrak Control dan berbagai fiturnya mari kita lihat
kelas turunan yang paling sederhana, yaitu Label.

Label

Kelas Label adalah teks atau gambar yang tidak bisa dipilih oleh user dan tidak menghasilkan
event apa-apa. Label biasanya digunakan untuk menampilkan teks pasif, misalnya judul suatu
input teks atau keterangan lainnya.

Kelas Label memiliki beberapa bit gaya, yaitu

Bit gaya Keterangan

Membuat garis, baik horizontal atau vertikal, yang biasanya digunakan sebagai
SWT.SEPARATOR
pembatas antar label atau pembatas antar widget

SWT.SHADOW_IN

SWT.SHADOW_OUT
Hanya salah satu dari gaya ini yang boleh digunakan, hanya digunakan dengan
SWT.SEPARATOR
SWT.SHADOW_NONE

SWT.LEFT
Hanya salah satu dari gaya ini yang boleh digunakan, hanya berguna untuk teks atau
SWT.RIGHT
gambar
SWT.CENTER

SWT.WRAP Memotong teks jika tampilan tidak cukup besar

Mari kita buat contoh sederhana, yaitu menggambar satu jendela (shell) dan satu label yang
bertuliskan "Selamat Datang!". Kita bisa buat programnya seperti ini.

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
 
public class HelloSWT2 {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Label label1;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
HelloSWT2() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setSize(200, 200);
shell.setText("Hello SWT");
 
// Inisialisasi label
label1 = new Label(shell, SWT.LEFT);
label1.setText("Selamat Datang!");
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
HelloSWT2 hello = new HelloSWT2();
hello.run();
}
}

Apa yang Anda dapatkan? Anda terkejut  karena label tidak ditampilkan? Apa yang kurang dari
program kita di atas?

Ketika suatu kontrol pertama kali dibuat (label adalah kelas turunan dari kontrol, jadi label juga
berperilaku seperti kontrol), ukuran dan lokasinya adalah 0. Tugas kita sebagai programmer
untuk menentukan ukuran kontrol dan lokasi di mana ia akan diletakkan.

Bound (Tepi)
Suatu persegi panjang yang menjelaskan lokasi dan ukuran suatu kontrol pada induknya disebut
tepi suatu kontrol. Tepi suatu kontrol memiliki satuan piksel. Sedangkan unitnya relatif terhadap
induknya. Untuk shell utama, koordinatnya mengikuti koordinat layar. Untuk kontrol yang
berada di dalam shell, koordinat (0,0) adalah koordinat pojok kiri atas dari shell. Jika suatu
widget berada dalam widget lain, maka koordinat (0,0)-nya adalah koordinat pojok kiri atas dari
widget induknya.

Untuk mengeset dan mengambil lokasi dan ukuran suatu widget, kita bisa gunakan beberapa
metode berikut ini :

Metode Penjelasan

setBounds(int x, int y, int


lebar, int tinggi)
Mengeset lokasi dan ukuran suatu kontrol

Mengeset lokasi dan ukuran suatu kontrol. Parameternya


setBounds(Rectangle bound)
bertipe Rectangle

setLocation(int x, int y) Mengeset lokasi suatu kontrol relatif terhadap induknya

Mengeset lokasi suatu kontrol relatif terhadap induknya.


setLocation(Point koordinat)
Parameternya bertipe Point

setSize(int lebar, int tinggi) Mengeset ukuran suatu kontrol.

setSize(Point ukuran)
Mengeset ukuran suatu kontrol. Parameternya bertipe
Point

Mengembalikan Rectangle yang merupakan ukuran dan


getBounds()
lokasi suatu kontrol relatif terhadap induknya

Mengembalikan Point yang merupakan lokasi suatu


getLocation()
kontrol relatif terhadap induknya

Mengembalikan Point yang merupakan ukuran suatu


getSize()
kontrol

Perhatikan bahwa beberapa metode menerima dan mengembalikan Rectangle dan Point
sebagai parameter atau tipe keluarannya. Kelas Rectangle dan Point adalah kelas generik yang
dimiliki SWT untuk melambangkan persegi panjang dan suatu titik. Kelas-kelas ini didefinisikan
dalam paket org.eclipse.swt.graphics.

Kelas Rectangle memiliki variabel instansi x, y, height, dan width yang semuanya bertipe
int. Sedangkan kelas Point memiliki variabel instansi x dan y yang bertipe int.
Mari kita tengok kembali program di atas. Kita akan ubah sedikit yaitu memberi ukuran dan
lokasi label sehingga bisa ditampilkan dengan benar.

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
 
public class HelloSWT2 {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Label label1;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
HelloSWT2() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setSize(200, 200);
shell.setText("Hello SWT");
 
// Inisialisasi label
label1 = new Label(shell, SWT.LEFT);
label1.setText("Selamat Datang!");
label1.setBounds(10, 10, 150, 25); // set lokasi & ukuran kontrol
agar bisa ditampilkan
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
HelloSWT2 hello = new HelloSWT2();
hello.run();
}
}

Berikut ini adalah hasilnya.


Ukuran yang Dibutuhkan

Setiap widget yang kita buat memiliki ukuran tertentu yang bisa dihitung secara otomatis,
sehingga programmer tidak perlu menerka atau mencoba-coba ukuran widget yang diperlukan.
Pada contoh di atas, kita harus menentukan sendiri ukuran suatu widget dengan menggunakan
setBounds(), akan tetapi kadang-kadang cara ini sulit dilakukan jika jumlah yang kita gunakan
beraneka ragam.

Kelas Control memiliki beberapa metode yang berhubungan dengan ukuran widget yang
dibutuhkan.

Metode Penjelasan

Mengeset ukuran suatu kontrol secara otomatis, berdasarkan ukuran


pack()
minimum yang dibutuhkan oleh kontrol tersebut

Mengeset ukuran suatu kontrol secara otomatis. Jika berubah diisi


pack(boolean berubah) true, maka ukuran kontrol akan dihitung kembali, bukan diambil dari
cache.

Menghitung ukuran kontrol yang dibutuhkan. Sama dengan


computeSize(int wHint, computeSize(wHint, hHint, true). Mengembalikan
int hHint) [code]Point

computeSize(int wHint, Menghitung ukuran kontrol yang dibutuhkan, dimana wHint adalah


int hHint, lebar kira-kira, dan hHint adalah tinggi kira-kira. Jika berubah diisi true
boolean
berubah)
maka ukuran kontrol akan dihitung kembali, bukan diambil dari cache.

Metode pack() digunakan untuk mengeset suatu kontrol secar otomatis berdasarkan ukuran
minimum yang dibutuhkan oleh kontrol tersebut. Pada contoh label di atas, kita bisa mengganti
instruksi setBounds() dengan rangkaian perintah pack() dan setLocation() untuk mengeset
ukuran dan lokasinya secara terpisah. Misalnya,
...
// Inisialisasi label
label1 = new Label(shell, SWT.LEFT);
label1.setText("Selamat Datang!");
label1.pack(); // set ukuran kontrol otomatis
label1.setLocation(10, 10); // set lokasi kontrol
...

Metode computeSize() digunakan untuk menghitung ukuran yang dibutuhkan oleh suatu
kontrol sehingga kontrol tersebut bisa digambar dengan utuh. Dengan kata lain kita ingin
menjawab pertanyaan ini : berapa tinggi yang dibutuhkan jika lebarnya adalah x, atau berapa
lebar yang dibutuhkan jika tingginya adalah y, atau berapa lebar dan tinggi yang dibutuhkan
secara umum.

Untuk menjawab pertanyaan tersebut, kita membutuhkan dua variabel, yaitu salah satu nilai
"saran", yaitu nilai yang kita sudah ketahui, dan nilai SWT.DEFAULT untuk menandai variabel
yang ingin kita cari. Misalnya

 Untuk menghitung tinggi widget jika lebarnya kira-kira 10 piksel, kita bisa menggunakan
label1.computeSize(10, SWT.DEFAULT)
 Untuk menghitung lebar widget jika tingginya kira-kira 10 piksel, kita bisa menggunakan
label1.computeSize(SWT.DEFAULT, 10)
 Untuk menghitung lebar dan tinggi widget yang dibutuhkan secara bersamaan, kita bisa
menggunakan label1.computeSize(SWT.DEFAULT,SWT.DEFAULT)

Event Ketika Kontrol Berpindah Tempat

Ketika suatu kontrol berpindah tempat, misalnya karena digeser atau ukurannya diubah oleh
user, event tertentu akan dilepaskan. Kita bisa memasang listener pada kontrol tersebut untuk
menangani event yang terjadi. Berikut ini adalah event yang terkait dengan perubahan lokasi dan
ukuran suatu kontrol.

Interface/Kelas Jenis event


Kelas Event
Listener (listener Metode (listener bertipe) (event tanpa Penjelasan
(event bertipe)
bertipe) tipe)

Posisi suatu
controlMoved(ControlEvent) SWT.Move kontrol
ControlListener (dan berubah
ControlEvent
ControlAdapter)
Ukuran kontrol
controlResized(ControlEvent) SWT.Resize berubah

Contoh berikut membuat dua buah shell, yaitu shell utama dan shell kedua. Shell kedua adalah
shell kosong tanpa tepi mirip seperti tool tip. Jika shell utama berubah posisi atau ukuran, shell
kedua akan tergeser secara otomatis sehingga jaraknya tetap sama.
Berikut ini adalah kode sumbernya yang bisa diunduh di sini.

package com.lyracc.shellpindah;
 
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
 
public class ShellPindah {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Shell shellKedua;
 
// Jarak antara kedua shell
private int jarakShell = 20;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
ShellPindah() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setSize(200, 200);
shell.setText("Shell Pindah");
 
// Inisialisasi Shell kedua
shellKedua = new Shell(shell,SWT.TOOL);
shellKedua.setSize(100,100);
 
// Tambah listener jika shell utama berubah ukuran dan lokasi
shell.addControlListener(new ControlListener() {
 
@Override
public void controlMoved(ControlEvent e) {
pindah();
}
 
@Override
public void controlResized(ControlEvent e) {
pindah();
}
 
});
 
// Jangan lupa shell harus di-open..
shellKedua.open();
}
 
// Pindahkan shell kedua
private void pindah() {
// Ambil ukuran dan lokasi shell pertama
Rectangle pp = shell.getBounds();
 
// Set lokasi shell kedua
shellKedua.setLocation(
pp.x + pp.width + jarakShell,
pp.y);
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
ShellPindah shellPindah = new ShellPindah();
shellPindah.run();
}
}

 Mengeset Teks pada Label


 Menggunakan Label sebagai Garis Pemisah
 Mengeset Warna
 Mengeset Huruf
 Menampilkan gambar

Mengeset Teks pada Label


Posted Sab, 05/16/2009 - 12:01 by belajarprogram

Versi ramah cetak


Suatu label bisa diisi teks atau gambar, tapi tidak keduanya secara bersamaan. Berikut ini adalah
beberapa metode yang digunakan untuk mengeset dan mengambil teks dan gambar pada label.

Metode Penjelasan

setText(String teks) Mengeset teks pada label

getText() Mengembalikan String yang merupakan teks pada label

Berikut ini adalah contoh mengeset teks dan gambar pada suatu label

Label label1 = new Label(shell, SWT.LEFT);


label1.setText("Selamat Datang!");

SWT.BORDER

SWT.BORDER adalah bit gaya yang tersedia pada Control. Semua kontrol, termasuk Label bisa
menggunakan bit gaya ini. Bit gaya ini memberikan garis tepi di sekitar kontrol. Misalnya, dari
contoh pada bagian sebelumnya, kita tambahkan SWT.BORDER sebagai bit gaya pada label1,
maka keluarannya ada seperti gambar berikut ini.

...
// Inisialisasi label
label1 = new Label(shell, SWT.LEFT | SWT.BORDER);
label1.setText("Selamat Datang!");
label1.setBounds(10, 10, 150, 25); // set lokasi & ukuran kontrol
agar bisa ditampilkan
...

Kerapatan Teks

Kita juga bisa mengatur kerapatan (alignment) suatu teks atau gambar. Selain menggunakan bit
gaya SWT.LEFT, SWT.RIGHT, atau SWT.CENTER pada konstruktor. Atau kita juga bisa
menggunakan metode instansi pada kelas tombol berikut :

Metode Penjelasan

setAlignment(int Mengeset kerapatan suatu teks atau gambar, rapatan hanya bisa berisi
rapatan) SWT.LEFT, SWT.RIGHT, atau SWT.CENTER

Mengambil int yang merupakan rapatan suatu teks atau gambar pada
getAlignment()
label.

Misalnya,
Label labelTeks = new Label(shell, SWT.NONE); // Tanpa bit gaya
labelTeks.setText("Tombolku");
labelTeks.setAlignment(SWT.LEFT);

Ilustrasi berikut menunjukkan label dengan tiga kerapatan berbeda, menggunakan bit gaya
SWT.LEFT, SWT.RIGHT, dan SWT.CENTER.

Memangkas Teks

Jika kita ingin agar label yang kita tampilkan hanya terbatas pada ukuran tertentu saja, bit gaya
SWT.WRAP bisa digunakan untuk ini. SWT.WRAP memberitahukan kontrol untuk memotong teks
sehingga tidak ada teks yang terpotong dengan paksa. Berikut ini adalah contoh perbedaan label
yang menggunakan SWT.WRAP (label atas) dan yang tidak (label bawah).

Kode lengkapnya adalah sebagai berikut :

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
 
public class HelloSWT3 {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Label label1;
private Label label2;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
HelloSWT3() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setSize(200, 200);
shell.setText("Hello SWT");
 
// Inisialisasi label
label1 = new Label(shell, SWT.LEFT | SWT.BORDER | SWT.WRAP);
label1.setText("Selamat Datang di sini");
label1.setLocation(10, 10); // set lokasi kontrol
 
// Hitung ukuran kontrol yang dibutuhkan
Point ukuran = label1.computeSize(SWT.DEFAULT, SWT.DEFAULT);
 
// Set lebar kontrol menjadi setengahnya
ukuran.x = ukuran.x/2;
label1.setSize(ukuran);
 
// Inisialisasi label
label2 = new Label(shell, SWT.LEFT | SWT.BORDER);
label2.setText("Selamat Datang di sini");
label2.setLocation(10, 40); // set lokasi kontrol
 
// Hitung ukuran kontrol yang dibutuhkan
ukuran = label2.computeSize(SWT.DEFAULT, SWT.DEFAULT);
 
// Set lebar kontrol menjadi setengahnya
ukuran.x = ukuran.x/2;
label2.setSize(ukuran);
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
HelloSWT3 hello = new HelloSWT3();
hello.run();
}
}

Menggunakan Label sebagai Garis Pemisah


Posted Sab, 05/16/2009 - 21:29 by belajarprogram

Versi ramah cetak

Kelas Label bisa digunakan untuk membuat garis pemisah, baik horizontal maupun vertikal,
yaitu dengan menggunakan bit gaya SWT.SEPARATOR yang digabungkan dengan salah satu dari
SWT.HORIZONTAL atau SWT.VERTICAL.
Garis pemisah biasanya digunakan untuk memisahkan item pada menu, atau memisahkan
pertanyaan dan tombol pada kotak dialog. Garis pemisah juga memiliki bit gaya lain, yaitu
SWT.SHADOW_IN, SWT.SHADOW_OUT dan SWT.SHADOW_NONE untuk menggambar beberapa jenis
garis pemisah, akan tetapi bit gaya ini tidak tersedia pada semua platform. Untuk platform yang
tidak tersedia seperti Linux, bit gaya ini tidak berpengaruh apa-apa.

Contoh kode berikut menggambar kedua jenis garis pemisah.

import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
 
public class HelloSWT4 {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Label label1;
private Label label2;
private Label label3;
private Label label4;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
HelloSWT4() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setSize(250, 200);
shell.setText("Hello SWT");
 
// Inisialisasi label
label1 = new Label(shell, SWT.CENTER);
label1.setText("Vertikal");
label1.setBounds(10, 10, 100, 15);
 
label2 = new Label(shell, SWT.CENTER);
label2.setText("Horizontal");
label2.setBounds(120, 10, 100, 15);
 
label3 = new Label(shell, SWT.SEPARATOR | SWT.VERTICAL);
label3.setBounds(10, 40, 100, 100);
 
label4 = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL);
label4.setBounds(120, 40, 100, 100);
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
HelloSWT4 hello = new HelloSWT4();
hello.run();
}
}

Mengeset Warna
Posted Sab, 05/16/2009 - 22:37 by belajarprogram

Versi ramah cetak

Kelas Control memiliki metode untuk mengeset latar belakang dan latar depan suatu kontrol.
Pada Label, latar belakang Label adalah ruangan di sekitar garis tepi atau wilayah yang
ditentukan dengan metode setBounds(), sedangkan latar depan Label adalah warna teksnya.

Karena kelas Control adalah kelas super dari kontrol-kontrol lain, bukan hanya Label, tetapi
juga Button, Text dan Shell misalnya, maka metode-metode ini juga bisa digunakan oleh
kontrol-kontrol lain yang merupakan kelas turunan dari Control. Latar belakang dan latar depan
tiap-tiap kontrol berbeda-beda tergantung dari kontrolnya.

Berikut ini adalah beberapa metode pada kelas Control untuk mengatur warna.

Metode Penjelasan

setForeground(Color warna) Mengeset warna latar depan suatu kontrol

setBackground(Color warna) Mengeset warna latar belakang suatu kontrol

Mengambil warna latar depan suatu kontrol. Tipe keluarannya bertipe


getForeground()
Color
Mengambil warna latar belakang suatu kontrol. Tipe keluarannya bertipe
getBackground()
Color

Perhatikan bahwa metode-metode di atas bekerja dengan menggunakan input dan output warna
bertipe Color. Kelas Color terdapat pada paket org.eclipse.swt.graphics

Kelas Color

Instansi kelas Color digunakan untuk melambangkan warna yang sebenarnya yang telah
diberikan oleh sistem operasi.

Kelas ini bisa dibuat dengan dua cara : mengambil instansi warna dari sistem, dan membuat
objek sendiri dari paduan warna merah, hijau dan biru (RGB). Khusus untuk cara yang kedua,
programmer bertanggung jawab untuk menghapus objek ini dari memori sistem dengan
menggunakan dispose() setelah kita selesai menggunakannya.

Mengambil warna sistem

Cara termudah untuk mengisi kelas Color untuk digunakan dalam mengeset latar belakang dan
latar depan suatu kontrol adalah dengan mengambil warna sistem. Warna sistem terdiri dari dua
jenis, yaitu warna deskriptif dan warna sistem.

Warna deskriptif adalah warna seperti yang kita kenal, seperti merah, hijau, biru. Akan tetapi
setiap platform memiliki daftar warna tersendiri. Oleh karena itu, SWT menyimpan warna-warna
ini dalam konstanta pada kelas SWT, misalnya SWT.COLOR_RED. Warna ini kita ubah
menjadi objek bertipe Color dengan menggunakan perintah getSystemColor(int
konstantaWarna) yang terdapat pada objek berkelas Display, misalnya

Color warna = display.getSystemColor(SWT.COLOR_RED);

Warna-warna deskriptif yang disimpan pada kelas SWT adalah sebagai berikut :

Warna

SWT.COLOR_WHITE

SWT.COLOR_BLACK

SWT.COLOR_RED

SWT.COLOR_DARK_RED

SWT.COLOR_GREEN

SWT.COLOR_DARK_GREEN
SWT.COLOR_YELLOW

SWT.COLOR_DARK_YELLOW

SWT.COLOR_BLUE

SWT.COLOR_DARK_BLUE

SWT.COLOR_MAGENTA

SWT.COLOR_DARK_MAGENTA

SWT.COLOR_CYAN

SWT.COLOR_DARK_CYAN

SWT.COLOR_GRAY

SWT.COLOR_DARK_GRAY

Warna sistem adalah warna yang dimiliki oleh sistem sebagai warna default suatu kontrol.
Misalnya, warna default latar belakang tombol selalu sama pada Windows, demikian juga pada
Linux. Jika warna ini diubah oleh user melalui Control Panel Windows, misalnya, maka seluruh
aplikasi akan mengikuti warna ini. Keuntungannya, warna aplikasi yang kita buat akan selalu
konsisten dengan warna sistem operasi. Warna sistem ini juga disimpan sebagai konstanta pada
kelas SWT, dan digunakan dengan cara yang sama dengan warna deskriptif di atas.

Perlu diingat bahwa tidak semua sistem operasi memiliki kesemua warna ini. Untuk mengetahui
warna aktual suatu widget kita bisa menggunakan perintah getBackground() dan
getForeground seperti disebutkan di awal bagian ini.

Warna sistem yang disediakan oleh SWT adalah sebagai berikut

Warna Penjelasan

SWT.COLOR_WIDGET_DARK_SHADOW Warna bayangan gelap suatu widget

SWT.COLOR_WIDGET_NORMAL_SHADOW Warna bayangan normal suatu widget

SWT.COLOR_WIDGET_LIGHT_SHADOW Warna bayangan terang suatu widget

SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW Warna bayangan highlight suatu widget

SWT.COLOR_WIDGET_FOREGROUND Warna latar depan widget

SWT.COLOR_WIDGET_BACKGROUND Warna latar belakang widget


SWT.COLOR_WIDGET_BORDER Warna tepi

SWT.COLOR_LIST_FOREGROUND Warna latar depan suatu list

SWT.COLOR_LIST_BACKGROUND Warna latar belakang suatu list

SWT.COLOR_LIST_SELECTION Warna latar belakang item yang dipilih

SWT.COLOR_LIST_SELECTION_TEXT Warna teks item yang dipilih

SWT.COLOR_INFO_FOREGROUND Warna latar depan tool tip

SWT.COLOR_INFO_BACKGROUND Warna latar belakang tool tip

SWT.COLOR_TITLE_FOREGROUND Warna latar depan judul jendela

SWT.COLOR_TITLE_BACKGROUND Warna latar belakang judul jendela

Warna gradasi latar belakang judul jendela


SWT.COLOR_TITLE_BACKGROUND_GRADIENT (hanya pada Windows lama, seperti Windows
2000)

Warna latar depan judul jendela yang tidak


SWT.COLOR_TITLE_INACTIVE_FOREGROUND
aktif

Warna latar belakang judul jendela yang tidak


SWT.COLOR_TITLE_INACTIVE_BACKGROUND
aktif

Warna gradasi latar belakang judul jendela


SWT.COLOR_TITLE_INACTIVE_BACKGROUND_GRADIENT yang tidak aktif (hanya pada Windows lama,
seperti Windows 2000)

Kelas RGB

Kelas ini merupakan representasi dari warna merah, hijau dan biru (red, green, blue = RGB),
yang merupakan komposisi suatu warna di layar. Kelas RGB berbeda dengan kelas Color di mana
RGB hanya berisi representasi dari warna tersebut, bukan merupakan warna yang sesungguhnya
yang bisa diolah atau diberikan kepada suatu kontrol.

Instasiasi dari kelas RGB bisa dibuat dengan menggunakan konstruktor dengan bentuk RGB(int
merah, int hijau, int biru).
Karena tidak menggunakan memori dari sistem operasi, maka seringkali instansi kelas ini
digunakan dalam transaksi data dengan widget lain, misalnya pada ColorDialog, warna yang
dipilih oleh user akan disimpan dalam bentuk RGB.

Seperti disebutkan sebelumnya, instansi kelas ini tidak bisa digunakan langsung untuk mengeset
latar belakang atau latar depan suatu kontrol. Untuk bisa digunakan, kita harus meminta alokasi
dari sistem operasi, yaitu dalam bentuk objek bertipe Color. Caranya yaitu dengan menggunakan
salah satu konstruktor kelas Color yang berbentuk seperti

Color(Device perangkat, RGB rgb)

Di sini perangkat bisa berupa display atau printer. Setelah kita berhasil meminta warna dari
sistem operasi, kita bisa mengecek apakah warna yang dihasilkan sesuai dengan yang kita
berikan dengan menggunakan metode pada kelas Color, yaitu

 getRed() untuk mendapatkan warna merah


 getGreen untuk mendapatkan warna hijau
 getBlue() untuk mendapatkan warna biru
 getRGB() untuk mendapatkan objek bertipe RGB yang merupakan gabungan merah, hijau dan
biru.

Apakah ini berarti bahwa warna yang kita minta belum tentu sama dengan warna yang diberikan
suatu perangkat? Jawabannya benar. Untuk perangkat yang memiliki warna tak terbatas, warna
yang kita set akan sama dengan warna yang kita dapat. Ada beberapa perangkat yang hanya
memiliki sejumlah warna tertentu. Artinya, warna-warna yang didukung oleh perangkat ini
terbatas jumlahnya. Ketika sistem operasi meminta warna dari perangkat ini, warna yang
terdekat yang akan diberikan kembali kepada kita. Ini sangat berguna untuk menjamin
portabilitas SWT di berbagai platform dan perangkat.

Mari kita lihat contoh berikut, di mana label akan kita berikan warna latar depan dan warna latar
belakang yang berbeda dari defaultnya. Program lengkapnya bisa Anda unduh di sini.

package com.lyracc.warnalabel;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.graphics.*;
 
public class WarnaLabel {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Label label1;
private Label label2;
private Color warna1;
private Color warna2;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
WarnaLabel() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setSize(250, 200);
shell.setText("Hello SWT");
 
// Inisialisasi label
label1 = new Label(shell, SWT.CENTER | SWT.BORDER);
label1.setText("Hello dari SWT");
label1.setBounds(10, 10, 200, 25);
 
// Set warna, cara pertama dengan mengambil warna dari sistem
label1.setBackground(display.getSystemColor(SWT.COLOR_BLUE));
label1.setForeground(display.getSystemColor(SWT.COLOR_YELLOW));
 
label2 = new Label(shell, SWT.CENTER | SWT.BORDER);
label2.setText("Hallo dari SWT");
label2.setBounds(10, 40, 200, 25);
 
// Set warna, cara kedua dengan membuat objek Color dan RGB
warna1 = new Color(display, new RGB(255,255,0)); // menggunakan objek
RGB
warna2 = new Color(display, 0, 0, 255); // konstruktor Color jenis
lain
label2.setBackground(warna1);
label2.setForeground(warna2);
warna1.dispose(); // objek ini harus dihapus manual dari memori
warna2.dispose(); // objek ini harus dihapus manual dari memori
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
WarnaLabel jendela = new WarnaLabel();
jendela.run();
}
}

Mengeset Huruf
Posted Min, 05/17/2009 - 12:26 by belajarprogram

Versi ramah cetak

Kelas Control memiliki metode untuk mengeset huruf kontrol. Berikut ini adalah beberapa
metode pada kelas Control untuk mengatur warna.

Metode Penjelasan

setFont(Font huruf) Mengeset huruf suatu kontrol

getFont() Mengambil huruf suatu kontrol. Tipe keluarannya bertipe Font

Perhatikan bahwa metode-metode di atas bekerja dengan menggunakan input dan output huruf
bertipe Font. Kelas Font terdapat pada paket org.eclipse.swt.graphics.

Seperti pada warna dengan Color dan RGB, huruf memiliki dua kelas sejenis, yaitu Font dan
FontData. Kelas Font, seperti Color adalah huruf yang sudah dialokasikan oleh sistem operasi,
sedangkan FontData seperti RGB adalah representasi huruf yang belum dialokasi oleh sistem
operasi.

Ingat bahwa jenis huruf sangat dipengaruhi oleh sistem operasi. Jenis huruf tertentu hanya ada
pada sistem operasi tertentu, sehingga sangat sulit untuk membuat aplikasi yang bergantung pada
huruf tertentu. Kita bisa juga mengontrol penggunaan huruf hingga detail, misalnya jeda antar
huruf, tinggi huruf dan lainnya, tapi dalam prakteknya, teknik ini jarang digunakan untuk
memodifikasi suatu kontrol. Kecuali jika Anda ingin membuat widget sendiri, atau ingin
menggambar langsung pada kanvas. Kita tidak akan membahas hingga ke level detail seperti ini.

Kelas Font

Instansi kelas Font digunakan untuk melambangkan huruf yang sebenarnya yang telah diberikan
oleh sistem operasi.

Kelas ini bisa hanya bisa dibuat dengan membuat objek sendiri dengan menggunakan
konstruktornya. Programmer bertanggung jawab untuk menghapus objek ini dari memori sistem
dengan menggunakan dispose() setelah kita selesai menggunakannya. Berikut ini adalah
konstruktor kelas Font yang tersedia :

Konstruktor Penjelasan

Font(Device device, Membuat huruf pada suatu perangkat (baik display atau printer)
FontData fd) dengan input FontData

Membuat huruf pada suatu perangkat (baik display atau printer)


Font(Device device,
FontData[] fds)
dengan input beberapa FontData yang tersusun dalam bentuk array
(hanya Mac OS yang bisa memiliki lebih dari satu jenis huruf)

Font(Device device, Membuat huruf pada suatu perangkat (baik display atau printer)
String name, int height, dengan input nama, tinggim dan gayanya. Gaya adalah salah satu atau
int style) gabungan dari SWT.NORMAL, SWT.BOLD, dan SWT.ITALIC

Mengambil instansi FontData dari Font

Misalnya kita hanya ingin mengubah ukuran huruf dari suatu kontrol. Cara yang paling mudah
dan bisa bekerja untuk semua platform adalah dengan mengambil huruf yang digunakan suatu
kontrol, dengan menggunakan getFont(), kemudian mengambil instansi FontData dari Font
yang dihasilkan. Kemudian kita konstruksi lagi Font baru dengan menambahkan ukuran huruf,
atau gayanya. Dengan huruf yang baru, kita gunakan setFont() untuk mengaplikasikannya
pada kontrol kita.

Untuk mengambil FontData dari suatu Font, kita bisa gunakan metode instansi getFontData()
dari kelas Font. Akan tetapi yang dikembalikan adalah array dari FontData. Pada Windows
hanya ada satu huruf yang dikembalikan, akan tetapi pada Mac OS, beberapa huruf bisa
dikembalikan. Misalnya lihat contoh berikut ini.

....
Font huruf = label1.getFont();
FontData[] dataHuruf = huruf.getFontData();
....

Kelas FontData

Kelas FontData bisa diambil dari suatu widget (seperti contoh sebelumnya), dari sistem operasi
(mengambil huruf yang disediakan oleh sistem operasi), atau membuatnya sendiri.

Untuk mengambil FontData yang tersedia pada suatu perangkat, kita bisa menggunakan metode
instansi getFontList(String namaFace, boolean scalable) dari suatu perangkat yang
dikembalikan dalam bentuk array. namaFace adalah nama huruf yang akan kita ambil, dan jika
scalable bernilai true, hanya huruf yang bisa diperbesar/diperkecil tanpa mengurangi keindahan
huruf saja yang akan diambil. Misalnya contoh berikut mengambil semua huruf yang tersedia
pada display,

FontData[] daftarHuruf = display.getFontList(null, true);

Untuk membuat FontData dari konstruktornya, tersedia beberapa jenis konstruktor, yaitu

Konstruktor Penjelasan

FontData() Membuat instansi FontData kosong

Membuat instansi FontData dengan input string yang menjelaskan


FontData(String string) nama dan ukuran huruf, dengan format seperti yang dikembalikan
oleh metode toString()

Membuat instansi FontData dengan input nama, tinggi huruf dan


FontData(String nama, int
tinggi, int gaya)
gaya. Gaya huruf bisa merupakan salah satu atua kombinasi dari
SWT.NORMAL, SWT.BOLD dan SWT.ITALIC

Untuk memanipulasi FontData berikut ini adalah beberapa metode yang bisa digunakan

Metode Penjelasan

getName() Mengembalikan String yang merupakan nama huruf

setName(String nama) Mengeset nama huruf

getStyle() Mengembalikan int yang merupakan gaya huruf

Mengeset gaya huruf, salah satu atau kombinasi dari SWT.NORMAL,


setStyle(int gaya)
SWT.BOLD dan SWT.ITALIC

getHeight() Mengembalikan int yang merupakan tinggi atau ukuran huruf

setHeight(int tinggi) Mengeset tinggi huruf

getLocale() Mengambil kedaerahan (locale) huruf dalam bentuk String

setLocale(String
locale)
Mengeset kedaerahan huruf

Mari kita simak contoh berikut ini. Kita akan membuat label dengan miring dan tebal dari suatu
kontrol. Ukurannya juga akan kita ubah menjadi 2 kali lipatnya. Algoritmanya bisa dituangkan
sebagai berikut :
 Ambil Font dari label tersebut
 Ambil FontData dari Font
 Modifikasi setiap FontData yang dikembalikan
 Buat Font baru
 Gunakan setFont() untuk mengeset huruf ke label tersebut

Algoritma tersebut dapat kita tuangkan seperti

...
Font huruf = label1.getFont();
FontData[] dataHuruf = huruf.getFontData();
for (int i = 0; i < dataHuruf.length; i++) {
dataHuruf[i].setStyle(SWT.BOLD | SWT.ITALIC);
dataHuruf[i].setHeight(dataHuruf[i].getHeight() * 2);
}
Font hurufBaru = new Font(display, dataHuruf);
label1.setFont(hurufBaru);
hurufBaru.dispose();
...

Kita modifikasi sedikit program kita sebelumnya untuk menampilkan label dengan huruf dan
warna berbeda. Program lengkapnya bisa diunduh di sini.

package com.lyracc.hurufdanwarnalabel;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.graphics.*;
 
public class HurufDanWarnaLabel {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Label label1;
private Label label2;
private Color warna1;
private Color warna2;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
HurufDanWarnaLabel() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setSize(500, 200);
shell.setText("Hello SWT");
 
// Inisialisasi label
label1 = new Label(shell, SWT.CENTER | SWT.BORDER);
label1.setText("Hello dari SWT");
label1.setBounds(10, 10, 400, 50);
 
// Set warna, cara pertama dengan mengambil warna dari sistem
label1.setBackground(display.getSystemColor(SWT.COLOR_BLUE));
label1.setForeground(display.getSystemColor(SWT.COLOR_YELLOW));
 
// Modifikasi huruf
Font huruf = label1.getFont();
FontData[] dataHuruf = huruf.getFontData();
for (int i = 0; i < dataHuruf.length; i++) {
dataHuruf[i].setStyle(SWT.BOLD | SWT.ITALIC);
dataHuruf[i].setHeight(dataHuruf[i].getHeight() * 2);
}
Font hurufBaru = new Font(display, dataHuruf);
label1.setFont(hurufBaru);
hurufBaru.dispose();
 
label2 = new Label(shell, SWT.CENTER | SWT.BORDER);
label2.setText("Hallo dari SWT");
label2.setBounds(10, 70, 200, 25);
 
// Set warna, cara kedua dengan membuat objek Color dan RGB
warna1 = new Color(display, new RGB(255,255,0)); // menggunakan objek
RGB
warna2 = new Color(display, 0, 0, 255); // konstruktor Color jenis
lain
label2.setBackground(warna1);
label2.setForeground(warna2);
warna1.dispose(); // objek ini harus dihapus manual dari memori
warna2.dispose(); // objek ini harus dihapus manual dari memori
 
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
HurufDanWarnaLabel jendela = new HurufDanWarnaLabel();
jendela.run();
}
}

Menampilkan gambar
Posted Min, 05/17/2009 - 16:15 by belajarprogram

Versi ramah cetak

Seperti halnya warna dan huruf pada SWT, ada dua kelas yang digunakan untuk menampilkan
gambar pada SWT : ImageData untuk melambangkan gambar dalam format yang tidak
tergantung pada suatu perangkat, dan Image yang merupakan representasi gambar pada suatu
perangkat.

Suatu kontrol memiliki beberapa metode untuk menampilkan gambar di latar depan ataupun latar
belakangnya. Tentunya, ini tergantung dari kontrol tersebut bagaimana hal ini akan
diimplementasikan. Pada Label misalnya, latar belakang bisa diset berbentuk gambar
menggantikan warna latar belakangnya. Atau bisa juga label diisi dengan gambar sebagai
pengganti teksnya.

Berikut ini adalah beberapa metode untuk mengeset suatu gambar pada kontrol.

Metode Penjelasan

setBackgroundImage(Image Mengeset latar belakang kontrol dengan gambar sebagai


gambar) pengganti warna latar belakang

setImage(Image gambar) Mengeset gambar sebagai pengganti teks pada kontrol

Mengembalikan Image yang merupakan gambar latar belakang


getBackgroundImage()
suatu kontrol

getImage() Mengembalikan Image yang merupakan gambar pada kontrol

Seperti warna dan huruf suatu kontrol yang memiliki pasangan Color dan RGB atau Font dan
FontData, gambar juga memiliki pasangan Image dan ImageData. ImageData bisa juga
dipergunakan untuk melakukan pengolahan gambar sederhana, misalnya mengganti kontras
melakukan clipping, dan sebagainya, akan tetapi kita tidak akan membahas terlalu detail tentang
gambar pada bagian ini. Kita akan bahas lebih lanjut bagaimana untuk mengeset gambar latar
depan dan latar belakang suatu kontrol.

Kelas Image
Kelas Image bisa diinstansiasi ke dalam bentuk objek dengan menggunakan beberapa
konstruktor. Salah satunya yang paling mudah digunakan adalah bentuk konstruktor seperti
Image(Device device, String namaFileGambar), di mana device adalah perangkat yang
akan digunakan untuk menampilkan gambar, bisa display atau printer, dan namaFileGambar
adalah path di mana file gambar yang akan kita tampilkan berada.

Misalnya, pada perintah berikut

Image gambar = new Image(display, "contoh.png");

digunakan untuk mengimport gambar ke dalam objek bernama gambar. Objek ini bisa kita
gunakan untuk mengeset gambar latar belakang atau pengganti teks pada suatu kontrol. Akan
tetapi ingat objek ini juga harus dihapus dari sistem operasi dengan memanggil
gambar.dispose() secara eksplisit setelah tidak lagi digunakan.

Jika ukuran suatu kontrol lebih besar dari pada gambar yang akan kita tampilkan di latar
belakangnya, maka gambar tersebut akan diulang-ulang untuk memenuhi tampilan suatu kontrol.
Kita bisa menggunakan metode instansi getBounds() dari suatu Image untuk mendapatkan
ukuran gambar yang diperlukan. Hasilnya bisa kita gunakan untuk mengeset kontrol yang akan
kita gunakan untuk menampilkan gambar.

Contoh berikut menampilkan dua jenis label, di mana yang pertama menampilkan gambar
sebagai warna latar belakangnya, dan yang satu menampilkan gambar sebagai pengganti teks.
Program lengkapnya dapat diunduh di sini.

package com.lyracc.gambarlabel;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.graphics.*;
 
public class GambarLabel {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Label label1;
private Label label2;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
GambarLabel() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setSize(250, 200);
shell.setText("Hello SWT");
 
// Inisialisasi label
label1 = new Label(shell, SWT.CENTER | SWT.BORDER);
label1.setText("Hello dari SWT");
label1.setBounds(10, 10, 200, 50);
label1.setForeground(display.getSystemColor(SWT.COLOR_RED));
 
// Inisialisasi gambar
Image gambar = new Image(display,"contoh.png");
 
label1.setBackgroundImage(gambar); // Set gambar sebagai latar
belakang
 
label2 = new Label(shell, SWT.CENTER | SWT.BORDER);
label2.setBounds(10, 70, 200, 50);
label2.setImage(gambar); // Set gambar
 
gambar.dispose(); // Jangan lupa menghapus gambar dari memori
 
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
GambarLabel jendela = new GambarLabel();
jendela.run();
}
}

Button (Tombol)
Posted Kam, 05/14/2009 - 23:49 by belajarprogram

Versi ramah cetak


Kelas Button melambangkan suatu tombol yang jika ditekan atau dilepaskan akan melepaskan
event tertentu.

Kelas Button memiliki beberapa bit gaya :

Tampilan (pada
Bit gaya Keterangan
Linux)

SWT.ARROW
 

SWT.CHECK  

SWT.PUSH Hanya salah satu dari gaya ini yang boleh digunakan
 

SWT.RADIO
 

SWT.TOGGLE
 

Menampilkan tombol dengan tampilan "rata", bukan seperti


SWT.FLAT tombol biasa yang memiliki tampilan 3D seperti tombol tekan.
 
(Hanya untuk beberapa platform tertentu saja)

SWT.LEFT

SWT.RIGHT Hanya salah satu dari gaya ini yang boleh digunakan

SWT.CENTER

SWT.UP

SWT.DOWN
Hanya boleh digunakan bersama dengan SWT.ARROW
SWT.LEFT

SWT.RIGHT
Suatu tombol bisa diisi teks atau gambar, tapi tidak keduanya secara bersamaan. Teks yang diisi
pada suatu tombol tidak dapat berisi baris baru '\n' atau '\r'. Berikut ini adalah beberapa metode
yang digunakan untuk mengeset dan mengambil teks dan gambar pada tombol.

Metode Penjelasan

setText(String teks) Mengeset teks pada tombol

getText() Mengembalikan String yang merupakan teks pada tombol

setImage(Image image) Mengeset gambar pada tombol

getImage() Mengembalikan Image yang merupakan gambar pada tombol

Berikut ini adalah contoh mengeset teks dan gambar pada suatu tombol :

Button tombolTeks = new Button(shell, SWT.PUSH);


tombolTeks.setText("Tombolku");
 
ImageData dataGambar = new ImageData("c:\\grafik.bmp");
Image gambar = new Image(display, dataGambar);
Button tombolGambar = new Button(shell, SWT.PUSH);
tombolGambar.setImage(gambar);

Kita juga bisa mengatur kerapatan (alignment) suatu teks atau gambar. Selain menggunakan bit
gaya SWT.LEFT, SWT.RIGHT, atau SWT.CENTER pada konstruktor. Atau kita juga bisa
menggunakan metode instansi pada kelas tombol berikut :

Metode Penjelasan

setAlignment(int Mengeset kerapatan suatu teks atau gambar, rapatan hanya bisa berisi
rapatan) SWT.LEFT, SWT.RIGHT, atau SWT.CENTER

getAlignment() Mengambil int yang merupakan rapatan suatu teks atau gambar pada tombol.

Misalnya,

Button tombolTeks = new Button(shell, SWT.PUSH);


tombolTeks.setText("Tombolku");
tombolTeks.setAlignment(SWT.LEFT);

Tombol SWT.PUSH

Tombol ini memiliki sifat tombol biasa, yaitu ketika di klik tombol akan tampil seperti ditekan,
dan ketika dilepas maka tombol akan kembali seperti biasa. Tombol ini memiliki event berikut :
Interface/Kelas
Kelas Event
Listener Jenis event (event Penjelasa
(event Metode (listener bertipe)
(listener tanpa tipe) n
bertipe)
bertipe)

Suatu aksi
pemilihan
dilakukan
pada
pilihan
widgetDefaultSelected(SelectionEv SWT.DefaultSelecti default
ent) on (misalnya
ketika
tombol
SelectionListene Enter
SelectionEven r (dan ditekan)
t SelectionAdapte
r) Suatu aksi
pemilihan
dilakukan
dalam
widget
widgetSelected(SelectionEvent) SWT.Selection (misalnya
memilih
item pada
drop
down list

Misalnya untuk menambahkan listener untuk event yang terjadi ketika tombol ditekan, kita bisa
menggunakan SWT.Selection, misalnya pada contoh berikut :

Button tombolTeks = new Button(shell, SWT.PUSH);


tombolTeks.setText("Tombolku");
tombolTeks.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
// Perintah-perintah lainnya
}
});

Tombol SWT.ARROW

Tombol ini secara perilaku mirip dengan SWT.PUSH, akan tetapi perbedaannya tombol ini tidak
bisa diisi teks atau gambar. Tombol ini akan menggambar tanda panah, yang arahnya tergantung
dari bit gaya yang diberikan, bisa ke kiri, kanan, atas atau bawah.
Tombol SWT.TOGGLE

Berbeda dengan tombol SWT.PUSH, tombol ini ketika diklik akan berada dalam posisi tertekan
terus walaupun mouse sudah dilepaskan. Untuk mengembalikannya, tombol ini harus diklik
kembali. Karena tombol ini bisa memiliki dua keadaan, yaitu keadaan tertekan dan keadaan
terlepas, ada dua metode yang kita bisa gunakan untuk mengeset keadaan tombol atau untuk
mengambil keadaan tombol saat itu, yaitu

Metode Penjelasan

Mengeset keadaan suatu tombol. Jika pilih bernilai true, maka tombol
berada dalam keadaan
setSelection(boolean tertekan.</td></tr><tr><td>getSelection()</td><td>Mengembalika
pilih) n [code]boolean yang berisi keadaan suatu tombol apakah dalam keadaan
tertekan atau terlepas

Tombol SWT.CHECK

Tombol SWT.CHECK tidak berbentuk seperti tombol, akan tetapi perilakunya mirip dengan
SWT.TOGGLE. Secara tampilan, SWT.CHECK ditampilkan seperti tombol kotak tik, yang
apabila diklik kotak tik akan tercontreng. Untuk menghilangkan contrengan, klik kembali kotak
cek tersebut.

Karenanya, mirip seperti SWT.TOGGLE, tombol ini memiliki dua keadaan tetap, yaitu kondisi
tercontreng dan tidak tercontreng. Untuk mengeset keadaan ini, gunakan metode yang sama
dengan SWT.TOGGLE, yaitu setSelection() dan getSelection().

Tombol SWT.RADIO

Tombol ini mirip seperti SWT.CHECK, di mana apabila kita mengklik tombol radio, maka
tombol tersebut berada dalam keadaan terpilih. Perbedaannya, jika beberapa tombol
SWT.RADIO berada dalam satu induk, maka hanya satu tombol radio saja yang bisa aktif.
Artinya jika kita mengklik tombol radio kedua, maka tombol ini akan terpilih dan yang lainnya
akan mati. Untuk mengesetnya, gunakan metode yang sama seperti pada SWT.CHECK dan
SWT.TOGGLE.

Biasanya, hanya satu tombol radio pada suatu kotak dialog atau jendela tidak masuk akal. Karena
hanya ada tombol radio yang bisa aktif, maka satu tombol radio ini akan selalu aktif, sehingga
percuma untuk diletakkan dalam GUI. Jika ada dua tombol radio, perilakunya persis sama
dengan satu tombol SWT.CHECK (jika satu aktif, maka yang lainnya pasti tidak aktif). Untuk
itu tombol radio biasanya digunakan untuk meminta user memilih satu dari sekian banyak
pilihan.

Berikut ini adalah contoh program yang bisa Anda unduh di sini. Program ini akan menggambar
beberapa jenis tombol. Jika salah satu tombol ditekan, maka warna latar belakang jendela akan
berubah-ubah. Warna-warna ini disimpan dalam palette warna dalam bentuk array. Jika warna
terakhir sudah ditampilkan, kemudian tombol ditekan kembali, maka warna pertama akan
ditampilkan kembali.

package com.lyracc.tombolwarna;
 
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
 
public class TombolWarna {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Color[] warna;
private int warnaSekarang = 0;
final int JUMLAHWARNA = 10;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
TombolWarna() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setLayout(new RowLayout());
 
// Ubah ukuran jendela menjadi 200 x 200 piksel
shell.setSize(250, 200);
 
// Inisialisasi tombol-tombol
Button tombol = new Button(shell,SWT.PUSH);
tombol.setText("Tombolku SWT.PUSH");
 
Button tombol1 = new Button(shell,SWT.ARROW | SWT.LEFT);
 
Button tombol2 = new Button(shell,SWT.TOGGLE);
tombol2.setText("Tombolku SWT.TOGGLE");
 
Button tombol3 = new Button(shell,SWT.CHECK);
tombol3.setText("Tombolku SWT.CHECK");
 
Button tombol4 = new Button(shell,SWT.RADIO);
tombol4.setText("Tombolku SWT.RADIO");
 
// Mengeset event
ListenerTombolWarna listenerTombolWarna = new
ListenerTombolWarna();
tombol.addSelectionListener(listenerTombolWarna);
tombol1.addSelectionListener(listenerTombolWarna);
tombol2.addSelectionListener(listenerTombolWarna);
tombol3.addSelectionListener(listenerTombolWarna);
tombol4.addSelectionListener(listenerTombolWarna);
 
// Mengeset warna-warna
warna = new Color[JUMLAHWARNA];
warna[0] = display.getSystemColor(SWT.COLOR_BLACK);
warna[1] = display.getSystemColor(SWT.COLOR_BLUE);
warna[2] = display.getSystemColor(SWT.COLOR_CYAN);
warna[3] = display.getSystemColor(SWT.COLOR_GRAY);
warna[4] = display.getSystemColor(SWT.COLOR_GREEN);
warna[5] = display.getSystemColor(SWT.COLOR_MAGENTA);
warna[6] = display.getSystemColor(SWT.COLOR_RED);
warna[7] = display.getSystemColor(SWT.COLOR_WHITE);
warna[8] = display.getSystemColor(SWT.COLOR_YELLOW);
warna[9] =
display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
}
 
// Kelas listener ketika tombol ditekan
class ListenerTombolWarna extends SelectionAdapter {
public void widgetSelected(SelectionEvent e) {
// Jika warna lebih sudah di akhir array
// kembali ke warna 0
if (warnaSekarang == warna.length)
warnaSekarang = 0;
shell.setBackground(warna[warnaSekarang++]);
}
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
TombolWarna tombolWarna = new TombolWarna();
tombolWarna.run();
}
}

Text
Posted Sen, 06/01/2009 - 14:45 by belajarprogram

Versi ramah cetak

Kelas Text digunakan sehingga user bisa mengetikkan atau mengedit suatu teks. Kelas ini juga
merupakan turunan dari kelas Control sehingga memiliki metode, bit gaya, dan event seperti
pada kelas Control lainnya. Berikut ini adalah metode, bit gaya, dan event khusus untuk kelas
Text

Tampilan (pada
Bit Gaya Keterangan Aturan
Linux)

Membuat garis tepi di sekitar


SWT.BORDER  
teks

SWT.SINGLE Membuat input teks satu baris

Hanya boleh salah satu


Membuat input teks banyak SWT.SINGLE atau SWT.MULTI
SWT.MULTI
baris

SWT.LEFT Kerapatan teks kiri

SWT.CENTER Kerapatan teks tengah Hanya boleh salah satu

SWT.RIGHT Kerapatan teks kanan

SWT.PASSWORD Input teks password  

Membuat input teks hanya bisa


SWT.READ_ONLY  
dibaca

Membuat input teks yang


SWT.WRAP  
terpotong (bukan tergulung).

Variabel Keterangan

DELIMITER Karakter pemisah baris. Biasanya mengikuti sistem operasi (Windows "\r\n" dan Linux "\n")
akan tetapi kita bisa atur sesuai kebutuhan

LIMIT Maksimum karakter yang bisa dimasukkan ke dalam input teks

Kontrol Text adalah elemen user interface yang digunakan sehingga user bisa memasukkan atau
mengedit string. Kontrol ini bisa dipilih. Pilhannya merupakan tempat di mana karakter akan
dimasukkan. Jika pilihannya lebih dari satu karakter, kontrol Text akan menggambar karakter
yang dipilih berbeda dengan karakter yang tidak dipilih (misalnya diberi warna latar belakang
biru atau hitam, sedangkan teks yang dipilih berwarna terang). Jika pilihannya tidak ada, maka
akan digambar seperti caret yang bentuknya seperti huruf I. Caret adalah garis vertikal yang
muncul di antara karakter. Caret ini memberi petunjuk kepada user dimana karakter yang diketik
akan dimasukkan.

Gambar berikut adalah caret yang diletakkan di akhir teks. Di bawahnya, ketika salah satu
karakter dipilih.

Kontrol Text hanya mendukung teks "biasa". Artinya semua karakter pada kontrol ini memiliki
jenis huruf dan warna yang sama. Jika kita membutuhkan kontrol untuk mengedit teks yang lebih
fleksibel, kita bisa menggunakan org.eclipse.swt.custom.StyledText yang didesain untuk
Eclipse. Perhatikan bahwa StyledText bukan widget alami bawaan sistem operasi.

Suatu program aplikasi bisa mendeteksi bahwa sesuatu dalam kontrol teks telah berubah, atau
untuk memfilter huruf/angka ketika diketik oleh user. Misalnya, suatu aplikasi memberi teks
peringatan bahwa hanya angka dari 0-9 saja yang bisa dimasukkan. Untuk itu, aplikasi akan
mendengarkan event SWT.Modify dan SWT.Verify yang akan dijelaskan kemudian.

Ada dua jenis kontrol teks : yang memiliki satu baris teks dan yang memiliki beberapa baris teks.

Kontrol Text Satu Baris dan Multi Baris

Bit gaya SWT.SINGLE digunakan untuk membuat kontrol teks satu baris. Potongan kode berikut
membuat kontrol teks satu baris yang dilengkapi dengan garis tepi, kemudian mengisi teksnya
dengan "asd".

Text teks1 = new Text(shell, SWT.BORDER | SWT.SINGLE);


teks1.setText("asd");

Kontrol teks banyak baris dibuat dengan menggunakan bit gaya SWT.MULTI. Tidak seperti
kontrol teks satu baris, kontrol teks banyak baris bisa kita lengkapi dengan SWT.H_SCROLL atau
SWT.V_SCROLL pada bit gayanya untuk membuat scroll bar horizontal dan vertikal. Berikut ini
adalah potongan kontrol banyak baris dengan garis tepi dan scroll bar, dengan teks yang cukup
panjang.

teks2 = new Text(shell, SWT.BORDER | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);


teks2.setText("Hallo SWT, saya sedang belajar " + Text.DELIMITER + "membuat
program dengan SWT");
teks2.setSize(100, 70);

Operasi String

Kontrol Text memiliki beberapa metode untuk mengisi dan mengambil string dari widget mirip
seperti Label dan Button.

Metode Penjelasan

Mengeset isi teks. Isi sebelumnya dihapus, kemudian isi baru dimasukkan. Caret
akan ditempatkan pada awal teks. Jika teks berisi pemisah baris (misalnya "\n")
setText(String s)
pada kontrol dengan bit gaya SWT.SINGLE hasilnya tidak akan sesuai dengan
yang diharapkan. Karakter mnemonik tidak didukung pada kontrol Text

getText() Mengambil String yang merupakan isi teks

Mengambil String yang merupakan isi teks dimulai dari karakter ke- mulai
getText(int hingga karakter ke-akhir, termasuk karakter ke-mulai dan karakter ke-akhir.
mulai, int akhir) Indeks dimulai dari nol. Jika indeks berada di luar jangkauan, SWT akan mencoba
mengambil karakter sebanyak mungkin.

getCharCount Mengembalikan int yang merupakan jumlah karakter pada kontrol.

Sebagian string dalam kontrol teks dapat dapat dipilih dengan menggunakan metode
setSelection(). Metode ini mengambil argumen berupa posisi caret awal dan posisi caret
akhir pilihan. Berikut ini adalah ilustrasi posisi caret di dalam suatu kontrol Text

Metode Penjelasan
setSelection(int Mengeset pilihan pada kontrol dari posisi caretAwal ke posisi
caretAwal, int caretAkhir. Jika caretAwal dan caretAkhir bernilai sama, maka caret
caretAkhir) akan berubah menjadi kursor di posisi tersebut.

setSelection(int Sama dengan memanggil dengan setSelection(caretAwal,


caretAwal) caretAwal)

Memilih semua string pada kontrol text. Sama dengan memanggil


selectAll()
dengan setSelection(0, teks1.getCharCount())

Menghapus pilihan dan memindahkan kursor ke posisi pilihan


clearSelection() pertama. (Misalnya, teks "hello" dipilih sebelumnya, setelah metode
ini dipanggil, posisi kursor akan berpindah ke sebelum "h")

Mengembalikan Point yang merupakan posisi pilihan. Point.x yang


getSelection() dikembalikan adalah posisi caretAwal dan Point.y adalah posisi
caretAkhir.

getSelectionCount() Mengembalikan int yaitu jumlah karakter yang ada di dalam pilihan

Program berikut membuat input teks banyak baris, yang kemudian memilih kata "Indonesia",
seperti pada gambar berikut.

package com.lyracc.pilihteks;
 
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
 
public class PilihTeks {
 
// Variabel-variabel widget kita deklarasikan sebagai
// variabel privat
private Display display;
private Shell shell;
private Text teks1;
 
// Konstruktor kelas ini, untuk menginisialisasi semua widget
PilihTeks() {
// Membuat display dan shell baru
display = new Display();
shell = new Shell(display);
shell.setText("Hello SWT");
shell.setSize(200,250);
shell.setLayout(new FillLayout());
 
// Inisialisasi label
teks1 = new Text(shell, SWT.BORDER | SWT.MULTI |
SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL);
teks1.setText("Kita bersama-sama di sini, untuk menegaskan " +
"kembali Indonesia tempat kita berdiri.");
teks1.setSelection(52, 61);
}
 
// Perintah "standar" SWT, harus ada pada setiap aplikasi SWT
public void run() {
shell.open();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
 
/**
* @param args
*/
public static void main(String[] args) {
// Instansiasi kelas ini, kemudian jalankan run
PilihTeks jendela = new PilihTeks();
jendela.run();
}
}

Menyisipkan dan Menambah Teks

Karakter bisa disisipkan ke dalam kontrol teks dengan metode insert() atau bisa ditambahkan
dengan metode append(). Penyisipan dilakukan pada posisi kursor, sedangkan penambahan teks
selalu dilakukan di akhir teks. Untuk menyisipkan teks pada posisi tertentu, pindahkan dahulu
posisi caret ke posisi yang diinginkan dengan setSelection(), baru lakukan penyisipan.

Metode Penjelasan

insert(String s) Menyisipkan String s pada posisi caret.


append(String s) Menambahkan String s di akhir input teks

Jika sebagian teks sudah dipilih, maka teks yang dipilih akan dihapus, kemudian teks baru disisipkan di
posisi tersebut.

Operasi Clipboard

Kontrol Text menyediakan fasilitas copy, cut, dan paste ke clipboard. Kontrol ini juga
mendukung tombol shortcut (misalnya Ctrl-C, Ctrl-X, dan Ctrl-V) untuk melakukan operasi
clipboard dari dan ke kontrol ini. Beberapa platform juga menyediakan menu konteks (yang
keluar ketika kita mengklik kanan di kontrol tersebut) yang berisi operasi clipboard ini.

Metode Penjelasan

cut() Teks yang dipilih di-cut ke dalam clipboard

copy() Teks yang dipilih di-copy ke dalam clipboard

Menyisipkan karakter dari dalam clipboard di posisi caret. Jika caret sudah memilih sebagian
paste()
teks, teks dipilih akan dihapus dan diganti dengan teks dari clipboard

Membatasi Jumlah Karakter yang Bisa Diinput

Untuk beberapa aplikasi, kadang diperlukan batas jumlah karakter yang diinput oleh user.
Misalnya, dalam aplikasi database, beberapa tabel hanya bisa menerima input sejumlah karakter
saja. Untuk itu, aplikasi perlu membatasi jumlah karakter yang bisa diinput oleh user.

Metode Penjelasan

setTextLimit(int Mengeset maksimum jumlah karakter yang bisa dimasukkan ke dalam input
batas) teks

Mengembalikan int yang merupakan batas maksimum jumlah karakter


getTextLimit()
yang bisa dimasukkan ke dalam input teks

Password dan Karakter Echo

Untuk membuat input teks yang disamarkan, seperti untuk field password, kita bisa
menggunakan bit gaya SWT.PASSWORD. Ketika user mengetikkan karakter pada input teks ini,
karakter yang diinput oleh user akan disamarkan dengan suatu karakter, misalnya (*) atau (.).
Kita bisa mengeset karakter apa yang digunakan untuk menyamarkan inputnya. Karakter ini
disebut karakter echo.

Metode Penjelasan
setEchoCharacter(char c) Mengeset karakter echo dengan karakter tertentu

Mengembalikan char yang merupakan karakter echo dari input teks


getEchoCharacter()
password

Bekerja Dengan Input Teks Banyak Baris

Input teks banyak baris memiliki fitur tambahan dibandingkan dengan input teks satu baris.
Salah satunya, karena inputnya bisa terdiri dari beberapa baris, kita bisa mengeset bagaimana
teks akan ditampilkan. Jika kita menggunakan SWT.WRAP, maka teks yang panjang akan otomatis
dipotong sehingga akan ditampilkan dalam beberapa baris.

Kita juga bisa mengeset karakter apa yang digunakan sebagai pembatas baris. Setiap sistem
operasi memiliki pembatas baris yang mungkin berbeda-beda. (Misalnya pada Windows "\n\r",
pada Linux "\n", dan pada Macintosh "\r"). KIta bisa mengubah pembatas barisnya, akan tetapi
mungkin aplikasi yang kita buat sulit bekerja lintas platform.

Variabel statik DELIMITER pada kelas Text digunakan untuk mengetahui pembatas baris pada
suatu platform. Ketika kita membaca input teks dari user, sistem operasi akan otomatis
menambahkan pembatas baris. Untuk itu kadang kita perlu mengetahui pembatas barisnya,
sehingga input dari user bisa kita olah lebih tepat. Metode lain yang bisa digunakan adalah
getLineDelimiter().

Menggulung Teks

Input teks banyak baris membutuhkan scroll bar baik horizontal dan vertikal. Kadang-kadang
kita perlu menggulung layar secara otomatis (supaya user tidak perlu lagi menggulung layar
sendiri, misalnya jika teks yang kita berikan sangat panjang dan kita hanya tertarik pada bagian
akhir teks).

Metode Penjelasan

setTopIndex(int
i)
Menggulung layar sehingga baris ke-i ditampilkan di baris pertama input teks

getTopIndex() Mengembalikan int yang merupakan baris pertama input teks yang ditampilkan.

Jika input teks berupa input teks banyak baris, dan pilihan tidak ditunjukkan,
misalnya karena tersembunyi di bagian bawah teks yang panjang, setelah
showSelection()
memanggil showSelection(), maka teks yang dipilih akan otomatis ditunjukkan,
yaitu dengan menggeser scroll bar secara otomatis hingga pilihan terlihat

Anda mungkin juga menyukai