Nama package bukan sekadar label — nama tersebut ikut tersebar ke seluruh kode pemanggil, berkas bytecode, dokumentasi, hingga koordinat dependensi di Maven Central. Kesalahan penamaan yang baru disadari setahun kemudian menjadi beban karena nama lengkap class tertanam di mana-mana. Karena itu ekosistem Java sejak lama bersepakat memakai satu konvensi: nama package berbasis domain internet yang dibalik. Pada Chapter ini kita akan membedah konvensi tersebut, aturan teknis apa saja yang mengikat segmen nama, dan prefiks mana yang dipesan platform sehingga tidak boleh kita pakai.
Konvensi Domain Terbalik #
Ide dasarnya: setiap penerbit kode di dunia menguasai satu nama domain, misalnya example.com, dan domain itu praktis menjamin keunikan. Konvensi domain terbalik menuliskan komponen domain dari belakang, lalu menambahkan nama proyek atau modul sebagai segmen akhir. Domain example.com menjadi prefiks com.example, sehingga package com.example.perpustakaan terbaca sebagai “proyek perpustakaan milik example.com”. Bila dua perusahaan berbeda kebetulan membuat class bernama sama, package berbeda menjaga keduanya tetap unik.
Beberapa pola yang umum kita jumpai:
| Domain / pemilik | Nama package khas | Contoh di ekosistem |
|---|---|---|
example.com (perusahaan) | com.example.<proyek> | com.google.guava |
tokobudi.co.id (domain berlevel banyak) | id.co.tokobudi.<proyek> | id.co.besi |
kampus.ac.id (universitas) | id.ac.kampus.<proyek> | id.ac.ui.cs |
| proyek open source tanpa domain khusus | org.<nama>.<proyek> | org.apache.commons |
Konvensi ini hanyalah konvensi — compiler tidak memeriksa apakah Anda benar-benar memiliki domainnya. Meski demikian, mengikuti konvensi membuat kode Anda tidak bertabrakan dengan pustaka lain saat semuanya berkumpul di satu classpath, dan pengguna library Anda dapat menebak asal setiap class hanya dari namanya.
Aturan Teknis Setiap Segmen #
Secara teknis, setiap segmen nama package harus merupakan identifier Java yang sah dan sebaiknya ditulis huruf kecil semua. Aturan mainnya:
- Huruf kecil seluruhnya —
com.example.perpustakaan, bukanCom.Example.Perpustakaan. CamelCase diserahkan untuk nama class agar kontras terlihat:com.example.perpustakaan.KatalogBuku. - Karakter yang diizinkan: huruf, angka, garis bawah; tidak boleh diawali angka. Tanda hubung
-tidak sah karena bukan bagian dari identifier — sumber kebingungan klasik saat domaincontoh-api.comingin dijadikan package. - Bukan keyword Java — segmen
com.contoh.intditolak compiler karenaintadalah keyword. - Sebaiknya pendek dan bermakna — segmen seperti
util,core,api,modellazim dipakai sebagai segmen akhir.
Program kecil berikut mempraktikkan dua hal sekaligus: membangun nama package dari domain terbalik, dan memeriksa sah-tidaknya sebuah kandidat nama:
public class NamaPaket {
public static void main(String[] args) {
System.out.println(bangunPaket("example.com", "perpustakaan"));
System.out.println(bangunPaket("tokobudi.co.id", "kasir"));
System.out.println(bangunPaket("kampus.ac.id", "nilai"));
System.out.println();
System.out.println("cek java.contoh : " + cek("java.contoh"));
System.out.println("cek com.example : " + cek("com.example"));
System.out.println("cek com.contoh-api : " + cek("com.contoh-api"));
}
static String bangunPaket(String domain, String proyek) {
String[] bagian = domain.toLowerCase().split("\\.");
StringBuilder nama = new StringBuilder();
for (int i = bagian.length - 1; i >= 0; i--) {
nama.append(bagian[i]).append('.');
}
return nama + proyek;
}
static String cek(String namaPaket) {
if (namaPaket.startsWith("java.")) {
return "terlarang, prefiks java dipesan platform";
}
for (String segmen : namaPaket.split("\\.")) {
if (!segmen.matches("[a-z_][a-z0-9_]*")) {
return "tidak sah, segmen '" + segmen + "' bukan identifier";
}
}
return "sah";
}
}Output yang Dihasilkan:
com.example.perpustakaan
id.co.tokobudi.kasir
id.ac.kampus.nilai
cek java.contoh : terlarang, prefiks java dipesan platform
cek com.example : sah
cek com.contoh-api : tidak sah, segmen 'contoh-api' bukan identifierMari kita telaah bagian pentingnya:
- Method
bangunPaket: memecah domain berdasarkan titik, lalu merangkai ulang dari segmen terakhir ke pertama —tokobudi.co.idmenjadiid.co.tokobudi— dan menempelkan nama proyek di ujung. - Baris
if (namaPaket.startsWith("java.")): pemeriksaan pertama methodcekmenjawab aturan spesifikasi: komponen pertamajavadipesan untuk platform Java SE, seperti kita bahas di bagian berikut. - Regex
[a-z_][a-z0-9_]*: meniru aturan identifier huruf kecil — segmen harus diawali huruf atau garis bawah, dilanjutkan huruf, angka, atau garis bawah; segmencontoh-apigagal karena memuat tanda hubung.
Prefiks yang Dipesan Platform #
Java Language Specification menegaskan bahwa nama package maupun module yang diawali identifier java dipesan untuk platform Java SE. Sistem class loader di JVM menolak mendefinisikan class buatan kita di sana. Perhatikan percobaan berikut yang kita jalankan sungguhan dengan berkas java/contoh/Demo.java berisi package java.contoh;:
javac -d kelas java/contoh/Demo.java
java -cp kelas java.contoh.DemoException in thread "main" java.lang.SecurityException: Prohibited package name: java.contohCompiler javac dengan senang hati mengompilasi berkas tersebut, tetapi JVM menolak memuat class-nya dengan SecurityException — bukti bahwa larangan ini ditegakkan di runtime, bukan sekadar anjuran sopan santun. Di luar java., prefiks seperti javax., jdk., sun., dan com.sun. juga sebaiknya dihindari karena dipakai oleh implementasi JDK dan API standar tambahan Oracle; memakainya untuk kode sendiri membuka peluang bentrok nama dengan class internal platform.
Nama Package dan Nama Module #
Konvensi yang sama berlaku untuk nama module pada Java Module System: com.example.perpustakaan adalah nama package sekaligus kandidat nama module yang wajar. JLS bahasa spesifikasinya memakai contoh module seperti com.nighthacks.scrabble dan org.openjdk.compiler — domain terbalik dipakai untuk tujuan keunikan yang sama. Saat kita tiba di Chapter Module Descriptors, kita akan melihat nama ini muncul di baris pertama module-info.java.
Satu catatan terakhir: nama package tidak menjanjikan lokasi unduhan di internet — package id.ac.kampus.nilai tidak harus hidup di server kampus.ac.id. Domain hanyalah sumber keunikan yang praktis, bukan alamat jaringan. Dengan nama yang unik dan teratur, kita siap mengatur siapa yang boleh memanggil class kita — tugas access control antarpaket pada Chapter berikutnya.
Referensi #
- JLS SE25 §6.1: Name Structure (nama unik dan prefiks terpesan)
- JLS SE25 §7.7: Module Declarations
- dev.java: Belajar Java
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
NamaPaket.java
Unduh berkaspublic class NamaPaket {
public static void main(String[] args) {
System.out.println(bangunPaket("example.com", "perpustakaan"));
System.out.println(bangunPaket("tokobudi.co.id", "kasir"));
System.out.println(bangunPaket("kampus.ac.id", "nilai"));
System.out.println();
System.out.println("cek java.contoh : " + cek("java.contoh"));
System.out.println("cek com.example : " + cek("com.example"));
System.out.println("cek com.contoh-api : " + cek("com.contoh-api"));
}
static String bangunPaket(String domain, String proyek) {
String[] bagian = domain.toLowerCase().split("\\.");
StringBuilder nama = new StringBuilder();
for (int i = bagian.length - 1; i >= 0; i--) {
nama.append(bagian[i]).append('.');
}
return nama + proyek;
}
static String cek(String namaPaket) {
if (namaPaket.startsWith("java.")) {
return "terlarang, prefiks java dipesan platform";
}
for (String segmen : namaPaket.split("\\.")) {
if (!segmen.matches("[a-z_][a-z0-9_]*")) {
return "tidak sah, segmen '" + segmen + "' bukan identifier";
}
}
return "sah";
}
}