Kelas yang dipakai dalam program berasal dari dua sumber, yaitu kelas yang ditulis sendiri dan kelas bawaan Java seperti String atau Scanner. Java mengelompokkannya ke dalam package, yaitu unit pengelompokan yang sekaligus menjadi ruang nama (namespace). Topik ini membahas cara mendeklarasikan package, cara import memangkas penulisan namanya, dan cara memilih nama fully-qualified (fully-qualified name) ketika dua nama kelas bertabrakan.
Package sebagai ruang nama kelas#
Setiap kelas di Java berada di dalam sebuah package, dan nama lengkap kelasnya terdiri atas nama package ditambah nama kelas, misalnya java.util.Random. Dua kelas boleh bernama sama asalkan package-nya berbeda, sehingga ruang nama ini mencegah tabrakan nama pada proyek yang menggabungkan banyak pustaka. Program berukuran satu berkas biasanya tidak menyatakan package, sehingga kelasnya berada di package tak bernama (unnamed package), yaitu kondisi yang wajar untuk tahap belajar.
Pada proyek yang dikompilasi dengan javac, package dipetakan ke folder. Deklarasi package util; berarti berkasnya berada di dalam folder util, sehingga bentuk fisiknya dan deklarasinya saling mengunci. Struktur berikut adalah proyek kecil dengan dua package.
aplikasi-nilai/
└── src/
├── util/
│ └── KonversiNilai.java
└── laporan/
└── CetakLaporan.javaDua berkas pada pohon di atas dideklarasikan seperti berikut. Berkas pertama menyediakan metode pembantu, sedangkan berkas kedua memakainya lewat import.
// tidak-dijalankan
package util;
public class KonversiNilai {
public static int skala(int nilai, int maks) {
return nilai * 100 / maks;
}
}// tidak-dijalankan
package laporan;
import util.KonversiNilai;
public class CetakLaporan {
public static void main(String[] args) {
System.out.println(KonversiNilai.skala(80, 100));
}
}Konvensi penamaannya konsisten huruf kecil, tanpa garis bawah dan tanpa huruf kapital. Pustaka yang disebarluaskan ke pihak lain lazimnya memakai nama domain terbalik, misalnya com.contoh.perhitungan, agar unik secara global. Package bawaan platform Java diawali java, seperti java.util dan java.lang, dan di antara semuanya java.lang mendapat perlakuan khusus yang dibahas pada bagian berikutnya.
Mengimpor kelas dengan import#
Tanpa import, kelas dari package lain tetap bisa dipakai dengan menulis nama lengkapnya setiap kali dipanggil. Import memperkenalkan nama pendeknya pada kompiler, sehingga cukup ditulis Random di sisa berkas. Deklarasinya ditempatkan di bawah pernyataan package dan di atas deklarasi kelas.
Program berikut memakai kelas Random dari package java.util untuk mengocok dua dadu. Kelas Math dari package java.lang dipakai tanpa import, karena package java.lang diimpor otomatis pada setiap berkas Java.
import java.util.Random;
public class DemoImport {
public static void main(String[] args) {
// Random berada di package java.util, sehingga perlu diimpor
Random acak = new Random(42);
int daduSatu = acak.nextInt(6) + 1;
int daduDua = acak.nextInt(6) + 1;
// Math berada di package java.lang yang diimpor otomatis
System.out.println("Dadu 1 : " + daduSatu);
System.out.println("Dadu 2 : " + daduDua);
System.out.println("Terbesar: " + Math.max(daduSatu, daduDua));
}
}Dadu 1 : 3
Dadu 2 : 4
Terbesar: 4Pemanggilan new Random(42) mengisi biji (seed) pengacak, sehingga urutan angkanya tetap sama pada setiap eksekusi dan cocok untuk contoh yang harus dapat diulang. Tanpa biji, Random memakai sumber keacakan sistem dan hasilnya berubah setiap kali program dijalankan. Dua bentuk import yang tersedia adalah import java.util.Random; untuk satu kelas dan import java.util.*; untuk seluruh kelas dalam satu package. Berkas yang membutuhkan banyak kelas asing menuliskan baris import berturut-turut di bagian atasnya. Konvensinya mengurutkan import secara alfabetis agar mudah dicari, sehingga dua import dari satu package bersebelahan.
Memilih antara import dan nama fully-qualified#
Pilihan antara keduanya ditentukan oleh kebiasaan berkasnya. Import per kelas menjadi pilihan utama, karena asal setiap nama terbaca pada bagian atas berkas. Nama fully-qualified dipilih ketika pemakaiannya hanya sekali, atau ketika dua kelas senama harus dipakai dalam satu berkas, karena import ganda atas dua kelas bernama sama ditolak kompiler.
| Situasi | Pilihan yang lazim |
|---|---|
| Kelas dipakai beberapa kali dalam satu berkas | import satu kelas |
| Banyak kelas dari satu package | import dengan tanda bintang, misalnya java.util.* |
| Kelas dipakai satu kali saja | nama fully-qualified tanpa import |
| Dua kelas senama dari package berbeda | nama fully-qualified untuk salah satu atau keduanya |
Contoh berikut memakai dua kelas Tanggal dari dua package berbeda dalam satu berkas. Import untuk keduanya tidak dapat dinyatakan sekaligus, sehingga salah satunya ditulis lengkap.
// tidak-dijalankan
import laporan.Tanggal;
Tanggal tanggalCetak = new Tanggal();
util.Tanggal tanggalUjian = new util.Tanggal();Import dengan tanda bintang praktis pada package yang dipakai menyeluruh, tetapi bentuk ini menyembunyikan asal setiap nama. Peluang ambiguitas juga naik bila dua package yang diimpor memuat kelas bernama sama, sehingga kompiler menampilkan pesan reference to Tanggal is ambiguous. Kebiasaan yang aman adalah import eksplisit per kelas, lalu nama fully-qualified untuk kasus khusus. Pada berkas yang panjang, daftar import di bagian atasnya menjadi peta ketergantungan yang mudah dibaca, sehingga asal setiap nama pendek dapat dilacak sekejap.
Mengompilasi proyek bertanda package#
Proyek dengan pernyataan package dikompilasi dari folder akar sumbernya, yaitu folder yang langsung memuat package-package terluar. Perintah javac mengompilasi seluruh berkas sekaligus, sedangkan perintah java menjalankan kelas utama dengan nama fully-qualified-nya, memakai tanda titik sebagai pemisah dan tanpa akhiran .java. Nama berkas sumber diberikan lengkap dengan foldernya kepada javac, sedangkan java tidak menerima berkas sama sekali, melainkan nama kelas yang dicari di dalam classpath.
# tidak-dijalankan
# dijalankan dari dalam folder src, hasil kompilasi dikumpulkan di folder out
javac -d out util/KonversiNilai.java laporan/CetakLaporan.java
# menjalankan kelas utama dengan nama fully-qualified-nya
java -cp out laporan.CetakLaporanOpsi -d out mengumpulkan hasil kompilasi ke folder out, dan opsi -cp menunjuk folder akar tempat package bermula, sehingga java dapat menemukan laporan.CetakLaporan di dalamnya. Folder out pun mencerminkan struktur package, yaitu out/util/KonversiNilai.class dan out/laporan/CetakLaporan.class, sehingga pohon folder sumber terulang kembali pada hasil kompilasi. Perintah-perintah tersebut tidak dapat dijalankan di lingkungan penulisan topik ini karena javac tidak tersedia di sana, tetapi jalannya sama pada mesin dengan JDK terpasang. Keluaran programnya sama persis dengan versi satu berkas, karena package tidak mengubah perilaku kode, melainkan mengatur alamat dan hubungan antarkelasnya.
Kesalahan umum#
- Kelas dipakai tanpa import dan tanpa nama lengkap, sehingga kompiler menolak dengan
cannot find symbol: class Random. Perbaikannya menambahkanimport java.util.Random;atau menulisjava.util.Randomdi tempat pemakaiannya. - Berkas tidak diletakkan di folder yang sesuai dengan package-nya, sehingga kelas yang mengimpornya gagal dikompilasi dengan
cannot find symbol. Perbaikannya menyamakan letak berkas dengan deklarasinya, misalnyaKonversiNilai.javadi dalam folderutil. - Kelas bertanda package dijalankan dengan nama pendek, misalnya
java CetakLaporan, dan JVM menjawabError: Could not find or load main class. Perbaikannya memakai nama fully-qualified, yaitujava -cp out laporan.CetakLaporan. - Mengira
importmenambah ukuran program atau menyalin kode. Import hanya pemberian nama bagi kompiler, dan tidak ada isi package yang disalin ke dalam berkas. - Meninggalkan baris import yang tidak terpakai. Program tetap berjalan, tetapi daftar import yang panjang menyesatkan pembaca tentang ketergantungan berkasnya. Hapus import yang tidak dipakai, dan IDE umumnya menyediakan aksinya.
Ringkasan#
- Package adalah ruang nama yang dipetakan ke folder, dan nama lengkap kelasnya berbentuk
namapackage.NamaKelas. - Import memperkenalkan nama pendek kelas pada kompiler, package
java.langdiimpor otomatis, dan tidak ada kode yang disalin oleh import. - Import per kelas menjadi pilihan utama, sedangkan nama fully-qualified menyelesaikan pemakaian sekali pakai dan bentrokan nama.
- Proyek bertanda package dikompilasi dari folder akar sumber dan dijalankan dengan nama fully-qualified-nya.
Referensi#
- Creating and Using Packages — Oracle Java Tutorials — Panduan resmi membuat package, konvensi penamaannya, dan kaitannya dengan folder.
- Using Package Members — Oracle Java Tutorials — Cara memakai kelas dari package lain melalui import dan nama lengkapnya.
- Class Random — Oracle
— Dokumentasi kelas
Random, termasuk konstruktor bertanda seed yang menghasilkan urutan tetap.